* 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.
This commit is contained in:
parent
eb4097180b
commit
a324a7f13f
@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
* NEWS, libmisc/chowntty.c: Fix a race condition that could lead to
|
* NEWS, libmisc/chowntty.c: Fix a race condition that could lead to
|
||||||
gaining ownership or changing mode of arbitrary files.
|
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-10-11 Nicolas François <nicolas.francois@centraliens.net>
|
2008-10-11 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
|
2
NEWS
2
NEWS
@ -64,6 +64,8 @@ shadow-4.1.2.1 -> shadow-4.1.2.2 23-11-2008
|
|||||||
*** security
|
*** security
|
||||||
- Fix a race condition in login that could lead to gaining ownership or
|
- Fix a race condition in login that could lead to gaining ownership or
|
||||||
changing mode of arbitrary files.
|
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
|
shadow-4.1.2 -> shadow-4.1.2.1 26-06-2008
|
||||||
|
|
||||||
|
@ -43,32 +43,14 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include "getdef.h"
|
#include "getdef.h"
|
||||||
/*
|
|
||||||
* is_my_tty -- determine if "tty" is the same as TTY stdin is using
|
|
||||||
*/
|
|
||||||
static bool is_my_tty (const char *tty)
|
|
||||||
{
|
|
||||||
struct stat by_name, by_fd;
|
|
||||||
|
|
||||||
if ((stat (tty, &by_name) != 0) || (fstat (0, &by_fd) != 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (by_name.st_rdev != by_fd.st_rdev) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* chown_tty() sets the login tty to be owned by the new user ID
|
* chown_tty() sets the login tty to be owned by the new user ID
|
||||||
* with TTYPERM modes
|
* 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 */
|
char *group; /* TTY group name or number */
|
||||||
struct group *grent;
|
struct group *grent;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
@ -97,18 +79,6 @@ void chown_tty (const char *tty, const struct passwd *info)
|
|||||||
* the group as determined above.
|
* 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) != 0)
|
if ( (fchown (STDIN_FILENO, info->pw_uid, gid) != 0)
|
||||||
|| (fchmod (STDIN_FILENO, getdef_num ("TTYPERM", 0600)) != 0)) {
|
|| (fchmod (STDIN_FILENO, getdef_num ("TTYPERM", 0600)) != 0)) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
@ -56,6 +56,31 @@ struct utmp utent;
|
|||||||
#define NO_TTY \
|
#define NO_TTY \
|
||||||
_("Unable to determine your tty name.")
|
_("Unable to determine your tty name.")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is_my_tty -- determine if "tty" is the same TTY stdin is using
|
||||||
|
*/
|
||||||
|
static bool 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 false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (by_name.st_rdev != by_fd.st_rdev) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* checkutmp - see if utmp file is correct for this process
|
* checkutmp - see if utmp file is correct for this process
|
||||||
*
|
*
|
||||||
@ -81,16 +106,20 @@ void checkutmp (bool picky)
|
|||||||
setutent ();
|
setutent ();
|
||||||
|
|
||||||
/* First, try to find a valid utmp entry for this process. */
|
/* First, try to find a valid utmp entry for this process. */
|
||||||
while ((ut = getutent ()) != NULL)
|
while ((ut = getutent ()) != NULL) {
|
||||||
if ( (ut->ut_pid == pid)
|
if ( (ut->ut_pid == pid)
|
||||||
&& ('\0' != ut->ut_line[0])
|
&& ('\0' != ut->ut_line[0])
|
||||||
&& ('\0' != ut->ut_id[0])
|
&& ('\0' != ut->ut_id[0])
|
||||||
&& ( (LOGIN_PROCESS == ut->ut_type)
|
&& ( (LOGIN_PROCESS == ut->ut_type)
|
||||||
|| (USER_PROCESS == ut->ut_type))) {
|
|| (USER_PROCESS == ut->ut_type))
|
||||||
|
/* A process may have failed to close an entry
|
||||||
|
* Check if this entry refers to this tty */
|
||||||
|
&& is_my_tty (ut->ut_line)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If there is one, just use it, otherwise create a new one. */
|
/* If there is one, just use it, otherwise create a new one. */
|
||||||
if (NULL != ut) {
|
if (NULL != ut) {
|
||||||
utent = *ut;
|
utent = *ut;
|
||||||
} else {
|
} else {
|
||||||
@ -110,7 +139,7 @@ void checkutmp (bool picky)
|
|||||||
utent.ut_type = LOGIN_PROCESS;
|
utent.ut_type = LOGIN_PROCESS;
|
||||||
utent.ut_pid = pid;
|
utent.ut_pid = pid;
|
||||||
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
strncpy (utent.ut_line, line, sizeof utent.ut_line);
|
||||||
/* XXX - assumes /dev/tty?? */
|
/* XXX - assumes /dev/tty?? or /dev/pts/?? */
|
||||||
strncpy (utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
|
strncpy (utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
|
||||||
strcpy (utent.ut_user, "LOGIN");
|
strcpy (utent.ut_user, "LOGIN");
|
||||||
utent.ut_time = time (NULL);
|
utent.ut_time = time (NULL);
|
||||||
@ -173,6 +202,10 @@ void checkutmp (bool picky)
|
|||||||
* the structure. The UNIX/PC is broken in this regard
|
* the structure. The UNIX/PC is broken in this regard
|
||||||
* and needs help ...
|
* and needs help ...
|
||||||
*/
|
*/
|
||||||
|
/* XXX: The ut_line may not match with the current tty.
|
||||||
|
* ut_line will be set by setutmp anyway, but ut_id
|
||||||
|
* will not be set, and the wrong utmp entry may be
|
||||||
|
* updated. -- nekral */
|
||||||
|
|
||||||
if (utent.ut_line[0] == '\0')
|
if (utent.ut_line[0] == '\0')
|
||||||
#endif /* !UNIXPC */
|
#endif /* !UNIXPC */
|
||||||
|
@ -1094,7 +1094,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
setup_limits (&pwent); /* nice, ulimit etc. */
|
setup_limits (&pwent); /* nice, ulimit etc. */
|
||||||
#endif /* ! USE_PAM */
|
#endif /* ! USE_PAM */
|
||||||
chown_tty (tty, &pwent);
|
chown_tty (&pwent);
|
||||||
|
|
||||||
#ifdef USE_PAM
|
#ifdef USE_PAM
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user