Fix for sunrpc in 2.1.90

Steven N. Hirsch (shirsch@ibm.net)
Thu, 19 Mar 1998 20:57:50 -0500 (EST)


All:

Ok, third time's the charm! Here is the full analysis of a bug I've
tracked (after a couple of false starts) to the sunrpc services in
2.1.90 - followed by a fix <g>.

In 2.0.x kernels, struct task stored a list of secondary group-id's
in:

int groups[NGROUPS];

The kernel set/get routines relied on a defined constant, NOGROUP (aka
-1), to serve as list terminator in the the case where actual
membership was less than NGROUPS.

As it turns out, the current 2.1.x sunrpc code is similarly dependent
upon the NOGROUP terminator. Here's the snippet from unx_marshal() in
net/sunrpc/auth_unix.c which fills the RPC buffer:

hold = p++; /* grab pointer to length word */

for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
*p++ = htonl((u32) cred->uc_gids[i]);

*hold = htonl(p - hold - 1); /* gid array length */

n.b. cred->uc_gids is a full copy of current->groups[]..

Which would be fine, except for the fact that 'struct task' changed at
some point to:

int ngroups;
gid_t groups[NGROUPS];

The valid count is now held in 'ngroups', and neither sys_setgroup()
nor sys_getgroup() rely on a terminator value.

Under these circumstances, unx_marshal() will never see the
terminator, and always copies a full NGROUPS count of data to the
outgoing credentials.

Unfortunately, if 'ngroups' is truly the user's membership count,
(NGROUPS - ngroups) of gids will be bogus. Why this hasn't caused
more problems until now isn't clear to me.

I do know that my IBM RT (running 4.3BSD) has a hard-coded limit of
(8) secondary groups per credential, so it rejected all RPC
credentials from 2.1.80-90 kernels.

Examination of unx_match() shows the potential for similar
(mis)behavior, BTW.

Anyway, the proper fix should be the one below..

Steve

--- linux/net/sunrpc/auth_unix.c.orig Wed Oct 30 03:39:45 1996
+++ linux/net/sunrpc/auth_unix.c Thu Mar 19 07:56:15 1998
@@ -88,8 +88,12 @@
cred->uc_gid = current->gid;
cred->uc_fsuid = current->fsuid;
cred->uc_fsgid = current->fsgid;
- for (i = 0; i < 16 && i < NGROUPS; i++)
+ for (i = 0; i < 16
+ && i < NGROUPS
+ && i < current->ngroups; i++)
cred->uc_gids[i] = (gid_t) current->groups[i];
+ if (i < NGROUPS)
+ cred->uc_gids[i] = NOGROUP;
}

return (struct rpc_cred *) cred;
@@ -141,7 +145,9 @@
|| cred->uc_fsgid != current->fsgid)
return 0;

- for (i = 0; i < 16 && i < NGROUPS; i++)
+ for (i = 0; i < 16
+ && i < NGROUPS
+ && i < current->ngroups; i++)
if (cred->uc_gids[i] != (gid_t) current->groups[i])
return 0;
return 1;

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