[LWN Logo]

Date:	Thu, 24 Dec 1998 18:02:03 +0300
From:	Savochkin Andrey Vladimirovich <saw@MSU.RU>
Subject:      Re: Linux PAM (up to 0.64-2) local root compromise
To:	BUGTRAQ@NETSPACE.ORG

--UlVJffcvxoiEqYs2
Content-Type: text/plain; charset=us-ascii

On Wed, Dec 23, 1998 at 01:12:45PM +0100, Michal Zalewski wrote:
> As someone said, "Never make any mistaeks."
>
> Latest release of Linux Pluggable Authentication Modules (pam-0.64-2, as
> well as previous ones), has huge security flaw in pam_unix_passwd.so
> module, which can be exploited to gain read/write permissions to
> /etc/shadow file.
>
[snip]
> Default password change routine in pam_unix_passwd.so module, called
> from passwd utility, creates temporary file /etc/nshadow using fopen().
> Unfortunately, process umask isn't changed. After approx. 3 syscalls,
> chmod is called to set proper mode on this file (0600). But, for these
> 3 syscalls, file permissions are equal to 0666 ~ umask. If umask of
> current process (which is inherited from parent process, of course)
> is set to 0, we have /etc/nshadow file with permissions 0666. Then,
> after all, it's moved using rename() to /etc/shadow. Cute.

Thank you for the report.
The attached patch takes care of file creation permissions in
pam_unix_passwd and pam_tally modules.  I should warn people that the patch
isn't well tested.  pam_unix_passwd module can't be tested on my system.
It doesn't work at all because of a glibc bug.

Best regards
                                        Andrey V.
                                        Savochkin

--UlVJffcvxoiEqYs2
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pam-0.65-umask.patch"

diff -ru Linux-PAM-0.65.orig/modules/pam_tally/pam_tally.c Linux-PAM-0.65/modules/pam_tally/pam_tally.c
--- Linux-PAM-0.65.orig/modules/pam_tally/pam_tally.c   Thu Jan 15 01:08:33 1998
+++ Linux-PAM-0.65/modules/pam_tally/pam_tally.c        Thu Dec 24 17:12:21 1998
@@ -137,13 +137,16 @@
     int lstat_ret = lstat(filename,&fileinfo);

     if ( lstat_ret && *tally!=TALLY_HI ) {
-      if ( ( *TALLY=fopen(filename, "a") ) ) {
-        /* Create file, or append-open in pathological case. */
+      int oldmask = umask(077);
+      *TALLY=fopen(filename, "a");
+      /* Create file, or append-open in pathological case. */
+      umask(oldmask);
+      if ( !*TALLY ) {
         _pam_log(LOG_ALERT, "Couldn't create %s",filename);
         return PAM_AUTH_ERR;
       }
+      lstat_ret = fstat(fileno(*TALLY),&fileinfo);
       fclose(*TALLY);
-      lstat_ret = lstat(filename,&fileinfo);
     }

     if ( lstat_ret ) {
@@ -563,6 +566,8 @@
            *argv);
     exit(0);
   }
+
+  umask(077);

   /*
    * Major difference between individual user and all users:
diff -ru Linux-PAM-0.65.orig/modules/pam_unix/pam_unix_passwd.c Linux-PAM-0.65/modules/pam_unix/pam_unix_passwd.c
--- Linux-PAM-0.65.orig/modules/pam_unix/pam_unix_passwd.c      Thu Oct  9 06:59:04 1997
+++ Linux-PAM-0.65/modules/pam_unix/pam_unix_passwd.c   Thu Dec 24 16:53:30 1998
@@ -554,6 +554,7 @@
   int err = 0;
 #ifdef HAVE_SHADOW_H
   struct spwd *spwdent=NULL, *stmpent=NULL;
+  int oldmask;
 #endif
   if(flags & PPW_SHADOW) { retval |= PPW_SHADOW; }
   gettimeofday(&time1, NULL);
@@ -583,7 +584,9 @@
       return PPW_NOSUCHUSER;
     spwdent->sp_pwdp = towhat;
     spwdent->sp_lstchg = time(NULL)/(60*60*24);
+    oldmask = umask(077);
     pwfile = fopen(SH_TMPFILE,"w");
+    umask(oldmask);
     opwfile = fopen("/etc/shadow","r");
     if(pwfile == NULL || opwfile == NULL)
       return PPW_ERROR;
@@ -623,7 +626,9 @@
       unlink(SH_TMPFILE);
   } else {
     pwd->pw_passwd = towhat;
+    oldmask = umask(077);
     pwfile = fopen(PW_TMPFILE,"w");
+    umask(oldmask);
     opwfile = fopen("/etc/passwd","r");
     if(pwfile == NULL || opwfile == NULL)
       return PPW_ERROR;
@@ -659,7 +664,9 @@
   }
 #else
   pwd->pw_passwd = towhat;
+  oldmask = umask(077);
   pwfile = fopen(PW_TMPFILE,"w");
+  umask(oldmask);
   opwfile = fopen("/etc/passwd","r");
   if(pwfile == NULL || opwfile == NULL)
     return PPW_ERROR;

--UlVJffcvxoiEqYs2--