From: nekral-guest Date: Sat, 22 Nov 2008 23:54:54 +0000 (+0000) Subject: * NEWS, libmisc/chowntty.c, libmisc/utmp.c: is_my_tty() moved from X-Git-Tag: 4.1.2.2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6b5da98d14bd90146372ed6b876ff3e735dbcf1e;p=thirdparty%2Fshadow.git * NEWS, libmisc/chowntty.c, libmisc/utmp.c: is_my_tty() moved from utmp.c to chowntty.c. checkutmp() now only uses an existing utmp entry if the pid matches and ut_line matches with the current tty. This fixes a possible DOS when entries can be forged in the utmp file. * libmisc/chowntty.c, src/login.c, lib/prototypes.h: Remove the tty argument from chown_tty. chown_tty always changes stdin and does not need this argument anymore. --- diff --git a/ChangeLog b/ChangeLog index 0c0d5d595..214dbdecb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,14 @@ * NEWS, libmisc/chowntty.c: Fix a race condition that could lead to gaining ownership or changing mode of arbitrary files. + * NEWS, libmisc/chowntty.c, libmisc/utmp.c: is_my_tty() moved from + utmp.c to chowntty.c. checkutmp() now only uses an existing utmp + entry if the pid matches and ut_line matches with the current tty. + This fixes a possible DOS when entries can be forged in the utmp + file. + * libmisc/chowntty.c, src/login.c, lib/prototypes.h: Remove the + tty argument from chown_tty. chown_tty always changes stdin and + does not need this argument anymore. 2008-06-26 Nicolas François diff --git a/NEWS b/NEWS index 8afcf03e6..fa6d0f128 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ shadow-4.1.2.1 -> shadow-4.1.2.2 23-11-2008 *** security - Fix a race condition in login that could lead to gaining ownership or changing mode of arbitrary files. +- Fix a possible login DOS, which could be caused by injecting forged + entries in utmp. shadow-4.1.2 -> shadow-4.1.2.1 26-06-2008 diff --git a/lib/prototypes.h b/lib/prototypes.h index 03f30d127..29d6aeeb7 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -73,7 +73,7 @@ extern char *Basename (char *str); extern int chown_tree (const char *, uid_t, uid_t, gid_t, gid_t); /* chowntty.c */ -extern void chown_tty (const char *, const struct passwd *); +extern void chown_tty (const struct passwd *); /* console.c */ extern int console (const char *); diff --git a/libmisc/chowntty.c b/libmisc/chowntty.c index 745ee8a3d..6cd0383e8 100644 --- a/libmisc/chowntty.c +++ b/libmisc/chowntty.c @@ -43,30 +43,13 @@ #include "defines.h" #include #include "getdef.h" -/* - * is_my_tty -- determine if "tty" is the same as TTY stdin is using - */ -static int is_my_tty (const char *tty) -{ - struct stat by_name, by_fd; - - if (stat (tty, &by_name) || fstat (0, &by_fd)) - return 0; - - if (by_name.st_rdev != by_fd.st_rdev) - return 0; - else - return 1; -} - /* * chown_tty() sets the login tty to be owned by the new user ID * with TTYPERM modes */ -void chown_tty (const char *tty, const struct passwd *info) +void chown_tty (const struct passwd *info) { - char buf[200], full_tty[200]; char *group; /* TTY group name or number */ struct group *grent; gid_t gid; @@ -90,18 +73,6 @@ void chown_tty (const char *tty, const struct passwd *info) * the group as determined above. */ - if (*tty != '/') { - snprintf (full_tty, sizeof full_tty, "/dev/%s", tty); - tty = full_tty; - } - - if (!is_my_tty (tty)) { - SYSLOG ((LOG_WARN, - "unable to determine TTY name, got %s\n", tty)); - closelog (); - exit (1); - } - if (fchown (STDIN_FILENO, info->pw_uid, gid) || fchmod (STDIN_FILENO, getdef_num ("TTYPERM", 0600))) { int err = errno; diff --git a/libmisc/utmp.c b/libmisc/utmp.c index f4dfbc3f5..130beed64 100644 --- a/libmisc/utmp.c +++ b/libmisc/utmp.c @@ -56,6 +56,30 @@ struct utmp utent; #define NO_TTY \ _("Unable to determine your tty name.") +/* + * is_my_tty -- determine if "tty" is the same TTY stdin is using + */ +static int is_my_tty (const char *tty) +{ + char full_tty[200]; + struct stat by_name, by_fd; + + if ('/' != *tty) { + snprintf (full_tty, sizeof full_tty, "/dev/%s", tty); + tty = full_tty; + } + + if ((stat (tty, &by_name) != 0) || (fstat (STDIN_FILENO, &by_fd) != 0)) { + return 0; + } + + if (by_name.st_rdev != by_fd.st_rdev) { + return 0; + } else { + return 1; + } +} + /* * checkutmp - see if utmp file is correct for this process * @@ -84,7 +108,8 @@ void checkutmp (int picky) while ((ut = getutent ())) if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] && (ut->ut_type == LOGIN_PROCESS - || ut->ut_type == USER_PROCESS)) + || ut->ut_type == USER_PROCESS) && + is_my_tty (ut->ut_line)) break; /* If there is one, just use it, otherwise create a new one. */ diff --git a/src/login.c b/src/login.c index 689ae1d3d..48328b343 100644 --- a/src/login.c +++ b/src/login.c @@ -1005,7 +1005,7 @@ int main (int argc, char **argv) } setup_limits (&pwent); /* nice, ulimit etc. */ #endif /* ! USE_PAM */ - chown_tty (tty, &pwent); + chown_tty (&pwent); #ifdef USE_PAM /*