pkgsrc-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: 'sudo' "use_pty" broken on serial or wscons terminals



>The default behavior of recent "security/sudo" is to open a pty.  While
>this works fine in XTerm (or similar) or over an SSH connection, it
>breaks programs run at a real serial terminal or wscons text console.
>
>Displayed text stair-steps each line keyboard input is either ignored,
>lost, or misdirected.
>

There's an inconsistency in the returned maj./min. devnos. for the current
terminal when it is a console which depends on the method you use to get this
info.

```
$ fgrep constty /etc/ttys
constty "/usr/libexec/getty Pc"         vt100   on secure
$
```

When you go through the filesystem like ttyname(3), for the console FD we get:

```
$ tty
/dev/constty
```

But, if you use sysctl(KERN_PROC2) we get something else entirely:

```
$ ./ttyname
/dev/ttyE0
```

because when wscons takes over the console, it overwrites the maj/min with
different ones. (Maybe file a PR for this?)

This inconsistency causes sudo to think that the current tty isn't a terminal.

To fix this issue, you can

a) either use `ttyE0' instead of `constty' -- like the other BSDs do:

```
constty "/usr/libexec/getty Pc"         vt100   on secure
ttyE0   "/usr/libexec/getty Pc"         wsvt25  on secure
```

That should work for standard VT console; or,

b) try this patch:

```
diff -urN sudo-1.9.15p5.orig/src/exec.c sudo-1.9.15p5/src/exec.c
--- sudo-1.9.15p5.orig/src/exec.c	2023-12-15 19:08:31.000000000 +0000
+++ sudo-1.9.15p5/src/exec.c	2024-03-23 14:14:59.597489636 +0000
@@ -395,8 +395,12 @@
     if (!S_ISCHR(fd_sb->st_mode))
 	debug_return_bool(false);
 
+#ifdef __NetBSD__
+    debug_return_bool(tty_sb ? tty_sb->st_rdev == fd_sb->st_rdev || isatty(fd) : isatty(fd));
+#else
     /* Compare with tty_sb if available, else just check that fd is a tty. */
     debug_return_bool(tty_sb ? tty_sb->st_rdev == fd_sb->st_rdev : isatty(fd));
+#endif
 }
 
 /*
```

HTH.

-RVP




ttyname.c source:

```
/**
 * TTY name using sysctl(3) a la sudo(8).
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static ssize_t getproclist(struct kinfo_proc2** kpp);
static void prtty(struct kinfo_proc2 ki);

int
main(void)
{
	struct kinfo_proc2* ka;
	ssize_t nprocs, i;

	nprocs = getproclist(&ka);
	if (nprocs == -1)
		err(EXIT_FAILURE, "can't get process list");
	// printf("total = %lu\n", nprocs);
	for (i = 0; i < nprocs; i++)
		prtty(ka[i]);
	free(ka);

	return 0;
}

static ssize_t
getproclist(struct kinfo_proc2** kpp)
{
	struct kinfo_proc2* kp = NULL;
	int mib[6], rc;
	size_t osiz, siz = 0;

        mib[0] = CTL_KERN;
        mib[1] = KERN_PROC2;
	mib[2] = KERN_PROC_PID;
	mib[3] = (int)getpid();
	mib[4] = sizeof (struct kinfo_proc2);
	mib[5] = 1;
	rc = sysctl(mib, 6, NULL, &siz, NULL, 0);
	if (rc == -1)
		return -1;
	if (siz == 0)
		goto out;
	do {
		siz += siz / 10;
		void* p = realloc(kp, siz);
		if (p == NULL) {
			free(kp);
			return -1;
		}
		kp = p;
		osiz = siz;
		mib[5] = (int)(siz / sizeof (struct kinfo_proc2));
		rc = sysctl(mib, 6, kp, &siz, NULL, 0);
	} while (rc == -1 && errno == ENOMEM && siz == osiz);
	if (rc == -1) {
		free(kp);
		return -1;
	}
out:
	*kpp = kp;
	return (ssize_t)(siz / sizeof (struct kinfo_proc2));
}

static void
prtty(struct kinfo_proc2 ki)
{
	FTS* ftsp;
	FTSENT* fe;
	char* const dirs[] = { "/dev", NULL };
	
	if ((ftsp = fts_open(dirs, FTS_NOCHDIR|FTS_PHYSICAL, NULL)) == NULL)
		return;

	// printf("0x%x = ", ki.p_tdev);
	while ((fe = fts_read(ftsp)) != NULL) {
		if (fe->fts_statp->st_rdev == ki.p_tdev) {
			printf("%s\n", fe->fts_path);
			break;
		}
	}
	fts_close(ftsp);
}
```



Home | Main Index | Thread Index | Old Index