From nobody Thu Oct 16 16:58:24 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cnZ0K3p3Tz6CnjB; Thu, 16 Oct 2025 16:58:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cnZ0J6DNcz3jtj; Thu, 16 Oct 2025 16:58:24 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760633904; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Piog4mNq/r8CHwX9m3uywnIWfYAjGwUMXxk9dhcHZjM=; b=plfGmtUSq/bYPJmEUs8wO2JzZgKPK6r3L1Lj8+3Akgh57HMJR5bD6NSDUResa0D+zihsz1 H/qmwqt7PQ6KlgavCHrii0MqvvH+mQl5cHYoh3IPRxMX99ZExBF6mQP1g0vPUlzpT9AyEg 8c3w7aObqjEV10ojGA7fbiNZ31pxwiq93LV3bJkehidRB/Qp9LUamwdyW3CCYN1Iw2umXd RvxrfemujCPG337kIZEDaYJ+ixBrVmLprAy71aZc+uXoTkPkyxzfQNcBRO5L1EmEzGnbBf dZx1jpNQkWguoKtH4uWnaAKDns7LxGOksBB8crzuIlbsFruoFJeE6QEkMfbMYw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760633904; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Piog4mNq/r8CHwX9m3uywnIWfYAjGwUMXxk9dhcHZjM=; b=hUBA7t4OTDUF59tYXWeU0RGfsRbfN7WuWJBMxkbKp1xo3Xs3eTgQvgfCiZmAo8yvzTvGPv Y5sXlhpxKfqDw74CovEYLONbU2sUTL+efwZpHPLhV9Bc2pZx2BXbYY/61aYlJMRVj+YEqV LGXjg9fS6RQHROfrr/FQRqs2WjaJJHZxpNnXmWNFfoQdX3J0idsI3LkiPtJQ8QmPWZkZMY qcu7gTPWZ2+ZbcCaVgz3C4JIopkAKfghw0nVHsK9ySwWT1rK4pT76EQuWVb1TcV3O34I0y k1XEkfbSYEjabHGn400rJAiGDVwmQClest3x6DM+aFrur1nvETmR2wHZlGdw2g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1760633904; a=rsa-sha256; cv=none; b=dwzPRzUlkGgWQMYDAOYo7bDfvWk4zFj9nseEGbnZR5ykS1vX/a8lk1D3lYH0FfHyPaSzjA uU0uyrm4TnApq/d0Nqt2ua7FbHfCS6cNXH/NvyrFMqyHRGHCgbyjiI447iUHVQCCfZ0cNR iTDmOG7/y4x6byy1kK9x7TNpJHm/ugV4RIyoK0Yo5xkJK6L8rm1rrQIHF3Q5mf+YgbnPDq fVJF5pKSecdcWSIVMoufZbacOBrgaplDgidqThpTjnlzSQ3Imc6LsMz4vv32IRHKOWcBK0 DpzjRPYvEAe50GG5LnuaPUbJN7JAUuTGhfgwyLxSfbh+UmouIwvB9/nqAUk3lA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cnZ0J5n39z2V5; Thu, 16 Oct 2025 16:58:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 59GGwOHN055877; Thu, 16 Oct 2025 16:58:24 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 59GGwOLH055874; Thu, 16 Oct 2025 16:58:24 GMT (envelope-from git) Date: Thu, 16 Oct 2025 16:58:24 GMT Message-Id: <202510161658.59GGwOLH055874@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Olivier Certner Subject: git: 45e671c9cd3b - stable/15 - sys/rpc: UNIX auth: Fix OOB reads on too short message List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: olce X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 45e671c9cd3b92ad20addf340f96399d0055df7a Auto-Submitted: auto-generated The branch stable/15 has been updated by olce: URL: https://cgit.FreeBSD.org/src/commit/?id=45e671c9cd3b92ad20addf340f96399d0055df7a commit 45e671c9cd3b92ad20addf340f96399d0055df7a Author: Olivier Certner AuthorDate: 2025-10-07 15:51:16 +0000 Commit: Olivier Certner CommitDate: 2025-10-16 16:57:46 +0000 sys/rpc: UNIX auth: Fix OOB reads on too short message In the inline version (_svcauth_unix()), fix multiple possible OOB reads when the credentials part of a request is too short to contain mandatory fields or with respect to the hostname length or number of groups it advertises. The previously existing check was arriving too late and relied on possibly wrong data coming from earlier OOB reads. While here, use 'uint32_t' as the length/size type, as it is more than enough and removes the need for conversions, explicit or implicit. While here, factor out setting 'stat' to AUTH_BADCRED and then jumping to 'done' on error, through the new 'badcred' label. While here, through comments, refer to what the non-inline version is doing (xdr_authunix_parms() in 'authunix_prot.c') and the reasons. Reviewed by: rmacklem Fixes: dfdcada31e79 ("Add the new kernel-mode NFS Lock Manager.") MFC after: 2 days Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D52964 (cherry picked from commit d4cc791f3b2e1b6926420649a481eacaf3bf268e) --- sys/rpc/svc_auth_unix.c | 99 ++++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/sys/rpc/svc_auth_unix.c b/sys/rpc/svc_auth_unix.c index b3389bc79511..4d5535a4fee2 100644 --- a/sys/rpc/svc_auth_unix.c +++ b/sys/rpc/svc_auth_unix.c @@ -59,11 +59,8 @@ _svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg) enum auth_stat stat; XDR xdrs; int32_t *buf; - uint32_t time; struct xucred *xcr; - u_int auth_len; - size_t str_len, supp_ngroups; - u_int i; + uint32_t auth_len, time; xcr = rqst->rq_clntcred; auth_len = (u_int)msg->rm_call.cb_cred.oa_length; @@ -71,51 +68,71 @@ _svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg) XDR_DECODE); buf = XDR_INLINE(&xdrs, auth_len); if (buf != NULL) { - time = IXDR_GET_UINT32(buf); - str_len = (size_t)IXDR_GET_UINT32(buf); - if (str_len > AUTH_SYS_MAX_HOSTNAME) { - stat = AUTH_BADCRED; - goto done; + /* 'time', 'str_len', UID, GID and 'supp_ngroups'. */ + const uint32_t min_len = 5 * BYTES_PER_XDR_UNIT; + uint32_t str_len, supp_ngroups; + + if (auth_len < min_len) { + (void)printf("AUTH_SYS: Too short credentials (%u)\n", + auth_len); + goto badcred; } + time = IXDR_GET_UINT32(buf); + str_len = IXDR_GET_UINT32(buf); + if (str_len > AUTH_SYS_MAX_HOSTNAME) + goto badcred; str_len = RNDUP(str_len); + /* + * Recheck message length now that we know the value of + * 'str_len' (and that it won't cause an overflow in additions + * below) to protect access to the credentials part. + */ + if (auth_len < min_len + str_len) { + (void)printf("AUTH_SYS: Inconsistent credentials and " + "host name lengths (%u, %u)\n", + auth_len, str_len); + goto badcred; + } buf += str_len / sizeof (int32_t); xcr->cr_uid = IXDR_GET_UINT32(buf); xcr->cr_gid = IXDR_GET_UINT32(buf); - supp_ngroups = (size_t)IXDR_GET_UINT32(buf); - if (supp_ngroups > AUTH_SYS_MAX_GROUPS) { - stat = AUTH_BADCRED; - goto done; - } - for (i = 0; i < supp_ngroups; i++) { - /* - * Note that this is a `struct xucred`, which maintains - * its historical layout of preserving the egid in - * cr_ngroups and cr_groups[0] == egid. - */ - if (i + 1 < XU_NGROUPS) - xcr->cr_groups[i + 1] = IXDR_GET_INT32(buf); - else - buf++; + supp_ngroups = IXDR_GET_UINT32(buf); + /* + * See the herald comment before a similar test at the end of + * xdr_authunix_parms() for why we strictly respect RFC 5531 and + * why we may have to drop the last supplementary group when + * there are AUTH_SYS_MAX_GROUPS of them. + */ + if (supp_ngroups > AUTH_SYS_MAX_GROUPS) + goto badcred; + /* + * Final message length check, as we now know how much we will + * read in total. + */ + if (auth_len < min_len + str_len + + supp_ngroups * BYTES_PER_XDR_UNIT) { + (void)printf("AUTH_SYS: Inconsistent lengths " + "(credentials %u, machine name %u, " + "supplementary groups %u)\n", + auth_len, str_len, + supp_ngroups * BYTES_PER_XDR_UNIT); + goto badcred; } - if (supp_ngroups + 1 > XU_NGROUPS) - xcr->cr_ngroups = XU_NGROUPS; - else - xcr->cr_ngroups = supp_ngroups + 1; /* - * five is the smallest unix credentials structure - - * timestamp, hostname len (0), uid, gid, and gids len (0). + * Note that 'xcr' is a 'struct xucred', which still has the + * historical layout where the effective GID is in cr_groups[0] + * and is accounted in 'cr_ngroups'. */ - if ((5 + supp_ngroups) * BYTES_PER_XDR_UNIT + str_len > auth_len) { - (void) printf("bad auth_len gid %ld str %ld auth %u\n", - (long)supp_ngroups, (long)str_len, auth_len); - stat = AUTH_BADCRED; - goto done; + for (uint32_t i = 0; i < supp_ngroups; ++i) { + if (i < XU_NGROUPS - 1) + xcr->cr_sgroups[i] = IXDR_GET_INT32(buf); + else + buf++; } - } else if (! xdr_authunix_parms(&xdrs, &time, xcr)) { - stat = AUTH_BADCRED; - goto done; - } + xcr->cr_ngroups = MIN(supp_ngroups + 1, XU_NGROUPS); + } else if (! xdr_authunix_parms(&xdrs, &time, xcr)) + goto badcred; rqst->rq_verf = _null_auth; stat = AUTH_OK; @@ -123,6 +140,10 @@ done: XDR_DESTROY(&xdrs); return (stat); + +badcred: + stat = AUTH_BADCRED; + goto done; }