From 46274e725e67d28f8536b8ea02931400d6cdf1fb Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 13 Aug 2024 20:07:28 -0600 Subject: [PATCH] Fix formatting of ttydev on systems with signed 32-bit dev_t If dev_t is 32-bit and signed, formatting as an unsigned long long may result in a bogus value due to sign extension. --- config.h.in | 3 +++ configure | 35 +++++++++++++++++++++++++++++ configure.ac | 1 + src/regress/ttyname/check_ttyname.c | 32 +++++++++++++++++++++++--- src/sudo.c | 7 +++++- 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/config.h.in b/config.h.in index 531fe8efe..2f9870674 100644 --- a/config.h.in +++ b/config.h.in @@ -1293,6 +1293,9 @@ /* Define to 1 if you want sudo to set $HOME in shell mode. */ #undef SHELL_SETS_HOME +/* The size of 'dev_t', as computed by sizeof. */ +#undef SIZEOF_DEV_T + /* The size of 'id_t', as computed by sizeof. */ #undef SIZEOF_ID_T diff --git a/configure b/configure index 18eb2bdf2..c44bad861 100755 --- a/configure +++ b/configure @@ -21003,6 +21003,41 @@ printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } printf "%s\n" "#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of dev_t" >&5 +printf %s "checking size of dev_t... " >&6; } +if test ${ac_cv_sizeof_dev_t+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (dev_t))" "ac_cv_sizeof_dev_t" "$ac_includes_default" +then : + +else case e in #( + e) if test "$ac_cv_type_dev_t" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (dev_t) +See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_dev_t=0 + fi ;; +esac +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_dev_t" >&5 +printf "%s\n" "$ac_cv_sizeof_dev_t" >&6; } + + + +printf "%s\n" "#define SIZEOF_DEV_T $ac_cv_sizeof_dev_t" >>confdefs.h + + # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. diff --git a/configure.ac b/configure.ac index 28b63ef0d..d48a596dc 100644 --- a/configure.ac +++ b/configure.ac @@ -2507,6 +2507,7 @@ SUDO_SOCK_SA_LEN SUDO_SOCK_SIN_LEN AC_CHECK_SIZEOF([long]) AC_CHECK_SIZEOF([long long]) +AC_CHECK_SIZEOF([dev_t]) AC_CHECK_SIZEOF([id_t]) AC_CHECK_SIZEOF([time_t]) AC_CHECK_SIZEOF([uid_t]) diff --git a/src/regress/ttyname/check_ttyname.c b/src/regress/ttyname/check_ttyname.c index 189404d95..6dca0f733 100644 --- a/src/regress/ttyname/check_ttyname.c +++ b/src/regress/ttyname/check_ttyname.c @@ -67,10 +67,10 @@ int main(int argc, char *argv[]) { char *tty_libc = NULL, *tty_sudo = NULL; - int ch, errors = 0, ntests = 1; char pathbuf[PATH_MAX]; bool verbose = false; - dev_t ttydev; + dev_t ttydev = -1; + int ch, errors = 0, ntests = 1; initprogname(argc > 0 ? argv[0] : "check_ttyname"); @@ -87,9 +87,35 @@ main(int argc, char *argv[]) /* Lookup tty name using kernel info if possible. */ ttydev = get_process_ttyname(pathbuf, sizeof(pathbuf)); - if (ttydev != (dev_t)-1) + if (ttydev != (dev_t)-1) { + char numbuf[STRLEN_MAX_UNSIGNED(unsigned long long) + 1]; + unsigned long long ullval; + const char *errstr; + dev_t newdev; + + /* For comparison below. */ tty_sudo = pathbuf; + /* Check that we can format a dev_t as a string and parse it. */ + ntests++; +#if SIZEOF_DEV_T == SIZEOF_LONG + ullval = (unsigned long)ttydev; +#else + ullval = (unsigned long long)ttydev; +#endif + (void)snprintf(numbuf, sizeof(numbuf), "%llu", ullval); + newdev = sudo_strtonum(numbuf, LLONG_MIN, LLONG_MAX, &errstr); + if (errstr != NULL) { + printf("%s: FAIL unable to parse device number %s: %s", + getprogname(), numbuf, errstr); + errors++; + } else if (ttydev != newdev) { + printf("%s: FAIL device mismatch for %s, %s != %llu", + getprogname(), pathbuf, numbuf, ullval); + errors++; + } + } + #if defined(HAVE_KINFO_PROC2_NETBSD) || \ defined(HAVE_KINFO_PROC_OPENBSD) || \ defined(HAVE_KINFO_PROC_FREEBSD) || \ diff --git a/src/sudo.c b/src/sudo.c index 1e2657cb4..0d82e785e 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -620,7 +620,12 @@ get_user_info(struct user_details *ud) ttydev = get_process_ttyname(path, sizeof(path)); if (ttydev != (dev_t)-1) { - if (asprintf(&info[++i], "ttydev=%llu", (unsigned long long)ttydev) == -1) +#if SIZEOF_DEV_T == SIZEOF_LONG + n = asprintf(&info[++i], "ttydev=%lu", (unsigned long)ttydev); +#else + n = asprintf(&info[++i], "ttydev=%llu", (unsigned long long)ttydev); +#endif + if (n == -1) goto oom; info[++i] = sudo_new_key_val("tty", path); if (info[i] == NULL)