From patchwork Sun May 28 19:00:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuxuan Luo X-Patchwork-Id: 1786896 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=canonical.com header.i=@canonical.com header.a=rsa-sha256 header.s=20210705 header.b=iem90KJH; dkim-atps=neutral Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QTnzl1Rllz20W0 for ; Mon, 29 May 2023 05:00:33 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1q3Lcq-0007wQ-KK; Sun, 28 May 2023 19:00:20 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1q3Lcn-0007vz-4r for kernel-team@lists.ubuntu.com; Sun, 28 May 2023 19:00:17 +0000 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 05A353F193 for ; Sun, 28 May 2023 19:00:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1685300415; bh=fSIyxTwfsE1QofBtZDF4Vwlh8Iz18N13X573XgrXFA4=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iem90KJHcZGNZfHWurol654p7pYcgeJvhLIxgqAcyKsLQIF4LIUmgx8sTxvZ86qXL rb6bRVPnZ9tmSB9oAYEAMWc3s9k6myv6hZL5wV2S2ZuhigIAmS12SGJIjRFXGvh1pG RIYtETgj3TY24N1N+s25btMknPxSPDciAvGbif4vctFqm5pJdFen5ScMKFsjXXQ8X6 zT1QYXOD56bZCfH3rp1Kk6zQdYHN2vIcemeIbjzcrOBhc+Dz9rbUQ6uV6cfRvP3vm0 CV7WGqGlTseyHc2JJIZ9+JZxMdSisw1cwqb5ynrxMhGuQAl0clFNciUpowI2qiaM8q 5Ee/aKBBJMriA== Received: by mail-qt1-f200.google.com with SMTP id d75a77b69052e-3f7fd14d605so15455371cf.1 for ; Sun, 28 May 2023 12:00:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685300413; x=1687892413; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fSIyxTwfsE1QofBtZDF4Vwlh8Iz18N13X573XgrXFA4=; b=RP3EcoEZCDxpdZ0OqBPUfM7Mbc2cnrjF0ooLDf3n+ykGtlzdw7m2dYQEXjf0G7hiSn H3XwgeybZvsEO8plrzfX6gQSgAYHtxYCOj3571PLsUflPx6AX9NClMQW6Yj5x+NQzSvD NO2wwiiKzDx6ptUTnMWdaHW2nTN24uQYc2xUvWrvYb4BtsPKnHW9c1EdIU0nwQFTF2l4 L3dzVp61V9W3d1TI6Xs60mzGa7ji//q/YEcv2kRddwdf09ZQKx9vRcbuozXr6p3+uhj1 WPGM5oNhYIYj2Hw0oQ4k0FcTPRl1g4uuvxJ7ncfvWEvN9Qoq446ewzHQnpQJVsPUZtM8 u9hw== X-Gm-Message-State: AC+VfDzR0E0DATdPs36uVF/+1jhk37CU4UJvNxY+N7bv97MOZjy+0isp e6BbugLDqD6gAjN9cBoEOTYGoAUJcK/2zvbayoB7uCNAskLs5hZijT0GoJ5q+IPGs7Z9vqbSiIH jY03NuiAdn+V2rm+vQZ56aDE3ffoirMTMQkDFQlqD8XN8AZKJBQ== X-Received: by 2002:a05:622a:306:b0:3f0:a892:3c0e with SMTP id q6-20020a05622a030600b003f0a8923c0emr8661231qtw.47.1685300413458; Sun, 28 May 2023 12:00:13 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5K6vKei+L3BMG/6DojvNiyL2Fog2DlwfqvtDvRnl7X4nBdEQh4MAqWkRWR8m680il8ueK3eA== X-Received: by 2002:a05:622a:306:b0:3f0:a892:3c0e with SMTP id q6-20020a05622a030600b003f0a8923c0emr8661205qtw.47.1685300412997; Sun, 28 May 2023 12:00:12 -0700 (PDT) Received: from cache-ubuntu.hsd1.nj.comcast.net ([2601:86:200:98b0:b8a2:bf93:e03b:7b20]) by smtp.gmail.com with ESMTPSA id b11-20020ad4518b000000b006215d0bdf37sm3082826qvp.16.2023.05.28.12.00.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 28 May 2023 12:00:12 -0700 (PDT) From: Yuxuan Luo To: kernel-team@lists.ubuntu.com Subject: [SRU][Focal][PATCH 1/1] netlink: limit recursion depth in policy validation Date: Sun, 28 May 2023 15:00:09 -0400 Message-Id: <20230528190009.24889-2-yuxuan.luo@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230528190009.24889-1-yuxuan.luo@canonical.com> References: <20230528190009.24889-1-yuxuan.luo@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" Now that we have nested policies, we can theoretically recurse forever parsing attributes if a (sub-)policy refers back to a higher level one. This is a situation that has happened in nl80211, and we've avoided it there by not linking it. Add some code to netlink parsing to limit recursion depth. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller (backported from commit 7690aa1cdf7c4565ad6b013b324c28b685505e24) [yuxuan.luo: skip the 47a1494b8208 commit and backport the fix commit directly by keep the validation_data parameter and add the new depth parameter. ] CVE-2020-36691 Signed-off-by: Yuxuan Luo --- lib/nlattr.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/nlattr.c b/lib/nlattr.c index b5ce5e46c06e0..c770b7bd6bc70 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -45,6 +45,20 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = { [NLA_S64] = sizeof(s64), }; +/* + * Nested policies might refer back to the original + * policy in some cases, and userspace could try to + * abuse that and recurse by nesting in the right + * ways. Limit recursion to avoid this problem. + */ +#define MAX_POLICY_RECURSION_DEPTH 10 + +static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype, + const struct nla_policy *policy, + unsigned int validate, + struct netlink_ext_ack *extack, + struct nlattr **tb, unsigned int depth); + static int validate_nla_bitfield32(const struct nlattr *nla, const u32 *valid_flags_mask) { @@ -71,7 +85,7 @@ static int validate_nla_bitfield32(const struct nlattr *nla, static int nla_validate_array(const struct nlattr *head, int len, int maxtype, const struct nla_policy *policy, struct netlink_ext_ack *extack, - unsigned int validate) + unsigned int validate, unsigned int depth) { const struct nlattr *entry; int rem; @@ -88,8 +102,9 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype, return -ERANGE; } - ret = __nla_validate(nla_data(entry), nla_len(entry), - maxtype, policy, validate, extack); + ret = __nla_validate_parse(nla_data(entry), nla_len(entry), + maxtype, policy, validate, extack, + NULL, depth + 1); if (ret < 0) return ret; } @@ -157,7 +172,7 @@ static int nla_validate_int_range(const struct nla_policy *pt, static int validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy, unsigned int validate, - struct netlink_ext_ack *extack) + struct netlink_ext_ack *extack, unsigned int depth) { u16 strict_start_type = policy[0].strict_start_type; const struct nla_policy *pt; @@ -271,9 +286,10 @@ static int validate_nla(const struct nlattr *nla, int maxtype, if (attrlen < NLA_HDRLEN) goto out_err; if (pt->validation_data) { - err = __nla_validate(nla_data(nla), nla_len(nla), pt->len, - pt->validation_data, validate, - extack); + err = __nla_validate_parse(nla_data(nla), nla_len(nla), + pt->len, pt->validation_data, + validate, extack, NULL, + depth + 1); if (err < 0) { /* * return directly to preserve the inner @@ -296,7 +312,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype, err = nla_validate_array(nla_data(nla), nla_len(nla), pt->len, pt->validation_data, - extack, validate); + extack, validate, depth); if (err < 0) { /* * return directly to preserve the inner @@ -360,11 +376,17 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype, const struct nla_policy *policy, unsigned int validate, struct netlink_ext_ack *extack, - struct nlattr **tb) + struct nlattr **tb, unsigned int depth) { const struct nlattr *nla; int rem; + if (depth >= MAX_POLICY_RECURSION_DEPTH) { + NL_SET_ERR_MSG(extack, + "allowed policy recursion depth exceeded"); + return -EINVAL; + } + if (tb) memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); @@ -382,7 +404,7 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype, type = array_index_nospec(type, maxtype + 1); if (policy) { int err = validate_nla(nla, maxtype, policy, - validate, extack); + validate, extack, depth); if (err < 0) return err; @@ -424,7 +446,7 @@ int __nla_validate(const struct nlattr *head, int len, int maxtype, struct netlink_ext_ack *extack) { return __nla_validate_parse(head, len, maxtype, policy, validate, - extack, NULL); + extack, NULL, 0); } EXPORT_SYMBOL(__nla_validate); @@ -479,7 +501,7 @@ int __nla_parse(struct nlattr **tb, int maxtype, struct netlink_ext_ack *extack) { return __nla_validate_parse(head, len, maxtype, policy, validate, - extack, tb); + extack, tb, 0); } EXPORT_SYMBOL(__nla_parse);