/proc and FIOSETOWN again (patch for 1.2.11)

Marek Michalkiewicz (marekm@i17linuxb.ists.pwr.wroc.pl)
Wed, 5 Jul 1995 20:18:18 +0200 (MET DST)


Hi, hackers!

There are some problems with the /proc security fix in 1.2.11 - as a side
effect, ps displays processes with the dumpable flag cleared as if they
were run as root. The problem is that we shouldn't change the owner of
/proc/pid itself, only /proc/pid/mem, /proc/pid/fd/ etc.

It is also necessary to clear the dumpable flag whenever euid or fsuid
of the process is changed. This is necessary at least for /bin/login
in the logdaemon-4.9 package - otherwise the user would be able to mess
with the lastlog file (which is open read-write) after setuid(user).

This patch also fixes the hole with FIOSETOWN ioctl on sockets - it was
possible to send a SIGURG to any process. This is a real bug - I wrote
a program which can be used to exploit it. This should be fixed too,
before we abandon 1.2.x completely...

Please let me know what do you think about this patch, or if there are
any problems with it. Thank you for your cooperation, and hope to see
1.2.12 soon.

Marek

----------
diff -urN v1.2.11/linux/fs/exec.c linux/fs/exec.c
--- v1.2.11/linux/fs/exec.c Mon Jan 30 12:08:04 1995
+++ linux/fs/exec.c Wed Jul 5 17:39:14 1995
@@ -509,7 +509,8 @@
int ch;
char * name;

- current->dumpable = 1;
+ if (current->euid == current->uid && current->egid == current->gid)
+ current->dumpable = 1;
name = bprm->filename;
for (i=0; (ch = *(name++)) != '\0';) {
if (ch == '/')
diff -urN v1.2.11/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v1.2.11/linux/fs/proc/inode.c Mon Jun 26 15:17:56 1995
+++ linux/fs/proc/inode.c Wed Jul 5 17:46:25 1995
@@ -194,7 +194,8 @@
return;
}
ino &= 0x0000ffff;
- if (p->dumpable && p->uid == p->euid && p->gid == p->egid) {
+ if (ino == PROC_PID_INO ||
+ (p->dumpable && p->uid == p->euid && p->gid == p->egid)) {
inode->i_uid = p->uid;
inode->i_gid = p->gid;
}
diff -urN v1.2.11/linux/kernel/sys.c linux/kernel/sys.c
--- v1.2.11/linux/kernel/sys.c Sat Mar 4 23:16:36 1995
+++ linux/kernel/sys.c Wed Jul 5 16:10:06 1995
@@ -195,6 +195,7 @@
asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
{
int old_rgid = current->gid;
+ int old_egid = current->egid;

if (rgid != (gid_t) -1) {
if ((old_rgid == rgid) ||
@@ -219,6 +220,8 @@
(egid != (gid_t) -1 && egid != old_rgid))
current->sgid = current->egid;
current->fsgid = current->egid;
+ if (current->egid != old_egid)
+ current->dumpable = 0;
return 0;
}

@@ -227,12 +230,16 @@
*/
asmlinkage int sys_setgid(gid_t gid)
{
+ int old_egid = current->egid;
+
if (suser())
current->gid = current->egid = current->sgid = current->fsgid = gid;
else if ((gid == current->gid) || (gid == current->sgid))
current->egid = current->fsgid = gid;
else
return -EPERM;
+ if (current->egid != old_egid)
+ current->dumpable = 0;
return 0;
}

@@ -284,6 +291,7 @@
asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
{
int old_ruid = current->uid;
+ int old_euid = current->euid;

if (ruid != (uid_t) -1) {
if ((old_ruid == ruid) ||
@@ -308,6 +316,8 @@
(euid != (uid_t) -1 && euid != old_ruid))
current->suid = current->euid;
current->fsuid = current->euid;
+ if (current->euid != old_euid)
+ current->dumpable = 0;
return 0;
}

@@ -324,12 +334,16 @@
*/
asmlinkage int sys_setuid(uid_t uid)
{
+ int old_euid = current->euid;
+
if (suser())
current->uid = current->euid = current->suid = current->fsuid = uid;
else if ((uid == current->uid) || (uid == current->suid))
current->fsuid = current->euid = uid;
else
return -EPERM;
+ if (current->euid != old_euid)
+ current->dumpable = 0;
return(0);
}

@@ -346,6 +360,8 @@
if (uid == current->uid || uid == current->euid ||
uid == current->suid || uid == current->fsuid || suser())
current->fsuid = uid;
+ if (current->fsuid != old_fsuid)
+ current->dumpable = 0;
return old_fsuid;
}

@@ -359,6 +375,8 @@
if (gid == current->gid || gid == current->egid ||
gid == current->sgid || gid == current->fsgid || suser())
current->fsgid = gid;
+ if (current->fsgid != old_fsgid)
+ current->dumpable = 0;
return old_fsgid;
}

diff -urN v1.2.11/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.2.11/linux/net/inet/af_inet.c Tue Jun 13 15:18:50 1995
+++ linux/net/inet/af_inet.c Wed Jul 5 16:00:19 1995
@@ -1260,6 +1260,7 @@
{
struct sock *sk=(struct sock *)sock->data;
int err;
+ int tmp;

switch(cmd)
{
@@ -1268,7 +1269,11 @@
err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
if(err)
return err;
- sk->proc = get_fs_long((int *) arg);
+ tmp = get_fs_long((int *) arg);
+ /* see inet_fcntl */
+ if (current->pid != tmp && current->pgrp != -tmp && !suser())
+ return -EPERM;
+ sk->proc = tmp;
return(0);
case FIOGETOWN:
case SIOCGPGRP:
----------