Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp1412408imm; Tue, 10 Jul 2018 01:04:52 -0700 (PDT) X-Google-Smtp-Source: AAOMgpdnZ48A7NlPA3DIfEgDeJ0Bv8JHDEdcTssS65ZA0R8gSqdKUMgWcF4jbuAHawoJu6hqqvQQ X-Received: by 2002:a63:3e0a:: with SMTP id l10-v6mr22028461pga.355.1531209892419; Tue, 10 Jul 2018 01:04:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531209892; cv=none; d=google.com; s=arc-20160816; b=p+BFUWRMl0sXB8pgGD64qHVAhwBUSp3kRbHTh6n2rvzSRyNIt6Xa+kkXMZJNyeGUmo aoQQvGu8WhyqGzNLbdQ/bNu+8cd2mM186vJcWWodc5nTDjRRw/ronr5cPbkSb06RYDRz n1/ZNR8lBC7C60hDXQ3uuhHSvvbhc9Np3IbOIfBoozf5knLtmgMhGRzU34txbx3WuGog KYvgfDbbF67dUzLtiaz4ukRn7AY/xVzotWY7P2n6XoweYqox6c6Lad6B0QEq0JvRFASF 5/Sr5gwhDk6lTO5OlzvcRYfmQ29+gdEPMBjo6T4up5225tL2ONPTzYQnFx+VHXrI7VUe Piqg== 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 :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:arc-authentication-results; bh=SXl+M76QPrC4OCTiJJUNdZ2nKKbO3bmY6gqx6aFGHj4=; b=blI3yeVeoDwQVCuEX7rn8DtLj3pIgqD9gI8NaUvXd+JqKtmbXWFWgX5m0TrFNaszd1 hMz226IdWnbvVyO4kQIOpAsRLjQl0DrmVvo1Nucn35AGBUhoKZudx9aaus04HOcp1grE Q4q6SX6VXEoqNeovSkD/MXp22oB17IEjraGxn9re7nuNkHDkGFD+zurOjKzMhaEul7nw CRq8XX5TnscmmYl0g/U29AksC7mkA9jRTymf1NwXiuhGgd/7Sk9eqvBFbUESlCH9+15J 7HKiSeFLao8nlHE1kTfzMk9OE9D0S9kvu86+4ug+ihNbxGXruDvPt6srGwzKZF9w0UVw o3pw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y7-v6si14527785pgp.551.2018.07.10.01.04.36; Tue, 10 Jul 2018 01:04:52 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933516AbeGJIDX (ORCPT + 99 others); Tue, 10 Jul 2018 04:03:23 -0400 Received: from www62.your-server.de ([213.133.104.62]:44606 "EHLO www62.your-server.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751182AbeGJIDV (ORCPT ); Tue, 10 Jul 2018 04:03:21 -0400 Received: from [88.198.220.130] (helo=sslproxy01.your-server.de) by www62.your-server.de with esmtpsa (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.85_2) (envelope-from ) id 1fcncG-0000bt-4Z; Tue, 10 Jul 2018 10:03:20 +0200 Received: from [2a02:120b:c3f4:b8b0:b5ea:3969:d380:aafd] (helo=linux.home) by sslproxy01.your-server.de with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1fcncF-0004a0-Tb; Tue, 10 Jul 2018 10:03:19 +0200 Subject: Re: [PATCH bpf] bpf: fix some bad __rcu annotations in bpf/core.c To: Roman Gushchin , netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kernel-team@fb.com, Alexei Starovoitov , yhs@fb.com References: <20180710015915.26358-1-guro@fb.com> From: Daniel Borkmann Message-ID: <31c2b14a-8890-0ebd-bb59-01616e9d8d5d@iogearbox.net> Date: Tue, 10 Jul 2018 10:03:19 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.3.0 MIME-Version: 1.0 In-Reply-To: <20180710015915.26358-1-guro@fb.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Authenticated-Sender: daniel@iogearbox.net X-Virus-Scanned: Clear (ClamAV 0.100.0/24739/Tue Jul 10 06:45:06 2018) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Roman, On 07/10/2018 03:59 AM, Roman Gushchin wrote: > Sparse shows some "incorrect type" warnings in the bpf core code. Thanks for taking a stab at these! It would really help if you could split the patch into a small series and fix each individual case that is problematic here. Please also add Fixes tags to the patches. More below. > They are caused by bad __rcu annotations: > 1) bpf_prog_array_alloc() returns an __rcu pointer, which isn't true. > At that moment it's obviously an exclusive "owning" pointer, > which is valid for an infinite amount of time, so __rcu is > meaningless. > 2) The progs local variable in compute_effective_progs should be > marked as __bpf too, it's a local variable, not shared with anyone Typo: __bpf ? > else at all. The real __rcu variable is array pointer, which should > be assigned with rcu_assign_pointer. > 3) __rcu progs argument of bpf_prog_array_free() should be casted > to a simple pointer before calling kfree_rcu(). > 4) There is a missing rcu_dereference() annotation in > bpf_prog_array_copy_to_user(). > 5) old_array __rcu pointer in bpf_prog_array_copy() is used as > a "normal" non-__rcu pointer. > > These changes remove the following sparse warnings: > kernel/bpf/core.c:1544:31: warning: incorrect type in return expression (different address spaces) > kernel/bpf/core.c:1544:31: expected struct bpf_prog_array [noderef] * > kernel/bpf/core.c:1544:31: got void * > kernel/bpf/core.c:1548:17: warning: incorrect type in return expression (different address spaces) > kernel/bpf/core.c:1548:17: expected struct bpf_prog_array [noderef] * > kernel/bpf/core.c:1548:17: got struct bpf_prog_array * > kernel/bpf/core.c:1556:9: warning: incorrect type in argument 1 (different address spaces) > kernel/bpf/core.c:1556:9: expected struct callback_head *head > kernel/bpf/core.c:1556:9: got struct callback_head [noderef] * > kernel/bpf/core.c:1629:34: warning: incorrect type in initializer (different address spaces) > kernel/bpf/core.c:1629:34: expected struct bpf_prog **prog > kernel/bpf/core.c:1629:34: got struct bpf_prog *[noderef] * > kernel/bpf/core.c:1653:31: warning: incorrect type in assignment (different address spaces) > kernel/bpf/core.c:1653:31: expected struct bpf_prog **existing_prog > kernel/bpf/core.c:1653:31: got struct bpf_prog *[noderef] * > kernel/bpf/core.c:1681:15: warning: incorrect type in assignment (different address spaces) > kernel/bpf/core.c:1681:15: expected struct bpf_prog_array *array > kernel/bpf/core.c:1681:15: got struct bpf_prog_array [noderef] * > kernel/bpf/core.c:1687:31: warning: incorrect type in assignment (different address spaces) > kernel/bpf/core.c:1687:31: expected struct bpf_prog **[assigned] existing_prog > kernel/bpf/core.c:1687:31: got struct bpf_prog *[noderef] * > > Signed-off-by: Roman Gushchin > Cc: Daniel Borkmann > Cc: Alexei Starovoitov > --- > include/linux/bpf.h | 2 +- > kernel/bpf/cgroup.c | 7 +++---- > kernel/bpf/core.c | 14 ++++++++------ > 3 files changed, 12 insertions(+), 11 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 8827e797ff97..943fb08d8287 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -352,7 +352,7 @@ struct bpf_prog_array { > struct bpf_prog *progs[0]; > }; > > -struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); > +struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); > void bpf_prog_array_free(struct bpf_prog_array __rcu *progs); > int bpf_prog_array_length(struct bpf_prog_array __rcu *progs); > int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, > diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c > index 3d83ee7df381..badabb0b435c 100644 > --- a/kernel/bpf/cgroup.c > +++ b/kernel/bpf/cgroup.c > @@ -95,7 +95,7 @@ static int compute_effective_progs(struct cgroup *cgrp, > enum bpf_attach_type type, > struct bpf_prog_array __rcu **array) > { > - struct bpf_prog_array __rcu *progs; > + struct bpf_prog_array *progs; > struct bpf_prog_list *pl; > struct cgroup *p = cgrp; > int cnt = 0; > @@ -120,13 +120,12 @@ static int compute_effective_progs(struct cgroup *cgrp, > &p->bpf.progs[type], node) { > if (!pl->prog) > continue; > - rcu_dereference_protected(progs, 1)-> > - progs[cnt++] = pl->prog; > + progs->progs[cnt++] = pl->prog; > } > p = cgroup_parent(p); > } while (p); > > - *array = progs; > + rcu_assign_pointer(*array, progs); > return 0; > } > > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index 1e5625d46414..f6e5b207a0d7 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -1538,7 +1538,7 @@ static struct { > .null_prog = NULL, > }; > > -struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags) > +struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags) > { > if (prog_cnt) > return kzalloc(sizeof(struct bpf_prog_array) + > @@ -1550,10 +1550,11 @@ struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags) Looks good to me to here. > void bpf_prog_array_free(struct bpf_prog_array __rcu *progs) > { > - if (!progs || > - progs == (struct bpf_prog_array __rcu *)&empty_prog_array.hdr) > + struct bpf_prog_array *array = rcu_access_pointer(progs); Can you elaborate on the rcu_access_pointer() part? This looks odd, at minimum this needs a comment explaining why it's needed. Is the __rcu annotation above even correct? > + > + if (!array || array == &empty_prog_array.hdr) > return; > - kfree_rcu(progs, rcu); > + kfree_rcu(array, rcu); > } > > int bpf_prog_array_length(struct bpf_prog_array __rcu *progs) > @@ -1626,7 +1627,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, > void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, > struct bpf_prog *old_prog) > { > - struct bpf_prog **prog = progs->progs; > + struct bpf_prog **prog = rcu_dereference(progs)->progs; Can you elaborate here as well? __rcu annotation buggy instead? > for (; *prog; prog++) > if (*prog == old_prog) { > @@ -1635,11 +1636,12 @@ void bpf_prog_array_delete_safe(struct bpf_prog_array __rcu *progs, > } > } > > -int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array, > +int bpf_prog_array_copy(struct bpf_prog_array __rcu *__old_array, > struct bpf_prog *exclude_prog, > struct bpf_prog *include_prog, > struct bpf_prog_array **new_array) > { > + struct bpf_prog_array *old_array = rcu_access_pointer(__old_array); Same comment here, this doesn't look right. We even fetch old_array->progs from it later on in this path. > int new_prog_cnt, carry_prog_cnt = 0; > struct bpf_prog **existing_prog; > struct bpf_prog_array *array; > Thanks, Daniel