Linux kernel: sys_set*id(uid_t...) confusion (fwd)

Phillip R. Jaenke (prj@nls.net)
Mon, 22 Jun 1998 12:18:37 -0400 (EDT)


Got this one off of bugtraq, just thought you all might want to know.

And, yes, I'm still alive.. small problem with my other mail account
(kernel), gonna try and get it sorted out today.

--Phillip R. Jaenke (prj@nls.net - InterNIC: PRJ5)
TheGuyInCharge(tm), Ketyra Designs, Inc.
"That's IT! I'm gonna slap Dr.Watson with a malpractice suit!!" --Keihra
ObBob! KHpB lWulH EO m23 C(PEW) B-18 OlO LM(p) ScjnM T++ A9! H8oc b123 D+
! I reserve the right to bill spammers for my time and disk space !

---------- Forwarded message ----------
Date: Fri, 19 Jun 1998 16:17:18 +0200
From: Michal Zalewski <lcamtuf@BOSS.STASZIC.WAW.PL>
To: BUGTRAQ@NETSPACE.ORG
Subject: Linux kernel: sys_set*id(uid_t...) confusion

Maybe this problem is well-known, but it seems to be not fixed yet:

'Physically', UID is stored by kernel in single word. Due to this
limitation, UID/GID must satisfy condition 0<=UID<=65535. But there are
serious problems with kernel sys_setuid(uid_t) and uid_t type itself:

- uid_t (UID/GID handling type), unsigned integer, is able to handle
large integers (>65535), eg. 131072.

- sys_setuid(uid_t) and other kernel UID/GID manipulation routines
(and their libc aliases, like setuid), silently strips higher uid_t bits,
then returns 'success' value (0).

So, attacker may change /etc/passwd UID of any account to 131072 (binary:
10 00000000 00000000) - it won't be traced by any intrusion-detection
programs looking for '0' UIDs, because uid_t is able to store this value,
and 131072 for sure is NOT equal to 0. But when he will login using this
account - he should get root shell (setuid, as I noticed above, silently
discards two highest bits, so 131072 becomes 0).

Nice trick, but that's not all. If you have eg. securetty installed to
prevent root logins from outside (or any other mechanism to prevent
unprivledged root access, eg. restricted 'su') - attacker will be able to
fool it, because UID retreived from /etc/passwd (uid_t) using standard
libc routines, is NOT equal to 0, so this account looks like
unprivledged...

Fixes:

First solution - rewrite kernel UID/GID code to extend UID address space
using eg. 4 bytes instead of 2 (whoow!) - but it will probably harm many
programs.

Second solution - patch your kernel to return EINVAL when uid_t is too
big. Here's the patch:

--- linux/kernel/sys.c.orig Tue Apr 8 17:47:47 1997
+++ linux/kernel/sys.c Fri Jun 19 16:00:28 1998
@@ -237,6 +237,8 @@
{
int old_rgid = current->gid;
int old_egid = current->egid;
+
+ if (rgid>0xffff || egid>0xffff) return -EINVAL;

if (rgid != (gid_t) -1) {
if ((old_rgid == rgid) ||
@@ -272,6 +274,8 @@
asmlinkage int sys_setgid(gid_t gid)
{
int old_egid = current->egid;
+
+ if (gid>0xffff) return -EINVAL;

if (suser())
current->gid = current->egid = current->sgid = current->fsgid = gid;
@@ -489,6 +493,8 @@
asmlinkage int sys_setuid(uid_t uid)
{
int old_euid = current->euid;
+
+ if (uid>0xffff) return -EINVAL;

if (suser())
current->uid = current->euid = current->suid = current->fsuid = uid;
@@ -510,6 +516,8 @@
asmlinkage int sys_setfsuid(uid_t uid)
{
int old_fsuid = current->fsuid;
+
+ if (uid>0xffff) return -EINVAL;

if (uid == current->uid || uid == current->euid ||
uid == current->suid || uid == current->fsuid || suser())
@@ -525,6 +533,8 @@
asmlinkage int sys_setfsgid(gid_t gid)
{
int old_fsgid = current->fsgid;
+
+ if (gid>0xffff) return -EINVAL;

if (gid == current->gid || gid == current->egid ||
gid == current->sgid || gid == current->fsgid || suser())
@@ -563,6 +573,8 @@
asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
{
struct task_struct * p;
+
+ if (pid>0xffff || pgid>0xffff) return -EINVAL;

if (!pid)
pid = current->pid;

_______________________________________________________________________
Michal Zalewski [lcamtuf@boss.staszic.waw.pl] <= finger for pub PGP key
Iterowac jest rzecza ludzka, wykonywac rekursywnie - boska [P. Deutsch]
[echo "\$0&\$0">_;chmod +x _;./_] <=------=> [tel +48 (0) 22 813 25 86]

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu