Skip to content

Commit 47e9c81

Browse files
committed
sys/rpc: UNIX auth: Fix OOB accesses, notably writes on decode
When the received authentication message had more than XU_NGROUPS, we would write group IDs beyond the end of cr_groups[] in the 'struct xucred' being filled (as 'ngroups_max' is always greater than XU_NGROUPS). For robustness, prevent various OOB accesses that would result from a change of value of XU_NGROUPS or a 'struct xucred' with an invalid 'cr_ngroups' field, even if these cases are unlikely. Reviewed by: rmacklem Fixes: dfdcada ("Add the new kernel-mode NFS Lock Manager.") MFC after: 2 days Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D52960
1 parent bda3b61 commit 47e9c81

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

sys/rpc/authunix_prot.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ xdr_authunix_parms(XDR *xdrs, uint32_t *time, struct xucred *cred)
7575
} else {
7676
namelen = 0;
7777
}
78-
junk = 0;
7978

8079
if (!xdr_uint32_t(xdrs, time)
8180
|| !xdr_uint32_t(xdrs, &namelen))
@@ -93,38 +92,41 @@ xdr_authunix_parms(XDR *xdrs, uint32_t *time, struct xucred *cred)
9392

9493
if (!xdr_uint32_t(xdrs, &cred->cr_uid))
9594
return (FALSE);
95+
96+
/*
97+
* Safety check: The protocol needs at least one group (access to
98+
* 'cr_gid', decrementation of 'cr_ngroups' below).
99+
*/
100+
if (xdrs->x_op == XDR_ENCODE && cred->cr_ngroups == 0)
101+
return (FALSE);
96102
if (!xdr_uint32_t(xdrs, &cred->cr_gid))
97103
return (FALSE);
98104

99105
if (xdrs->x_op == XDR_ENCODE) {
100106
/*
101-
* Note that this is a `struct xucred`, which maintains its
102-
* historical layout of preserving the egid in cr_ngroups and
103-
* cr_groups[0] == egid.
107+
* Note that this is a 'struct xucred', which still has the
108+
* historical layout where the effective GID is in cr_groups[0]
109+
* and is accounted in 'cr_ngroups'. We substract 1 to obtain
110+
* the number of "supplementary" groups, passed in the AUTH_SYS
111+
* credentials variable-length array called gids[] in RFC 5531.
104112
*/
113+
MPASS(cred->cr_ngroups <= XU_NGROUPS);
105114
supp_ngroups = cred->cr_ngroups - 1;
106115
if (supp_ngroups > NGRPS)
107116
supp_ngroups = NGRPS;
108117
}
109118

110119
if (!xdr_uint32_t(xdrs, &supp_ngroups))
111120
return (FALSE);
112-
for (i = 0; i < supp_ngroups; i++) {
113-
if (i < ngroups_max) {
114-
if (!xdr_uint32_t(xdrs, &cred->cr_groups[i + 1]))
115-
return (FALSE);
116-
} else {
117-
if (!xdr_uint32_t(xdrs, &junk))
118-
return (FALSE);
119-
}
120-
}
121121

122-
if (xdrs->x_op == XDR_DECODE) {
123-
if (supp_ngroups > ngroups_max)
124-
cred->cr_ngroups = ngroups_max + 1;
125-
else
126-
cred->cr_ngroups = supp_ngroups + 1;
127-
}
122+
junk = 0;
123+
for (i = 0; i < supp_ngroups; ++i)
124+
if (!xdr_uint32_t(xdrs, i < XU_NGROUPS - 1 ?
125+
&cred->cr_sgroups[i] : &junk))
126+
return (FALSE);
127+
128+
if (xdrs->x_op != XDR_ENCODE)
129+
cred->cr_ngroups = MIN(supp_ngroups + 1, XU_NGROUPS);
128130

129131
return (TRUE);
130132
}

0 commit comments

Comments
 (0)