Received: by 2002:a25:1985:0:0:0:0:0 with SMTP id 127csp638799ybz; Wed, 29 Apr 2020 06:50:35 -0700 (PDT) X-Google-Smtp-Source: APiQypJA2DcPv2Xp4qx9cUV9HgeYJw1GFLeEJBZk/QVTNa/e4wvIWG5gOuITPvVkDgT24EHcvgLF X-Received: by 2002:a50:e68e:: with SMTP id z14mr2603884edm.307.1588168235176; Wed, 29 Apr 2020 06:50:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1588168235; cv=none; d=google.com; s=arc-20160816; b=L2V+8JYiX3gYWk4HqZw/0kpW/gwyuV6OvzWUTBuISzSvBB5BOT29enBPq7NCG30NGG zAgRTchZ8783WVWuGEO6YJidIZnhLHNhfm/n//pGPL1RyG5/Im/aYyLGYyBTi5n8NOhm 5VWTTgpqojbWC4R4nZ9+XTVOdRFXQLdGHukmvCLz5Lb0QCwsbQEdkNv0rGCOnydqbmJC m2CuBAWA8WtKcdeqHMWqLg35QF3fP4du2wOiyfsLaT+2g/Yk7CuJZgru7vOlfHlXL2oq QV/JybNe1KHBiM8RBgFV0pCoZ5a5hYVlPOj1u9iltGmBn0AyMSgRTHv+mwVjvHrgDyS8 ANqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=NDKH1GRXdpEPgnoVLJym6mQ6V5SHpLmpQKRvFtn5HFI=; b=yRXelzYnHV8LTiQAJkbnJ6UMFshVpfR76y9wCX3mKKOTfjSX6KvjENLjklgVn6dLuE c3ipRGlHBTki4xT8YB/WZxsIMCbUo0s8zmw72CoucSwKsHugJesReYpH90ywCftcUHqI yrk8jjIp8jcP1DXHJhMcL+f0AIsMdyHWnz+XUdjZrU6ExizYzutBH1/RfLJcsKH5hZAe 2aQjgwc9e8TYz/AYj446TllgkQuMvTRSaKn0ga5RIphDjZRUbCaBgSf7Ty36XXiRy34I t8TZz0w0hdzmgmONfIudJ3iHIOxbc1xureyf4PqgzC3TrYOckzLRbTH/evNr7rLNGY+V IXyg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-wireless-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-wireless-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id d13si3944708ejy.137.2020.04.29.06.50.10; Wed, 29 Apr 2020 06:50:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-wireless-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-wireless-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-wireless-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727798AbgD2Ns6 (ORCPT + 99 others); Wed, 29 Apr 2020 09:48:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54916 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726913AbgD2Ns6 (ORCPT ); Wed, 29 Apr 2020 09:48:58 -0400 Received: from sipsolutions.net (s3.sipsolutions.net [IPv6:2a01:4f8:191:4433::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D7F42C03C1AE; Wed, 29 Apr 2020 06:48:57 -0700 (PDT) Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.93) (envelope-from ) id 1jTn55-001vkM-PU; Wed, 29 Apr 2020 15:48:55 +0200 From: Johannes Berg To: netdev@vger.kernel.org Cc: Antonio Quartulli , linux-wireless@vger.kernel.org, Johannes Berg Subject: [PATCH 2/7] netlink: limit recursion depth in policy validation Date: Wed, 29 Apr 2020 15:48:38 +0200 Message-Id: <20200429154836.e15dc653f1dc.Iddcc303b711eabe6cb41f1647c49714d8792bd55@changeid> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200429134843.42224-1-johannes@sipsolutions.net> References: <20200429134843.42224-1-johannes@sipsolutions.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Johannes Berg 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 --- lib/nlattr.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/nlattr.c b/lib/nlattr.c index 3df05db732ca..7f7ebd89caa4 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -44,6 +44,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) { @@ -70,7 +84,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; @@ -87,8 +101,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; } @@ -156,7 +171,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; @@ -269,9 +284,10 @@ static int validate_nla(const struct nlattr *nla, int maxtype, if (attrlen < NLA_HDRLEN) goto out_err; if (pt->nested_policy) { - err = __nla_validate(nla_data(nla), nla_len(nla), pt->len, - pt->nested_policy, validate, - extack); + err = __nla_validate_parse(nla_data(nla), nla_len(nla), + pt->len, pt->nested_policy, + validate, extack, NULL, + depth + 1); if (err < 0) { /* * return directly to preserve the inner @@ -294,7 +310,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype, err = nla_validate_array(nla_data(nla), nla_len(nla), pt->len, pt->nested_policy, - extack, validate); + extack, validate, depth); if (err < 0) { /* * return directly to preserve the inner @@ -358,11 +374,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)); @@ -379,7 +401,7 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype, } if (policy) { int err = validate_nla(nla, maxtype, policy, - validate, extack); + validate, extack, depth); if (err < 0) return err; @@ -421,7 +443,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); @@ -476,7 +498,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); -- 2.25.1