Netdev List
 help / color / mirror / Atom feed
* [PATCH net] ipv6: Don't use ufo handling on later transformed packets
From: Jakub Sitnicki @ 2016-10-26  9:21 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Hannes Frederic Sowa, Florian Westphal

Similar to commit c146066ab802 ("ipv4: Don't use ufo handling on later
transformed packets"), don't perform UFO on packets that will be IPsec
transformed. To detect it we rely on the fact that headerlen in
dst_entry is non-zero only for transformation bundles (xfrm_dst
objects).

Unwanted segmentation can be observed with a NETIF_F_UFO capable device,
such as a dummy device:

  DEV=dum0 LEN=1493

  ip li add $DEV type dummy
  ip addr add fc00::1/64 dev $DEV nodad
  ip link set $DEV up
  ip xfrm policy add dir out src fc00::1 dst fc00::2 \
     tmpl src fc00::1 dst fc00::2 proto esp spi 1
  ip xfrm state add src fc00::1 dst fc00::2 \
     proto esp spi 1 enc 'aes' 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b

  tcpdump -n -nn -i $DEV -t &
  socat /dev/zero,readbytes=$LEN udp6:[fc00::2]:$LEN

tcpdump output before:

  IP6 fc00::1 > fc00::2: frag (0|1448) ESP(spi=0x00000001,seq=0x1), length 1448
  IP6 fc00::1 > fc00::2: frag (1448|48)
  IP6 fc00::1 > fc00::2: ESP(spi=0x00000001,seq=0x2), length 88

... and after:

  IP6 fc00::1 > fc00::2: frag (0|1448) ESP(spi=0x00000001,seq=0x1), length 1448
  IP6 fc00::1 > fc00::2: frag (1448|80)

Fixes: e89e9cf539a2 ("[IPv4/IPv6]: UFO Scatter-gather approach")

Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
 net/ipv6/ip6_output.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 6001e78..59eb4ed 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1366,7 +1366,7 @@ static int __ip6_append_data(struct sock *sk,
 	if (((length > mtu) ||
 	     (skb && skb_is_gso(skb))) &&
 	    (sk->sk_protocol == IPPROTO_UDP) &&
-	    (rt->dst.dev->features & NETIF_F_UFO) &&
+	    (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
 	    (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) {
 		err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
 					  hh_len, fragheaderlen, exthdrlen,
-- 
2.7.4

^ permalink raw reply related

* Re: concurrent rhashtable test failure
From: Geert Uytterhoeven @ 2016-10-26  9:11 UTC (permalink / raw)
  To: Phil Sutter, Geert Uytterhoeven, Thomas Graf, Herbert Xu,
	netdev@vger.kernel.org, linux-m68k
In-Reply-To: <20161026073337.GM5640@orbyte.nwl.cc>

On Wed, Oct 26, 2016 at 9:33 AM, Phil Sutter <phil@nwl.cc> wrote:
> On Mon, Oct 24, 2016 at 02:11:32PM +0200, Geert Uytterhoeven wrote:
>> On m68k/ARAnyM, test_rhashtable fails with:
>>
>>     Test failed: thread 0 returned: -4
>>
>> (-4 = -EINTR)
>
> How reproducible is this? I wonder why out of the ten threads only the
> first one fails.

100% reproducible.

Does it need SMP?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH net-next] switchdev: Remove redundant variable
From: idosch @ 2016-10-26  9:03 UTC (permalink / raw)
  To: davem, jiri; +Cc: netdev, mlxsw, Ido Schimmel

From: Ido Schimmel <idosch@mellanox.com>

Instead of storing return value in 'err' and returning, just return
directly.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
---
 net/switchdev/switchdev.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 02beb35..6f145b5 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -624,13 +624,10 @@ EXPORT_SYMBOL_GPL(unregister_switchdev_notifier);
 int call_switchdev_notifiers(unsigned long val, struct net_device *dev,
 			     struct switchdev_notifier_info *info)
 {
-	int err;
-
 	ASSERT_RTNL();
 
 	info->dev = dev;
-	err = raw_notifier_call_chain(&switchdev_notif_chain, val, info);
-	return err;
+	return raw_notifier_call_chain(&switchdev_notif_chain, val, info);
 }
 EXPORT_SYMBOL_GPL(call_switchdev_notifiers);
 
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH net-next] netlink: Add nla_memdup() to wrap kmemdup() use on nlattr
From: Johannes Berg @ 2016-10-26  8:59 UTC (permalink / raw)
  To: Thomas Graf, davem-fT/PcQaiUtIeIZ0/mPfg9Q
  Cc: daniel-FeC+5ew28dpmcu3hnIyYJQ, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <2d0864c85200f1b42b1ebceee7c2dc60fe29f26a.1477471562.git.tgraf-G/eBtMaohhA@public.gmane.org>


>  /**
> + * nla_memdup - duplicate attribute memory (kmemdup)
> + * @src: netlink attribute to duplicate from
> + * @gfp: GFP mask

Actually, is there any point in passing a GFP mask? None of the current
users need it, and it seems fairly unlikely to be needed since this is
typically used on the netlink input path, where you surely shouldn't
need GFP_ATOMIC or so?

johannes

^ permalink raw reply

* Re: [PATCH (net.git) 0/3] stmmac: fix PTP support
From: Richard Cochran @ 2016-10-26  8:58 UTC (permalink / raw)
  To: Giuseppe Cavallaro
  Cc: netdev, alexandre.torgue, rayagond, linux-kernel,
	seraphin.bonnaffe
In-Reply-To: <1477464964-5960-1-git-send-email-peppe.cavallaro@st.com>

On Wed, Oct 26, 2016 at 08:56:01AM +0200, Giuseppe Cavallaro wrote:
> This subset of patches aim to fix the PTP support
> for the stmmac and especially for 4.x chip series.
> While setting PTP on an ST box with 4.00a Ethernet
> core, the kernel panics due to a broken settings
> of the descriptors. The patches review the
> register configuration, the algo used for configuring
> the protocol, the way to get the timestamp inside
> the RX/TX descriptors and, in the end, the statistics
> displayed by ethtool.
> 
> Giuseppe Cavallaro (3):
>   stmmac: update the PTP header file
>   stmmac: fix PTP support for GMAC4
>   stmmac: fix PTP type ethtool stats

Acked-by: Richard Cochran <richardcochran@gmail.com>

^ permalink raw reply

* Re: [PATCH net-next] netlink: Add nla_memdup() to wrap kmemdup() use on nlattr
From: Daniel Borkmann @ 2016-10-26  8:57 UTC (permalink / raw)
  To: Thomas Graf, davem; +Cc: johannes, netdev, linux-wireless
In-Reply-To: <2d0864c85200f1b42b1ebceee7c2dc60fe29f26a.1477471562.git.tgraf@suug.ch>

On 10/26/2016 10:53 AM, Thomas Graf wrote:
> Wrap several common instances of:
> 	kmemdup(nla_data(attr), nla_len(attr), GFP_KERNEL);
>
> Signed-off-by: Thomas Graf <tgraf@suug.ch>

Thanks!

Acked-by: Daniel Borkmann <daniel@iogearbox.net>

^ permalink raw reply

* Re: [PATCH net-next] netlink: Add nla_memdup() to wrap kmemdup() use on nlattr
From: Johannes Berg @ 2016-10-26  8:56 UTC (permalink / raw)
  To: Thomas Graf, davem-fT/PcQaiUtIeIZ0/mPfg9Q
  Cc: daniel-FeC+5ew28dpmcu3hnIyYJQ, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <2d0864c85200f1b42b1ebceee7c2dc60fe29f26a.1477471562.git.tgraf-G/eBtMaohhA@public.gmane.org>

On Wed, 2016-10-26 at 10:53 +0200, Thomas Graf wrote:
> Wrap several common instances of:
> 	kmemdup(nla_data(attr), nla_len(attr), GFP_KERNEL);

Makes sense

Acked-by: Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org>

johannes

^ permalink raw reply

* [PATCH net-next] netlink: Add nla_memdup() to wrap kmemdup() use on nlattr
From: Thomas Graf @ 2016-10-26  8:53 UTC (permalink / raw)
  To: davem; +Cc: johannes, daniel, netdev, linux-wireless

Wrap several common instances of:
	kmemdup(nla_data(attr), nla_len(attr), GFP_KERNEL);

Signed-off-by: Thomas Graf <tgraf@suug.ch>
---
 include/net/netlink.h  | 10 ++++++++++
 net/sched/act_bpf.c    |  4 +---
 net/sched/cls_bpf.c    |  4 +---
 net/wireless/nl80211.c |  3 +--
 4 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/include/net/netlink.h b/include/net/netlink.h
index 254a0fc..a34f53a 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -1191,6 +1191,16 @@ static inline struct in6_addr nla_get_in6_addr(const struct nlattr *nla)
 }
 
 /**
+ * nla_memdup - duplicate attribute memory (kmemdup)
+ * @src: netlink attribute to duplicate from
+ * @gfp: GFP mask
+ */
+static inline void *nla_memdup(const struct nlattr *src, gfp_t gfp)
+{
+	return kmemdup(nla_data(src), nla_len(src), gfp);
+}
+
+/**
  * nla_nest_start - Start a new level of nested attributes
  * @skb: socket buffer to add attributes to
  * @attrtype: attribute type of container
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 1d39600..9ff06cf 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -226,9 +226,7 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
 		return PTR_ERR(fp);
 
 	if (tb[TCA_ACT_BPF_NAME]) {
-		name = kmemdup(nla_data(tb[TCA_ACT_BPF_NAME]),
-			       nla_len(tb[TCA_ACT_BPF_NAME]),
-			       GFP_KERNEL);
+		name = nla_memdup(tb[TCA_ACT_BPF_NAME], GFP_KERNEL);
 		if (!name) {
 			bpf_prog_put(fp);
 			return -ENOMEM;
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index bb1d5a4..52dc85a 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -369,9 +369,7 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
 		return PTR_ERR(fp);
 
 	if (tb[TCA_BPF_NAME]) {
-		name = kmemdup(nla_data(tb[TCA_BPF_NAME]),
-			       nla_len(tb[TCA_BPF_NAME]),
-			       GFP_KERNEL);
+		name = nla_memdup(tb[TCA_BPF_NAME], GFP_KERNEL);
 		if (!name) {
 			bpf_prog_put(fp);
 			return -ENOMEM;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c510810..7bfe1e0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10638,8 +10638,7 @@ static int handle_nan_filter(struct nlattr *attr_filter,
 
 	i = 0;
 	nla_for_each_nested(attr, attr_filter, rem) {
-		filter[i].filter = kmemdup(nla_data(attr), nla_len(attr),
-					   GFP_KERNEL);
+		filter[i].filter = nla_memdup(attr, GFP_KERNEL);
 		filter[i].len = nla_len(attr);
 		i++;
 	}
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v2 5/5] posix-timers: make it configurable
From: Richard Cochran @ 2016-10-26  8:51 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: John Stultz, Yann E. MORIN, Michal Marek, Thomas Gleixner,
	Josh Triplett, Edward Cree, netdev, linux-kbuild, linux-kernel
In-Reply-To: <1477448931-29051-6-git-send-email-nicolas.pitre@linaro.org>

On Tue, Oct 25, 2016 at 10:28:51PM -0400, Nicolas Pitre wrote:
> +config POSIX_TIMERS
> +	bool "Posix Clocks & timers" if EXPERT
> +	default y
> +	help
> +	  This includes native support for POSIX timers to the kernel.
> +	  Most embedded systems may have no use for them and therefore they
> +	  can be configured out to reduce the size of the kernel image.

Can you please fix this sentence?  It doesn't make any sense.  "Most"
is making a definite statement of fact, while "may have no use" is
not.

Either you mean:

  1. Most embedded systems have no use for them.

  2. Embedded systems may have no use for them.

or expressing #2 in other words:

  3. Many embedded systems have no use for them.

  4. Some embedded systems have no use for them.

Take your pick.  (But I doubt #1 is really true, and so I would like
to see some numbers to back up that claim.)

Thanks,
Richard

^ permalink raw reply

* Re: [PATCH net-next 2/3] bpf: Add new cgroups prog type to enable sock modifications
From: Thomas Graf @ 2016-10-26  8:41 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, daniel, ast, daniel
In-Reply-To: <1477434613-3169-3-git-send-email-dsa@cumulusnetworks.com>

On 10/25/16 at 03:30pm, David Ahern wrote:
> @@ -171,6 +177,9 @@ int __cgroup_bpf_run_filter(struct sock *sk,
>  		case BPF_CGROUP_INET_EGRESS:
>  			ret = __cgroup_bpf_run_filter_skb(skb, prog);
>  			break;
> +		case BPF_CGROUP_INET_SOCK_CREATE:
> +			ret = __cgroup_bpf_run_filter_sk_create(sk, prog);
> +			break;
>  		/* make gcc happy else complains about missing enum value */
>  		default:
>  			return 0;

Thinking further ahead of your simple example. Instead of adding yet
another prog type for the same hook, we can make this compatible with
BPF_CGROUP_INET_EGRESS instead which would then provide a ctx which
contains both, the sk and skb.

The ctx concept is very flexible. We can keep the existing dummy skb
representation and add sk_ fields which are only valid for BPF at
socket layer, e.g skb->sk_bound_dev_if would translate to
sk->bound_dev_if.

^ permalink raw reply

* Re: [PATCH net-next 2/3] bpf: Add new cgroups prog type to enable sock modifications
From: Daniel Borkmann @ 2016-10-26  8:33 UTC (permalink / raw)
  To: David Ahern, netdev; +Cc: daniel, ast
In-Reply-To: <660435c4-6cea-9648-0106-afb3ab6910fc@cumulusnetworks.com>

On 10/26/2016 04:05 AM, David Ahern wrote:
> On 10/25/16 5:28 PM, Daniel Borkmann wrote:
>>> +BPF_CALL_3(bpf_sock_store_u32, struct sock *, sk, u32, offset, u32, val)
>>> +{
>>> +    u8 *ptr = (u8 *)sk;
>>> +
>>> +    if (unlikely(offset > sizeof(*sk)))
>>> +        return -EFAULT;
>>> +
>>> +    *((u32 *)ptr) = val;
>>> +
>>> +    return 0;
>>> +}
>>
>> Seems strange to me. So, this helper allows to overwrite arbitrary memory
>> of a struct sock instance. Potentially we could crash the kernel.
>>
>> And in your sock_filter_convert_ctx_access(), you already implement inline
>> read/write for the context ...
>>
>> Your demo code does in pseudocode:
>>
>>    r1 = sk
>>    r2 = offsetof(struct bpf_sock, bound_dev_if)
>>    r3 = idx
>>    r1->sk_bound_dev_if = idx
>>    sock_store_u32(r1, r2, r3) // updates sk_bound_dev_if again to idx
>>    return 1
>>
>> Dropping that helper from the patch, the only thing a program can do here
>> is to read/write the sk_bound_dev_if helper per cgroup. Hmm ... dunno. So
>> this really has to be for cgroups v2, right?
>
> Showing my inexperience with the bpf code. The helper can be dropped. I'll do that for v2.
>
> Yes, Daniel's patch set provides the infra for this one and it has a cgroups v2 limitation.

Sure, I understand that, and I know it was brought up at netconf, I'm
just still wondering in general if BPF is a good fit here in the sense
that what the program can do is just really really limited (at least
right now). Hmm, just trying to understand where this would go long term.
Probably okay'ish, if it's guaranteed that it can also integrate various
other use cases as well for the new program type like the ones proposed
by Anoop from net cgroup.

If that would reuse BPF_PROG_TYPE_CGROUP_SOCK from not only sk_alloc()
hook, programs can thus change sk_bound_dev_if also from elsewhere since
it's a fixed part of the context, and attaching to the cgroup comes after
program was verified and returned a program fd back to the user. I guess
it might be expected, right?

I mean non-cooperative processes in that cgroup could already overwrite
the policy set in sk_alloc() anyway with SO_BINDTODEVICE, no? What is the
expectation if processes are moved from one cgroup to another one? Is it
expected that also sk_bound_dev_if updates (not yet seeing how that would
work from a BPF program)? If sk_bound_dev_if is enforced from cgroup side,
should that lock out processes from changing it (maybe similar to what we
do in SOCK_FILTER_LOCKED)?

^ permalink raw reply

* [PATCH net] cxgb4: Fix error handling in alloc_uld_rxqs().
From: Ganesh Goudar @ 2016-10-26  7:56 UTC (permalink / raw)
  To: davem, netdev; +Cc: hariprasad, nirranjan, Ganesh Goudar

Fix to release resources properly in error handling path of
alloc_uld_rxqs(), This patch also removes unwanted arguments
and avoids calling the same function twice.

Fixes: 94cdb8bb993a (cxgb4: Add support for dynamic allocation
       of resources for ULD
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 40 ++++++++++++--------------
 1 file changed, 18 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
index 0945fa4..2471ff4 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
@@ -135,15 +135,17 @@ static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp,
 }
 
 static int alloc_uld_rxqs(struct adapter *adap,
-			  struct sge_uld_rxq_info *rxq_info,
-			  unsigned int nq, unsigned int offset, bool lro)
+			  struct sge_uld_rxq_info *rxq_info, bool lro)
 {
 	struct sge *s = &adap->sge;
-	struct sge_ofld_rxq *q = rxq_info->uldrxq + offset;
-	unsigned short *ids = rxq_info->rspq_id + offset;
-	unsigned int per_chan = nq / adap->params.nports;
+	unsigned int nq = rxq_info->nrxq + rxq_info->nciq;
+	struct sge_ofld_rxq *q = rxq_info->uldrxq;
+	unsigned short *ids = rxq_info->rspq_id;
 	unsigned int bmap_idx = 0;
-	int i, err, msi_idx;
+	unsigned int per_chan;
+	int i, err, msi_idx, que_idx = 0;
+
+	per_chan = rxq_info->nrxq / adap->params.nports;
 
 	if (adap->flags & USING_MSIX)
 		msi_idx = 1;
@@ -151,12 +153,18 @@ static int alloc_uld_rxqs(struct adapter *adap,
 		msi_idx = -((int)s->intrq.abs_id + 1);
 
 	for (i = 0; i < nq; i++, q++) {
+		if (i == rxq_info->nrxq) {
+			/* start allocation of concentrator queues */
+			per_chan = rxq_info->nciq / adap->params.nports;
+			que_idx = 0;
+		}
+
 		if (msi_idx >= 0) {
 			bmap_idx = get_msix_idx_from_bmap(adap);
 			msi_idx = adap->msix_info_ulds[bmap_idx].idx;
 		}
 		err = t4_sge_alloc_rxq(adap, &q->rspq, false,
-				       adap->port[i / per_chan],
+				       adap->port[que_idx++ / per_chan],
 				       msi_idx,
 				       q->fl.size ? &q->fl : NULL,
 				       uldrx_handler,
@@ -165,29 +173,19 @@ static int alloc_uld_rxqs(struct adapter *adap,
 		if (err)
 			goto freeout;
 		if (msi_idx >= 0)
-			rxq_info->msix_tbl[i + offset] = bmap_idx;
+			rxq_info->msix_tbl[i] = bmap_idx;
 		memset(&q->stats, 0, sizeof(q->stats));
 		if (ids)
 			ids[i] = q->rspq.abs_id;
 	}
 	return 0;
 freeout:
-	q = rxq_info->uldrxq + offset;
+	q = rxq_info->uldrxq;
 	for ( ; i; i--, q++) {
 		if (q->rspq.desc)
 			free_rspq_fl(adap, &q->rspq,
 				     q->fl.size ? &q->fl : NULL);
 	}
-
-	/* We need to free rxq also in case of ciq allocation failure */
-	if (offset) {
-		q = rxq_info->uldrxq + offset;
-		for ( ; i; i--, q++) {
-			if (q->rspq.desc)
-				free_rspq_fl(adap, &q->rspq,
-					     q->fl.size ? &q->fl : NULL);
-		}
-	}
 	return err;
 }
 
@@ -205,9 +203,7 @@ setup_sge_queues_uld(struct adapter *adap, unsigned int uld_type, bool lro)
 			return -ENOMEM;
 	}
 
-	ret = !(!alloc_uld_rxqs(adap, rxq_info, rxq_info->nrxq, 0, lro) &&
-		 !alloc_uld_rxqs(adap, rxq_info, rxq_info->nciq,
-				 rxq_info->nrxq, lro));
+	ret = !(!alloc_uld_rxqs(adap, rxq_info, lro));
 
 	/* Tell uP to route control queue completions to rdma rspq */
 	if (adap->flags & FULL_INIT_DONE &&
-- 
2.1.0

^ permalink raw reply related

* Re: concurrent rhashtable test failure
From: Phil Sutter @ 2016-10-26  7:33 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Thomas Graf, Herbert Xu, netdev@vger.kernel.org, linux-m68k
In-Reply-To: <CAMuHMdWTqXaJAM-O+mmha=JbuyvvNxYyHuV6e4YK7oUkh9rCkA@mail.gmail.com>

Hi Geert,

On Mon, Oct 24, 2016 at 02:11:32PM +0200, Geert Uytterhoeven wrote:
> On m68k/ARAnyM, test_rhashtable fails with:
> 
>     Test failed: thread 0 returned: -4
> 
> (-4 = -EINTR)

How reproducible is this? I wonder why out of the ten threads only the
first one fails.

> I traced this back to your commit f4a3e90ba5739cfd ("rhashtable-test: extend
> to test concurrency"), which added that part of the test.
> 
> Diff of the test output between the failing commit and its parent:
> 
>  Running rhashtable test nelem=8, max_size=65536, shrinking=0
>  Test 00:
>    Adding 50000 keys
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Deleting 50000 keys
> -  Duration of test: 1029960000 ns
> +  Duration of test: 990000000 ns
>  Test 01:
>    Adding 50000 keys
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Deleting 50000 keys
> -  Duration of test: 990000000 ns
> +  Duration of test: 720000000 ns
>  Test 02:
>    Adding 50000 keys
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Deleting 50000 keys
> -  Duration of test: 1130000000 ns
> +  Duration of test: 700000000 ns
>  Test 03:
>    Adding 50000 keys
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Traversal complete: counted=50000, nelems=50000, entries=50000, table-jumps=0
>    Deleting 50000 keys
> -  Duration of test: 1080000000 ns
> -Average test time: 1057490000
> +  Duration of test: 700000000 ns
> +Average test time: 777500000
> +Testing concurrent rhashtable access from 10 threads
> +Test failed: thread 0 returned: -4
> +Started 10 threads, 1 failed
> 
> Do you have any clue?

Not really, I merely implemented the test.

Thanks, Phil

^ permalink raw reply

* Re: [PATCH (net.git) 0/3] stmmac: fix PTP support
From: Alexandre Torgue @ 2016-10-26  7:29 UTC (permalink / raw)
  To: Giuseppe Cavallaro, netdev
  Cc: rayagond, richardcochran, linux-kernel, seraphin.bonnaffe
In-Reply-To: <1477464964-5960-1-git-send-email-peppe.cavallaro@st.com>

Hi Peppe,


On 10/26/2016 08:56 AM, Giuseppe Cavallaro wrote:
> This subset of patches aim to fix the PTP support
> for the stmmac and especially for 4.x chip series.
> While setting PTP on an ST box with 4.00a Ethernet
> core, the kernel panics due to a broken settings
> of the descriptors. The patches review the
> register configuration, the algo used for configuring
> the protocol, the way to get the timestamp inside
> the RX/TX descriptors and, in the end, the statistics
> displayed by ethtool.
>
> Giuseppe Cavallaro (3):
>   stmmac: update the PTP header file
>   stmmac: fix PTP support for GMAC4
>   stmmac: fix PTP type ethtool stats
>
>  drivers/net/ethernet/stmicro/stmmac/common.h       | 24 +++---
>  drivers/net/ethernet/stmicro/stmmac/descs.h        | 20 +++--
>  drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 95 ++++++++++++++++-----
>  drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h |  4 +
>  drivers/net/ethernet/stmicro/stmmac/enh_desc.c     | 28 ++++---
>  drivers/net/ethernet/stmicro/stmmac/stmmac.h       |  1 +
>  .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   | 19 +++--
>  .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  | 43 ++++++++--
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 97 +++++++++++-----------
>  drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c   |  9 +-
>  drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h   | 72 ++++++++--------
>  11 files changed, 260 insertions(+), 152 deletions(-)
>

For the series:
Acked-by: Alexandre Torgue <alexandre.torgue@st.com>

Thanks
Alex

^ permalink raw reply

* Re: [RFC v4 02/18] bpf: Move u64_to_ptr() to BPF headers and inline it
From: Arnd Bergmann @ 2016-10-26  7:19 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-3-mic@digikod.net>

On Wednesday, October 26, 2016 8:56:38 AM CEST Mickaël Salaün wrote:
>  include/linux/bpf.h  | 6 ++++++
>  kernel/bpf/syscall.c | 6 ------
>  2 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index c201017b5730..cf87db6daf27 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -283,6 +283,12 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size)
>  
>  /* verify correctness of eBPF program */
>  int bpf_check(struct bpf_prog **fp, union bpf_attr *attr);
> +
> +/* helper to convert user pointers passed inside __aligned_u64 fields */
> +static inline void __user *u64_to_ptr(__u64 val)
> +{
> +       return (void __user *) (unsigned long) val;
> +}
>  #else
> 


We already have at least six copies of this helper:

fs/btrfs/qgroup.c:#define u64_to_ptr(x) ((struct btrfs_qgroup *)(uintptr_t)x)
kernel/bpf/syscall.c:static void __user *u64_to_ptr(__u64 val)
drivers/staging/android/ion/ion_test.c:#define u64_to_uptr(x) ((void __user *)(unsigned long)(x))
drivers/firewire/core-cdev.c:static void __user *u64_to_uptr(u64 value)
drivers/staging/android/ion/ion_test.c:#define u64_to_uptr(x) ((void __user *)(unsigned long)(x))
include/linux/kernel.h:#define u64_to_user_ptr(x) (            \

Just use the one in linux/kernel.h

	Arnd

^ permalink raw reply

* [PATCH (net.git) 2/3] stmmac: fix PTP support for GMAC4
From: Giuseppe Cavallaro @ 2016-10-26  6:56 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.torgue, rayagond, richardcochran, linux-kernel,
	seraphin.bonnaffe, Giuseppe Cavallaro
In-Reply-To: <1477464964-5960-1-git-send-email-peppe.cavallaro@st.com>

Due to bad management of the descriptors, when use ptp4l,
kernel panics as shown below:
-----------------------------------------------------------
 Unable to handle kernel NULL pointer dereference at virtual
 address 000001ac
 ...
 Internal error: Oops: 17 [#1] SMP ARM
 ...
 Hardware name: STi SoC with Flattened Device Tree
 task: c0c05e80 task.stack: c0c00000
 PC is at dwmac4_wrback_get_tx_timestamp_status+0x0/0xc
 LR is at stmmac_tx_clean+0x2f8/0x4d4
-----------------------------------------------------------

In case of GMAC4 the extended descriptor pointers were
used for getting the timestamp. These are NULL for this HW,
and the normal ones must be used.

The PTP also had problems on this chip due to the bad
register management and issues on the algo adopted to
setup the PTP and getting the timestamp values from the
descriptors.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre TORGUE <alexandre.torgue@st.com>
Cc: Rayagond Kokatanur <rayagond@vayavyalabs.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h       |  5 +-
 drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 68 ++++++++++++---
 drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h |  4 +
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |  1 +
 .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  | 43 ++++++++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 97 +++++++++++-----------
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c   |  9 +-
 7 files changed, 154 insertions(+), 73 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index d3292c4..6fc214c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -482,11 +482,12 @@ struct stmmac_ops {
 /* PTP and HW Timer helpers */
 struct stmmac_hwtimestamp {
 	void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
-	u32 (*config_sub_second_increment) (void __iomem *ioaddr, u32 clk_rate);
+	u32 (*config_sub_second_increment)(void __iomem *ioaddr, u32 ptp_clock,
+					   int gmac4);
 	int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
 	int (*config_addend) (void __iomem *ioaddr, u32 addend);
 	int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
-			       int add_sub);
+			       int add_sub, int gmac4);
 	 u64(*get_systime) (void __iomem *ioaddr);
 };
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index a1b17cd..2ef2f0c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -204,14 +204,18 @@ static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p)
 
 static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p)
 {
-	return (p->des3 & TDES3_TIMESTAMP_STATUS)
-		>> TDES3_TIMESTAMP_STATUS_SHIFT;
+	/* Context type from W/B descriptor must be zero */
+	if (p->des3 & TDES3_CONTEXT_TYPE)
+		return -EINVAL;
+
+	/* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
+	if (p->des3 & TDES3_TIMESTAMP_STATUS)
+		return 0;
+
+	return 1;
 }
 
-/*  NOTE: For RX CTX bit has to be checked before
- *  HAVE a specific function for TX and another one for RX
- */
-static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
+static inline u64 dwmac4_get_timestamp(void *desc, u32 ats)
 {
 	struct dma_desc *p = (struct dma_desc *)desc;
 	u64 ns;
@@ -223,12 +227,54 @@ static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
 	return ns;
 }
 
-static int dwmac4_context_get_rx_timestamp_status(void *desc, u32 ats)
+static int dwmac4_rx_check_timestamp(void *desc)
+{
+	struct dma_desc *p = (struct dma_desc *)desc;
+	u32 own, ctxt;
+	int ret = 1;
+
+	own = p->des3 & RDES3_OWN;
+	ctxt = ((p->des3 & RDES3_CONTEXT_DESCRIPTOR)
+		>> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
+
+	if (likely(!own && ctxt)) {
+		if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
+			/* Corrupted value */
+			ret = -EINVAL;
+		else
+			/* A valid Timestamp is ready to be read */
+			ret = 0;
+	}
+
+	/* Timestamp not ready */
+	return ret;
+}
+
+static int dwmac4_wrback_get_rx_timestamp_status(void *desc, u32 ats)
 {
 	struct dma_desc *p = (struct dma_desc *)desc;
+	int ret = -EINVAL;
+
+	/* Get the status from normal w/b descriptor */
+	if (likely(p->des3 & TDES3_RS1V)) {
+		if (likely(p->des1 & RDES1_TIMESTAMP_AVAILABLE)) {
+			int i = 0;
+
+			/* Check if timestamp is OK from context descriptor */
+			do {
+				ret = dwmac4_rx_check_timestamp(desc);
+				if (ret < 0)
+					goto exit;
+				i++;
 
-	return (p->des1 & RDES1_TIMESTAMP_AVAILABLE)
-		>> RDES1_TIMESTAMP_AVAILABLE_SHIFT;
+			} while ((ret == 1) || (i < 10));
+
+			if (i == 10)
+				ret = -EBUSY;
+		}
+	}
+exit:
+	return ret;
 }
 
 static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
@@ -373,8 +419,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
 	.get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
 	.enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
 	.get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,
-	.get_timestamp = dwmac4_wrback_get_timestamp,
-	.get_rx_timestamp_status = dwmac4_context_get_rx_timestamp_status,
+	.get_rx_timestamp_status = dwmac4_wrback_get_rx_timestamp_status,
+	.get_timestamp = dwmac4_get_timestamp,
 	.set_tx_ic = dwmac4_rd_set_tx_ic,
 	.prepare_tx_desc = dwmac4_rd_prepare_tx_desc,
 	.prepare_tso_tx_desc = dwmac4_rd_prepare_tso_tx_desc,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h
index 0902a2e..9736c50 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h
@@ -59,10 +59,13 @@
 #define TDES3_CTXT_TCMSSV		BIT(26)
 
 /* TDES3 Common */
+#define	TDES3_RS1V			BIT(26)
+#define	TDES3_RS1V_SHIFT		26
 #define TDES3_LAST_DESCRIPTOR		BIT(28)
 #define TDES3_LAST_DESCRIPTOR_SHIFT	28
 #define TDES3_FIRST_DESCRIPTOR		BIT(29)
 #define TDES3_CONTEXT_TYPE		BIT(30)
+#define	TDES3_CONTEXT_TYPE_SHIFT	30
 
 /* TDS3 use for both format (read and write back) */
 #define TDES3_OWN			BIT(31)
@@ -117,6 +120,7 @@
 #define RDES3_LAST_DESCRIPTOR		BIT(28)
 #define RDES3_FIRST_DESCRIPTOR		BIT(29)
 #define RDES3_CONTEXT_DESCRIPTOR	BIT(30)
+#define RDES3_CONTEXT_DESCRIPTOR_SHIFT	30
 
 /* RDES3 (read format) */
 #define RDES3_BUFFER1_VALID_ADDR	BIT(24)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index b15fc55..4d2a759 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -129,6 +129,7 @@ struct stmmac_priv {
 	int irq_wake;
 	spinlock_t ptp_lock;
 	void __iomem *mmcaddr;
+	void __iomem *ptpaddr;
 	u32 rx_tail_addr;
 	u32 tx_tail_addr;
 	u32 mss;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index a77f689..10d6059 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -34,21 +34,29 @@ static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
 }
 
 static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr,
-					      u32 ptp_clock)
+					      u32 ptp_clock, int gmac4)
 {
 	u32 value = readl(ioaddr + PTP_TCR);
 	unsigned long data;
 
-	/* Convert the ptp_clock to nano second
-	 * formula = (2/ptp_clock) * 1000000000
-	 * where, ptp_clock = 50MHz.
+	/* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second
+	 *	formula = (1/ptp_clock) * 1000000000
+	 * where ptp_clock is 50MHz if fine method is used to update system
 	 */
-	data = (2000000000ULL / ptp_clock);
+	if (value & PTP_TCR_TSCFUPDT)
+		data = (1000000000ULL / 50000000);
+	else
+		data = (1000000000ULL / ptp_clock);
 
 	/* 0.465ns accuracy */
 	if (!(value & PTP_TCR_TSCTRLSSR))
 		data = (data * 1000) / 465;
 
+	data &= PTP_SSIR_SSINC_MASK;
+
+	if (gmac4)
+		data = data << GMAC4_PTP_SSIR_SSINC_SHIFT;
+
 	writel(data, ioaddr + PTP_SSIR);
 
 	return data;
@@ -104,14 +112,30 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
 }
 
 static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
-				 int add_sub)
+				 int add_sub, int gmac4)
 {
 	u32 value;
 	int limit;
 
+	if (add_sub) {
+		/* If the new sec value needs to be subtracted with
+		 * the system time, then MAC_STSUR reg should be
+		 * programmed with (2^32 – <new_sec_value>)
+		 */
+		if (gmac4)
+			sec = (100000000ULL - sec);
+
+		value = readl(ioaddr + PTP_TCR);
+		if (value & PTP_TCR_TSCTRLSSR)
+			nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
+		else
+			nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
+	}
+
 	writel(sec, ioaddr + PTP_STSUR);
-	writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
-		ioaddr + PTP_STNSUR);
+	value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
+	writel(value, ioaddr + PTP_STNSUR);
+
 	/* issue command to initialize the system time value */
 	value = readl(ioaddr + PTP_TCR);
 	value |= PTP_TCR_TSUPDT;
@@ -134,8 +158,9 @@ static u64 stmmac_get_systime(void __iomem *ioaddr)
 {
 	u64 ns;
 
+	/* Get the TSSS value */
 	ns = readl(ioaddr + PTP_STNSR);
-	/* convert sec time value to nanosecond */
+	/* Get the TSS and convert sec time value to nanosecond */
 	ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
 
 	return ns;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 48e71fa..2e228d5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -340,18 +340,17 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
 /* stmmac_get_tx_hwtstamp - get HW TX timestamps
  * @priv: driver private structure
- * @entry : descriptor index to be used.
+ * @p : descriptor pointer
  * @skb : the socket buffer
  * Description :
  * This function will read timestamp from the descriptor & pass it to stack.
  * and also perform some sanity checks.
  */
 static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
-				   unsigned int entry, struct sk_buff *skb)
+				   struct dma_desc *p, struct sk_buff *skb)
 {
 	struct skb_shared_hwtstamps shhwtstamp;
 	u64 ns;
-	void *desc = NULL;
 
 	if (!priv->hwts_tx_en)
 		return;
@@ -360,58 +359,55 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
 	if (likely(!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
 		return;
 
-	if (priv->adv_ts)
-		desc = (priv->dma_etx + entry);
-	else
-		desc = (priv->dma_tx + entry);
-
 	/* check tx tstamp status */
-	if (!priv->hw->desc->get_tx_timestamp_status((struct dma_desc *)desc))
-		return;
+	if (!priv->hw->desc->get_tx_timestamp_status(p)) {
+		/* get the valid tstamp */
+		ns = priv->hw->desc->get_timestamp(p, priv->adv_ts);
 
-	/* get the valid tstamp */
-	ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
+		memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+		shhwtstamp.hwtstamp = ns_to_ktime(ns);
 
-	memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
-	shhwtstamp.hwtstamp = ns_to_ktime(ns);
-	/* pass tstamp to stack */
-	skb_tstamp_tx(skb, &shhwtstamp);
+		netdev_info(priv->dev, "get valid TX hw timestamp %llu\n", ns);
+		/* pass tstamp to stack */
+		skb_tstamp_tx(skb, &shhwtstamp);
+	}
 
 	return;
 }
 
 /* stmmac_get_rx_hwtstamp - get HW RX timestamps
  * @priv: driver private structure
- * @entry : descriptor index to be used.
+ * @p : descriptor pointer
+ * @np : next descriptor pointer
  * @skb : the socket buffer
  * Description :
  * This function will read received packet's timestamp from the descriptor
  * and pass it to stack. It also perform some sanity checks.
  */
-static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv,
-				   unsigned int entry, struct sk_buff *skb)
+static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
+				   struct dma_desc *np, struct sk_buff *skb)
 {
 	struct skb_shared_hwtstamps *shhwtstamp = NULL;
 	u64 ns;
-	void *desc = NULL;
 
 	if (!priv->hwts_rx_en)
 		return;
 
-	if (priv->adv_ts)
-		desc = (priv->dma_erx + entry);
-	else
-		desc = (priv->dma_rx + entry);
-
-	/* exit if rx tstamp is not valid */
-	if (!priv->hw->desc->get_rx_timestamp_status(desc, priv->adv_ts))
-		return;
+	/* Check if timestamp is available */
+	if (!priv->hw->desc->get_rx_timestamp_status(p, priv->adv_ts)) {
+		/* For GMAC4, the valid timestamp is from CTX next desc. */
+		if (priv->plat->has_gmac4)
+			ns = priv->hw->desc->get_timestamp(np, priv->adv_ts);
+		else
+			ns = priv->hw->desc->get_timestamp(p, priv->adv_ts);
 
-	/* get valid tstamp */
-	ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
-	shhwtstamp = skb_hwtstamps(skb);
-	memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
-	shhwtstamp->hwtstamp = ns_to_ktime(ns);
+		netdev_info(priv->dev, "get valid RX hw timestamp %llu\n", ns);
+		shhwtstamp = skb_hwtstamps(skb);
+		memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+		shhwtstamp->hwtstamp = ns_to_ktime(ns);
+	} else  {
+		netdev_err(priv->dev, "cannot get RX hw timestamp\n");
+	}
 }
 
 /**
@@ -598,17 +594,18 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
 	priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON;
 
 	if (!priv->hwts_tx_en && !priv->hwts_rx_en)
-		priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
+		priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, 0);
 	else {
 		value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR |
 			 tstamp_all | ptp_v2 | ptp_over_ethernet |
 			 ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
 			 ts_master_en | snap_type_sel);
-		priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value);
+		priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, value);
 
 		/* program Sub Second Increment reg */
 		sec_inc = priv->hw->ptp->config_sub_second_increment(
-			priv->ioaddr, priv->clk_ptp_rate);
+			priv->ptpaddr, priv->clk_ptp_rate,
+			priv->plat->has_gmac4);
 		temp = div_u64(1000000000ULL, sec_inc);
 
 		/* calculate default added value:
@@ -618,14 +615,14 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
 		 */
 		temp = (u64)(temp << 32);
 		priv->default_addend = div_u64(temp, priv->clk_ptp_rate);
-		priv->hw->ptp->config_addend(priv->ioaddr,
+		priv->hw->ptp->config_addend(priv->ptpaddr,
 					     priv->default_addend);
 
 		/* initialize system time */
 		ktime_get_real_ts64(&now);
 
 		/* lower 32 bits of tv_sec are safe until y2106 */
-		priv->hw->ptp->init_systime(priv->ioaddr, (u32)now.tv_sec,
+		priv->hw->ptp->init_systime(priv->ptpaddr, (u32)now.tv_sec,
 					    now.tv_nsec);
 	}
 
@@ -1333,7 +1330,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
 				priv->dev->stats.tx_packets++;
 				priv->xstats.tx_pkt_n++;
 			}
-			stmmac_get_tx_hwtstamp(priv, entry, skb);
+			stmmac_get_tx_hwtstamp(priv, p, skb);
 		}
 
 		if (likely(priv->tx_skbuff_dma[entry].buf)) {
@@ -1479,10 +1476,13 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
 	unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
 			    MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
 
-	if (priv->synopsys_id >= DWMAC_CORE_4_00)
+	if (priv->synopsys_id >= DWMAC_CORE_4_00) {
+		priv->ptpaddr = priv->ioaddr + PTP_GMAC4_OFFSET;
 		priv->mmcaddr = priv->ioaddr + MMC_GMAC4_OFFSET;
-	else
+	} else {
+		priv->ptpaddr = priv->ioaddr + PTP_GMAC3_X_OFFSET;
 		priv->mmcaddr = priv->ioaddr + MMC_GMAC3_X_OFFSET;
+	}
 
 	dwmac_mmc_intr_all_mask(priv->mmcaddr);
 
@@ -2477,7 +2477,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 	if (netif_msg_rx_status(priv)) {
 		void *rx_head;
 
-		pr_debug("%s: descriptor ring:\n", __func__);
+		pr_info(">>>>>> %s: descriptor ring:\n", __func__);
 		if (priv->extend_desc)
 			rx_head = (void *)priv->dma_erx;
 		else
@@ -2488,6 +2488,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 	while (count < limit) {
 		int status;
 		struct dma_desc *p;
+		struct dma_desc *np;
 
 		if (priv->extend_desc)
 			p = (struct dma_desc *)(priv->dma_erx + entry);
@@ -2507,9 +2508,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 		next_entry = priv->cur_rx;
 
 		if (priv->extend_desc)
-			prefetch(priv->dma_erx + next_entry);
+			np = (struct dma_desc *)(priv->dma_erx + next_entry);
 		else
-			prefetch(priv->dma_rx + next_entry);
+			np = priv->dma_rx + next_entry;
+
+		prefetch(np);
 
 		if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status))
 			priv->hw->desc->rx_extended_status(&priv->dev->stats,
@@ -2561,7 +2564,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 				frame_len -= ETH_FCS_LEN;
 
 			if (netif_msg_rx_status(priv)) {
-				pr_debug("\tdesc: %p [entry %d] buff=0x%x\n",
+				pr_info("\tdesc: %p [entry %d] buff=0x%x\n",
 					p, entry, des);
 				if (frame_len > ETH_FRAME_LEN)
 					pr_debug("\tframe size %d, COE: %d\n",
@@ -2618,13 +2621,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 						 DMA_FROM_DEVICE);
 			}
 
-			stmmac_get_rx_hwtstamp(priv, entry, skb);
-
 			if (netif_msg_pktdata(priv)) {
 				pr_debug("frame received (%dbytes)", frame_len);
 				print_pkt(skb->data, frame_len);
 			}
 
+			stmmac_get_rx_hwtstamp(priv, p, np, skb);
+
 			stmmac_rx_vlan(priv->dev, skb);
 
 			skb->protocol = eth_type_trans(skb, priv->dev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index 1477471..3eb281d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -54,7 +54,7 @@ static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
 
 	spin_lock_irqsave(&priv->ptp_lock, flags);
 
-	priv->hw->ptp->config_addend(priv->ioaddr, addend);
+	priv->hw->ptp->config_addend(priv->ptpaddr, addend);
 
 	spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
@@ -89,7 +89,8 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
 
 	spin_lock_irqsave(&priv->ptp_lock, flags);
 
-	priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
+	priv->hw->ptp->adjust_systime(priv->ptpaddr, sec, nsec, neg_adj,
+				      priv->plat->has_gmac4);
 
 	spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
@@ -114,7 +115,7 @@ static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts)
 
 	spin_lock_irqsave(&priv->ptp_lock, flags);
 
-	ns = priv->hw->ptp->get_systime(priv->ioaddr);
+	ns = priv->hw->ptp->get_systime(priv->ptpaddr);
 
 	spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
@@ -141,7 +142,7 @@ static int stmmac_set_time(struct ptp_clock_info *ptp,
 
 	spin_lock_irqsave(&priv->ptp_lock, flags);
 
-	priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
+	priv->hw->ptp->init_systime(priv->ptpaddr, ts->tv_sec, ts->tv_nsec);
 
 	spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH (net.git) 0/3] stmmac: fix PTP support
From: Giuseppe Cavallaro @ 2016-10-26  6:56 UTC (permalink / raw)
  To: netdev
  Cc: alexandre.torgue, rayagond, richardcochran, linux-kernel,
	seraphin.bonnaffe, Giuseppe Cavallaro

This subset of patches aim to fix the PTP support
for the stmmac and especially for 4.x chip series.
While setting PTP on an ST box with 4.00a Ethernet
core, the kernel panics due to a broken settings
of the descriptors. The patches review the
register configuration, the algo used for configuring
the protocol, the way to get the timestamp inside
the RX/TX descriptors and, in the end, the statistics
displayed by ethtool.

Giuseppe Cavallaro (3):
  stmmac: update the PTP header file
  stmmac: fix PTP support for GMAC4
  stmmac: fix PTP type ethtool stats

 drivers/net/ethernet/stmicro/stmmac/common.h       | 24 +++---
 drivers/net/ethernet/stmicro/stmmac/descs.h        | 20 +++--
 drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 95 ++++++++++++++++-----
 drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h |  4 +
 drivers/net/ethernet/stmicro/stmmac/enh_desc.c     | 28 ++++---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |  1 +
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   | 19 +++--
 .../net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c  | 43 ++++++++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 97 +++++++++++-----------
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c   |  9 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h   | 72 ++++++++--------
 11 files changed, 260 insertions(+), 152 deletions(-)

-- 
2.7.4

^ permalink raw reply

* Re: [PATCH net] bpf: fix samples to add fake KBUILD_MODNAME
From: Daniel Borkmann @ 2016-10-26  7:01 UTC (permalink / raw)
  To: Alexei Starovoitov; +Cc: davem, netdev
In-Reply-To: <20161026011713.GA35732@ast-mbp.thefacebook.com>

[-- Attachment #1: Type: text/plain, Size: 1884 bytes --]

On 10/26/2016 03:17 AM, Alexei Starovoitov wrote:
> On Wed, Oct 26, 2016 at 12:37:53AM +0200, Daniel Borkmann wrote:
>> Some of the sample files are causing issues when they are loaded with tc
>> and cls_bpf, meaning tc bails out while trying to parse the resulting ELF
>> file as program/map/etc sections are not present, which can be easily
>> spotted with readelf(1).
>>
>> Currently, BPF samples are including some of the kernel headers and mid
>> term we should change them to refrain from this, really. When dynamic
>> debugging is enabled, we bail out due to undeclared KBUILD_MODNAME, which
>> is easily overlooked in the build as clang spills this along with other
>> noisy warnings from various header includes, and llc still generates an
>> ELF file with mentioned characteristics. For just playing around with BPF
>> examples, this can be a bit of a hurdle to take.
>>
>> Just add a fake KBUILD_MODNAME as a band-aid to fix the issue, same is
>> done in xdp*_kern samples already.
>>
>> Fixes: 65d472fb007d ("samples/bpf: add 'pointer to packet' tests")
>> Fixes: 6afb1e28b859 ("samples/bpf: Add tunnel set/get tests.")
>> Fixes: a3f74617340b ("cgroup: bpf: Add an example to do cgroup checking in BPF")
>> Reported-by: Chandrasekar Kannan <ckannan@console.to>
>> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
>> ---
>>   samples/bpf/parse_ldabs.c        | 1 +
>>   samples/bpf/parse_simple.c       | 1 +
>>   samples/bpf/parse_varlen.c       | 1 +
>>   samples/bpf/tcbpf1_kern.c        | 1 +
>>   samples/bpf/tcbpf2_kern.c        | 1 +
>>   samples/bpf/test_cgrp2_tc_kern.c | 1 +
>>   6 files changed, 6 insertions(+)
>
> It's also needed for all of tracex*_kern.c, right?

Rest compiles just fine for me and readelf output looks good on all
tracex*_kern.o, too.

I see just warnings coming from various kernel header inclusions (see
log), but no errors anymore.

[-- Attachment #2: log --]
[-- Type: text/plain, Size: 19109 bytes --]

/home/darkstar/net/samples/bpf/trace_output_user.c:64:6: warning: no previous prototype for ‘perf_event_read’ [-Wmissing-prototypes]
 void perf_event_read(print_fn fn)
      ^
In file included from /home/darkstar/net/samples/bpf/sockex2_kern.c:8:
In file included from ./include/uapi/linux/if_tunnel.h:6:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/sockex2_kern.c:8:
In file included from ./include/uapi/linux/if_tunnel.h:6:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/sockex3_kern.c:14:
In file included from ./include/uapi/linux/if_tunnel.h:6:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/sockex3_kern.c:14:
In file included from ./include/uapi/linux/if_tunnel.h:6:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/tracex1_kern.c:7:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/tracex1_kern.c:7:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/tracex2_kern.c:7:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/tracex2_kern.c:7:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/tracex3_kern.c:7:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/tracex3_kern.c:7:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/tracex4_kern.c:7:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/tracex5_kern.c:7:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/tracex6_kern.c:1:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/test_probe_write_user_kern.c:7:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/test_probe_write_user_kern.c:7:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/trace_output_kern.c:1:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/tcbpf2_kern.c:18:
In file included from ./include/net/ipv6.h:16:
In file included from ./include/linux/ipv6.h:76:
In file included from ./include/linux/icmpv6.h:4:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/tcbpf2_kern.c:18:
In file included from ./include/net/ipv6.h:16:
In file included from ./include/linux/ipv6.h:76:
In file included from ./include/linux/icmpv6.h:4:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/lathist_kern.c:9:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/offwaketime_kern.c:12:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/spintest_kern.c:7:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/spintest_kern.c:7:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/map_perf_test_kern.c:7:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/map_perf_test_kern.c:7:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/test_overhead_kprobe_kern.c:8:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/parse_varlen.c:8:
In file included from ./include/linux/if_ether.h:23:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/parse_varlen.c:8:
In file included from ./include/linux/if_ether.h:23:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/parse_simple.c:8:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/parse_simple.c:8:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/parse_ldabs.c:8:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/parse_ldabs.c:8:
In file included from ./include/linux/ip.h:20:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/xdp1_kern.c:10:
In file included from ./include/linux/if_ether.h:23:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/xdp1_kern.c:10:
In file included from ./include/linux/if_ether.h:23:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/xdp2_kern.c:10:
In file included from ./include/linux/if_ether.h:23:
In file included from ./include/linux/skbuff.h:29:
In file included from ./include/linux/net.h:28:
./include/linux/fs.h:2693:9: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
        if (id < 0 || id >= READING_MAX_ID)
            ~~ ^ ~
In file included from /home/darkstar/net/samples/bpf/xdp2_kern.c:10:
In file included from ./include/linux/if_ether.h:23:
In file included from ./include/linux/skbuff.h:30:
In file included from ./include/linux/textsearch.h:8:
In file included from ./include/linux/slab.h:118:
In file included from ./include/linux/kasan.h:4:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
2 warnings generated.
In file included from /home/darkstar/net/samples/bpf/test_current_task_under_cgroup_kern.c:8:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/trace_event_kern.c:7:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.
In file included from /home/darkstar/net/samples/bpf/sampleip_kern.c:8:
In file included from ./include/linux/ptrace.h:5:
In file included from ./include/linux/sched.h:61:
./include/linux/cgroup-defs.h:322:16: warning: field 'cgrp' with variable sized type 'struct cgroup' not at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
        struct cgroup cgrp;
                      ^
1 warning generated.

^ permalink raw reply

* [RFC v4 15/18] bpf/cgroup: Move capability check
From: Mickaël Salaün @ 2016-10-26  6:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

This will be useful to be able to add more BPF attach type with
different capability checks.

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Daniel Mack <daniel@zonque.org>
---
 kernel/bpf/syscall.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index e62123aeb202..128acb4f7177 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -833,15 +833,15 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 	struct cgroup *cgrp;
 	int result;
 
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	if (CHECK_ATTR(BPF_PROG_ATTACH))
 		return -EINVAL;
 
 	switch (attr->attach_type) {
 	case BPF_CGROUP_INET_INGRESS:
 	case BPF_CGROUP_INET_EGRESS:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
 		prog = bpf_prog_get_type(attr->attach_bpf_fd,
 					 BPF_PROG_TYPE_CGROUP_SKB);
 		break;
@@ -872,15 +872,15 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 	struct cgroup *cgrp;
 	int result = 0;
 
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	if (CHECK_ATTR(BPF_PROG_DETACH))
 		return -EINVAL;
 
 	switch (attr->attach_type) {
 	case BPF_CGROUP_INET_INGRESS:
 	case BPF_CGROUP_INET_EGRESS:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
 		cgrp = cgroup_get_from_fd(attr->target_fd);
 		if (IS_ERR(cgrp))
 			return PTR_ERR(cgrp);
-- 
2.9.3

^ permalink raw reply related

* [RFC v4 18/18] samples/landlock: Add sandbox example
From: Mickaël Salaün @ 2016-10-26  6:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

Add a basic sandbox tool to create a process isolated from some part of
the system. This can depend of the current cgroup.

A sandbox process can stat the directories from the root up to the
allowed files. This then allow to stat ".." in an allowed directory.
Accessing to other sibling files (not parent of allowed files), are
denied with ENOENT to forbid file names discovery by bruteforcing.

Example with the current process hierarchy (seccomp):

  $ ls /home
  user1
  $ LANDLOCK_ALLOWED='/bin:/lib:/usr:/tmp:/proc/self/fd/0' \
      ./samples/landlock/sandbox /bin/sh -i
  Launching a new sandboxed process.
  $ ls /home
  ls: cannot access '/home': No such file or directory

Example with a cgroup:

  $ mkdir /sys/fs/cgroup/sandboxed
  $ ls /home
  user1
  $ LANDLOCK_CGROUPS='/sys/fs/cgroup/sandboxed' \
      LANDLOCK_ALLOWED='/bin:/lib:/usr:/tmp:/proc/self/fd/0' \
      ./samples/landlock/sandbox
  Ready to sandbox with cgroups.
  $ ls /home
  user1
  $ echo $$ > /sys/fs/cgroup/sandboxed/cgroup.procs
  $ ls /home
  ls: cannot access '/home': No such file or directory

Changes since v3:
* remove seccomp and origin field: completely free from seccomp programs
* handle more FS-related hooks
* handle inode hooks and directory traversal
* add faked but consistent view thanks to ENOENT
* add /lib64 in the example
* fix spelling
* rename some types and definitions (e.g. SECCOMP_ADD_LANDLOCK_RULE)

Changes since v2:
* use BPF_PROG_ATTACH for cgroup handling

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Serge E. Hallyn <serge@hallyn.com>
---
 samples/Makefile            |   2 +-
 samples/landlock/.gitignore |   1 +
 samples/landlock/Makefile   |  16 ++
 samples/landlock/sandbox.c  | 405 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 423 insertions(+), 1 deletion(-)
 create mode 100644 samples/landlock/.gitignore
 create mode 100644 samples/landlock/Makefile
 create mode 100644 samples/landlock/sandbox.c

diff --git a/samples/Makefile b/samples/Makefile
index e17d66d77f09..9f1b87bad1c0 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -2,4 +2,4 @@
 
 obj-$(CONFIG_SAMPLES)	+= kobject/ kprobes/ trace_events/ livepatch/ \
 			   hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
-			   configfs/ connector/ v4l/ trace_printk/ blackfin/
+			   configfs/ connector/ v4l/ trace_printk/ blackfin/ landlock/
diff --git a/samples/landlock/.gitignore b/samples/landlock/.gitignore
new file mode 100644
index 000000000000..f6c6da930a30
--- /dev/null
+++ b/samples/landlock/.gitignore
@@ -0,0 +1 @@
+/sandbox
diff --git a/samples/landlock/Makefile b/samples/landlock/Makefile
new file mode 100644
index 000000000000..d1044b2afd27
--- /dev/null
+++ b/samples/landlock/Makefile
@@ -0,0 +1,16 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+hostprogs-$(CONFIG_SECURITY_LANDLOCK) := sandbox
+sandbox-objs := sandbox.o
+
+always := $(hostprogs-y)
+
+HOSTCFLAGS += -I$(objtree)/usr/include
+
+# Trick to allow make to be run from this directory
+all:
+	$(MAKE) -C ../../ $$PWD/
+
+clean:
+	$(MAKE) -C ../../ M=$$PWD clean
diff --git a/samples/landlock/sandbox.c b/samples/landlock/sandbox.c
new file mode 100644
index 000000000000..9a36ebdf02d8
--- /dev/null
+++ b/samples/landlock/sandbox.c
@@ -0,0 +1,405 @@
+/*
+ * Landlock LSM - Sandbox example
+ *
+ * Copyright (C) 2016  Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3, as
+ * published by the Free Software Foundation.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h> /* open() */
+#include <linux/bpf.h>
+#include <linux/filter.h>
+#include <linux/prctl.h>
+#include <linux/seccomp.h>
+#include <linux/stat.h> /* S_IFDIR() */
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "../../tools/include/linux/filter.h"
+
+#include "../bpf/libbpf.c"
+
+#ifndef seccomp
+static int seccomp(unsigned int op, unsigned int flags, void *args)
+{
+	errno = 0;
+	return syscall(__NR_seccomp, op, flags, args);
+}
+#endif
+
+static int landlock_prog_load(const struct bpf_insn *insns, int prog_len,
+		enum landlock_hook hook, __u64 access)
+{
+	union bpf_attr attr = {
+		.prog_type = BPF_PROG_TYPE_LANDLOCK,
+		.insns = ptr_to_u64((void *) insns),
+		.insn_cnt = prog_len / sizeof(struct bpf_insn),
+		.license = ptr_to_u64((void *) "GPL"),
+		.log_buf = ptr_to_u64(bpf_log_buf),
+		.log_size = LOG_BUF_SIZE,
+		.log_level = 1,
+		.prog_subtype.landlock_rule = {
+			.hook = hook,
+			.access = access,
+		},
+	};
+
+	/* assign one field outside of struct init to make sure any
+	 * padding is zero initialized
+	 */
+	attr.kern_version = 0;
+
+	bpf_log_buf[0] = 0;
+
+	return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
+}
+
+#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
+#define MAX_ERRNO	4095
+#define MAY_EXEC	0x00000001
+
+struct landlock_rule {
+	enum landlock_hook hook;
+	struct bpf_insn *bpf;
+	size_t size;
+};
+
+static int apply_sandbox(const char **allowed_paths, int path_nb, const char
+		**cgroup_paths, int cgroup_nb)
+{
+	__u32 key;
+	int i, ret = 0, map_fs = -1;
+
+	/* set up the test sandbox */
+	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+		perror("prctl(no_new_priv)");
+		return 1;
+	}
+
+	if (path_nb) {
+		map_fs = bpf_create_map(BPF_MAP_TYPE_LANDLOCK_ARRAY,
+				sizeof(key), sizeof(struct landlock_handle),
+				10, 0);
+		if (map_fs < 0) {
+			fprintf(stderr, "bpf_create_map(fs): %s\n",
+					strerror(errno));
+			return 1;
+		}
+		for (key = 0; key < path_nb; key++) {
+			int fd = open(allowed_paths[key],
+					O_RDONLY | O_CLOEXEC);
+			if (fd < 0) {
+				fprintf(stderr, "open(fs: \"%s\"): %s\n",
+						allowed_paths[key],
+						strerror(errno));
+				return 1;
+			}
+			struct landlock_handle handle = {
+				.type = BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD,
+				.fd = (__u64)fd,
+			};
+
+			/* register a new LSM handle */
+			if (bpf_update_elem(map_fs, &key, &handle, BPF_ANY)) {
+				fprintf(stderr, "bpf_update_elem(fs: \"%s\"): %s\n",
+						allowed_paths[key],
+						strerror(errno));
+				close(fd);
+				return 1;
+			}
+			close(fd);
+		}
+	}
+
+	/* Landlock rule for file-based and path-based hooks */
+	struct bpf_insn hook_file[] = {
+		/* save context */
+		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+		/* specify an option, if any */
+		BPF_MOV32_IMM(BPF_REG_1, 0),
+		/* handles to compare with */
+		BPF_LD_MAP_FD(BPF_REG_2, map_fs),
+		BPF_MOV64_IMM(BPF_REG_3, BPF_MAP_ARRAY_OP_OR),
+		/* hook argument */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_6, offsetof(struct
+					landlock_data, args[0])),
+		/* checker function */
+		BPF_EMIT_CALL(BPF_FUNC_landlock_cmp_fs_beneath),
+		/* if the checked path is beneath the handle */
+		BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2),
+		BPF_MOV32_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN(),
+		/* allow anonymous mapping */
+		BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -ENOENT, 2),
+		BPF_MOV32_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN(),
+		/* deny by default, if any error */
+		BPF_MOV32_IMM(BPF_REG_0, EACCES),
+		BPF_EXIT_INSN(),
+	};
+
+	/* Landlock rule for inode-based hooks */
+	struct bpf_insn hook_inode[] = {
+		/* save context */
+		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+		/* specify an option, if any */
+		BPF_MOV32_IMM(BPF_REG_1, 0),
+		/* handles to compare with */
+		BPF_LD_MAP_FD(BPF_REG_2, map_fs),
+		BPF_MOV64_IMM(BPF_REG_3, BPF_MAP_ARRAY_OP_OR),
+		/* hook argument */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_6, offsetof(struct
+					landlock_data, args[0])),
+		/* checker function */
+		BPF_EMIT_CALL(BPF_FUNC_landlock_cmp_fs_beneath),
+		/* if the checked path is beneath the handle */
+		BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2),
+		BPF_MOV32_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN(),
+
+		/*
+		 * We must allow MAY_EXEC access on directories from the root to the
+		 * handles, otherwise they are not reachable.
+		 */
+
+		/* hook argument */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(struct
+					landlock_data, args[0])),
+		/* checker function */
+		BPF_EMIT_CALL(BPF_FUNC_landlock_get_fs_mode),
+		/* check if it returned an error */
+		BPF_MOV64_IMM(BPF_REG_7, 0),
+		BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, MAX_ERRNO),
+		BPF_JMP_REG(BPF_JGE, BPF_REG_0, BPF_REG_7, 2),
+		/* check if the inode is a directory */
+		BPF_ALU64_IMM(BPF_AND, BPF_REG_0, S_IFMT),
+		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, S_IFDIR, 2),
+		/* no entry by default, if any error */
+		BPF_MOV32_IMM(BPF_REG_0, ENOENT),
+		BPF_EXIT_INSN(),
+
+		/* specify an option, if any */
+		BPF_MOV32_IMM(BPF_REG_1, LANDLOCK_FLAG_OPT_REVERSE),
+		/* handles to compare with */
+		BPF_LD_MAP_FD(BPF_REG_2, map_fs),
+		BPF_MOV64_IMM(BPF_REG_3, BPF_MAP_ARRAY_OP_OR),
+		/* hook argument */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_6, offsetof(struct
+					landlock_data, args[0])),
+		/* checker function */
+		BPF_EMIT_CALL(BPF_FUNC_landlock_cmp_fs_beneath),
+		/* if one handle is not beneath the checked path */
+		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+		BPF_MOV32_IMM(BPF_REG_0, ENOENT),
+		BPF_EXIT_INSN(),
+
+		/* check access mask */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_6, offsetof(struct
+					landlock_data, args[1])),
+		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, MAY_EXEC, 2),
+		BPF_MOV32_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN(),
+		BPF_MOV32_IMM(BPF_REG_0, EACCES),
+		BPF_EXIT_INSN(),
+	};
+
+	/* Landlock rule for the stat hook */
+	struct bpf_insn hook_stat[] = {
+		/* save context */
+		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+		/* specify an option, if any */
+		BPF_MOV32_IMM(BPF_REG_1, 0),
+		/* handles to compare with */
+		BPF_LD_MAP_FD(BPF_REG_2, map_fs),
+		BPF_MOV64_IMM(BPF_REG_3, BPF_MAP_ARRAY_OP_OR),
+		/* hook argument */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_6, offsetof(struct
+					landlock_data, args[0])),
+		/* checker function */
+		BPF_EMIT_CALL(BPF_FUNC_landlock_cmp_fs_beneath),
+		/* if the checked path is beneath the handle */
+		BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2),
+		BPF_MOV32_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN(),
+
+		/*
+		 * We may want to allow discovery of the directories hierarchy
+		 * (from the root to the handles).
+		 */
+
+		/* hook argument */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(struct
+					landlock_data, args[0])),
+		/* checker function */
+		BPF_EMIT_CALL(BPF_FUNC_landlock_get_fs_mode),
+		/* check if it returned an error */
+		BPF_MOV64_IMM(BPF_REG_7, 0),
+		BPF_ALU64_IMM(BPF_SUB, BPF_REG_7, MAX_ERRNO),
+		BPF_JMP_REG(BPF_JGE, BPF_REG_0, BPF_REG_7, 2),
+		/* check if the inode is a directory */
+		BPF_ALU64_IMM(BPF_AND, BPF_REG_0, S_IFMT),
+		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, S_IFDIR, 2),
+		/* no entry by default, if any error */
+		BPF_MOV32_IMM(BPF_REG_0, ENOENT),
+		BPF_EXIT_INSN(),
+
+		/* specify an option, if any */
+		BPF_MOV32_IMM(BPF_REG_1, LANDLOCK_FLAG_OPT_REVERSE),
+		/* handles to compare with */
+		BPF_LD_MAP_FD(BPF_REG_2, map_fs),
+		BPF_MOV64_IMM(BPF_REG_3, BPF_MAP_ARRAY_OP_OR),
+		/* hook argument) */
+		BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_6, offsetof(struct
+					landlock_data, args[0])),
+		/* checker function */
+		BPF_EMIT_CALL(BPF_FUNC_landlock_cmp_fs_beneath),
+		/* if one handle is not beneath the checked path */
+		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+		BPF_MOV32_IMM(BPF_REG_0, ENOENT),
+		BPF_EXIT_INSN(),
+		BPF_MOV32_IMM(BPF_REG_0, 0),
+		BPF_EXIT_INSN(),
+	};
+
+	struct landlock_rule rules[] = {
+		{
+			.hook = LANDLOCK_HOOK_FILE_OPEN,
+			.bpf = hook_file,
+			.size = sizeof(hook_file),
+		},
+		{
+			.hook = LANDLOCK_HOOK_FILE_PERMISSION,
+			.bpf = hook_file,
+			.size = sizeof(hook_file),
+		},
+		{
+			.hook = LANDLOCK_HOOK_MMAP_FILE,
+			.bpf = hook_file,
+			.size = sizeof(hook_file),
+		},
+		{
+			.hook = LANDLOCK_HOOK_INODE_PERMISSION,
+			.bpf = hook_inode,
+			.size = sizeof(hook_inode),
+		},
+		{
+			.hook = LANDLOCK_HOOK_INODE_GETATTR,
+			.bpf = hook_stat,
+			.size = sizeof(hook_stat),
+		},
+	};
+	for (i = 0; i < ARRAY_SIZE(rules) && !ret; i++) {
+		int bpf0 = landlock_prog_load(rules[i].bpf, rules[i].size, rules[i].hook, 0);
+		if (bpf0 == -1) {
+			perror("prog_load");
+			fprintf(stderr, "%s", bpf_log_buf);
+			ret = 1;
+			break;
+		}
+		if (!cgroup_nb) {
+			if (seccomp(SECCOMP_ADD_LANDLOCK_RULE, 0, &bpf0)) {
+				perror("seccomp(set_hook)");
+				ret = 1;
+			}
+		} else {
+			for (key = 0; key < cgroup_nb && !ret; key++) {
+				int fd = open(cgroup_paths[key],
+						O_DIRECTORY | O_CLOEXEC);
+				if (fd < 0) {
+					fprintf(stderr, "open(cgroup: \"%s\"): %s\n",
+							cgroup_paths[key], strerror(errno));
+					ret = 1;
+					break;
+				}
+				if (bpf_prog_attach(bpf0, fd, BPF_CGROUP_LANDLOCK)) {
+					fprintf(stderr, "bpf_prog_attach(cgroup: \"%s\"): %s\n",
+							cgroup_paths[key], strerror(errno));
+					ret = 1;
+				}
+				close(fd);
+			}
+		}
+		close(bpf0);
+	}
+
+	if (path_nb) {
+		close(map_fs);
+	}
+	return ret;
+}
+
+#define ENV_FS_PATH_NAME "LANDLOCK_ALLOWED"
+#define ENV_CGROUP_PATH_NAME "LANDLOCK_CGROUPS"
+#define ENV_PATH_TOKEN ":"
+
+static int parse_path(char *env_path, const char ***path_list)
+{
+	int i, path_nb = 0;
+
+	if (env_path) {
+		path_nb++;
+		for (i = 0; env_path[i]; i++) {
+			if (env_path[i] == ENV_PATH_TOKEN[0]) {
+				path_nb++;
+			}
+		}
+	}
+	*path_list = malloc(path_nb * sizeof(**path_list));
+	for (i = 0; i < path_nb; i++) {
+		(*path_list)[i] = strsep(&env_path, ENV_PATH_TOKEN);
+	}
+
+	return path_nb;
+}
+
+int main(int argc, char * const argv[], char * const *envp)
+{
+	char *cmd_path;
+	char *env_path_allowed, *env_path_cgroup;
+	int path_nb, cgroup_nb;
+	const char **sb_paths = NULL;
+	const char **cg_paths = NULL;
+	char * const *cmd_argv;
+
+	env_path_allowed = getenv(ENV_FS_PATH_NAME);
+	if (env_path_allowed)
+		env_path_allowed = strdup(env_path_allowed);
+	env_path_cgroup = getenv(ENV_CGROUP_PATH_NAME);
+	if (env_path_cgroup)
+		env_path_cgroup = strdup(env_path_cgroup);
+
+	path_nb = parse_path(env_path_allowed, &sb_paths);
+	cgroup_nb = parse_path(env_path_cgroup, &cg_paths);
+	if (argc < 2 && !cgroup_nb) {
+		fprintf(stderr, "usage: %s <cmd> [args]...\n\n", argv[0]);
+		fprintf(stderr, "Environment variables containing paths, each separated by a colon:\n");
+		fprintf(stderr, "* %s (whitelist of allowed files and directories)\n",
+				ENV_FS_PATH_NAME);
+		fprintf(stderr, "* %s (optional cgroup paths for which the sandbox is enabled)\n",
+				ENV_CGROUP_PATH_NAME);
+		fprintf(stderr, "\nexample:\n%s='/bin:/lib:/lib64:/usr:/tmp:/proc/self/fd/0' %s /bin/sh -i\n",
+				ENV_FS_PATH_NAME, argv[0]);
+		return 1;
+	}
+	if (apply_sandbox(sb_paths, path_nb, cg_paths, cgroup_nb))
+		return 1;
+	if (!cgroup_nb) {
+		cmd_path = argv[1];
+		cmd_argv = argv + 1;
+		fprintf(stderr, "Launching a new sandboxed process.\n");
+		execve(cmd_path, cmd_argv, envp);
+		perror("execve");
+		return 1;
+	}
+	fprintf(stderr, "Ready to sandbox with cgroups.\n");
+	return 0;
+}
-- 
2.9.3


^ permalink raw reply related

* [RFC v4 17/18] landlock: Add update and debug access flags
From: Mickaël Salaün @ 2016-10-26  6:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

For now, the update and debug accesses are only accessible to a process
with CAP_SYS_ADMIN. This could change in the future.

The capability check is statically done when loading an eBPF program,
according to the current process. If the process has enough rights and
set the appropriate access flags, then the dedicated functions or data
will be accessible.

With the update access, the following functions are available:
* bpf_map_lookup_elem
* bpf_map_update_elem
* bpf_map_delete_elem
* bpf_tail_call

With the debug access, the following functions are available:
* bpf_trace_printk
* bpf_get_prandom_u32
* bpf_get_current_pid_tgid
* bpf_get_current_uid_gid
* bpf_get_current_comm

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: Kees Cook <keescook@chromium.org>
Cc: Sargun Dhillon <sargun@sargun.me>
---
 include/uapi/linux/bpf.h |  4 +++-
 security/landlock/lsm.c  | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 1d36f7d99288..013f661e27f8 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -607,7 +607,9 @@ enum landlock_hook {
 #define _LANDLOCK_HOOK_LAST LANDLOCK_HOOK_INODE_GETATTR
 
 /* eBPF context and functions allowed for a rule */
-#define _LANDLOCK_SUBTYPE_ACCESS_MASK		((1ULL << 0) - 1)
+#define LANDLOCK_SUBTYPE_ACCESS_UPDATE		(1 << 0)
+#define LANDLOCK_SUBTYPE_ACCESS_DEBUG		(1 << 1)
+#define _LANDLOCK_SUBTYPE_ACCESS_MASK		((1ULL << 2) - 1)
 
 /*
  * (future) options for a Landlock rule (e.g. run even if a previous rule
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index b5180aa7291f..1d924d2414f2 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -194,12 +194,57 @@ static int landlock_enforce(enum landlock_hook hook, __u64 args[6])
 static const struct bpf_func_proto *bpf_landlock_func_proto(
 		enum bpf_func_id func_id, union bpf_prog_subtype *prog_subtype)
 {
+	bool access_update = !!(prog_subtype->landlock_rule.access &
+			LANDLOCK_SUBTYPE_ACCESS_UPDATE);
+	bool access_debug = !!(prog_subtype->landlock_rule.access &
+			LANDLOCK_SUBTYPE_ACCESS_DEBUG);
+
 	switch (func_id) {
 	case BPF_FUNC_landlock_get_fs_mode:
 		return &bpf_landlock_get_fs_mode_proto;
 	case BPF_FUNC_landlock_cmp_fs_beneath:
 		return &bpf_landlock_cmp_fs_beneath_proto;
 
+	/* access_update */
+	case BPF_FUNC_map_lookup_elem:
+		if (access_update)
+			return &bpf_map_lookup_elem_proto;
+		return NULL;
+	case BPF_FUNC_map_update_elem:
+		if (access_update)
+			return &bpf_map_update_elem_proto;
+		return NULL;
+	case BPF_FUNC_map_delete_elem:
+		if (access_update)
+			return &bpf_map_delete_elem_proto;
+		return NULL;
+	case BPF_FUNC_tail_call:
+		if (access_update)
+			return &bpf_tail_call_proto;
+		return NULL;
+
+	/* access_debug */
+	case BPF_FUNC_trace_printk:
+		if (access_debug)
+			return bpf_get_trace_printk_proto();
+		return NULL;
+	case BPF_FUNC_get_prandom_u32:
+		if (access_debug)
+			return &bpf_get_prandom_u32_proto;
+		return NULL;
+	case BPF_FUNC_get_current_pid_tgid:
+		if (access_debug)
+			return &bpf_get_current_pid_tgid_proto;
+		return NULL;
+	case BPF_FUNC_get_current_uid_gid:
+		if (access_debug)
+			return &bpf_get_current_uid_gid_proto;
+		return NULL;
+	case BPF_FUNC_get_current_comm:
+		if (access_debug)
+			return &bpf_get_current_comm_proto;
+		return NULL;
+
 	default:
 		return NULL;
 	}
@@ -373,6 +418,14 @@ static inline bool bpf_landlock_is_valid_subtype(
 	if (prog_subtype->landlock_rule.option & ~_LANDLOCK_SUBTYPE_OPTION_MASK)
 		return false;
 
+	/* check access flags */
+	if (prog_subtype->landlock_rule.access & LANDLOCK_SUBTYPE_ACCESS_UPDATE &&
+			!capable(CAP_SYS_ADMIN))
+		return false;
+	if (prog_subtype->landlock_rule.access & LANDLOCK_SUBTYPE_ACCESS_DEBUG &&
+			!capable(CAP_SYS_ADMIN))
+		return false;
+
 	return true;
 }
 
-- 
2.9.3


^ permalink raw reply related

* [RFC v4 16/18] bpf/cgroup,landlock: Handle Landlock hooks per cgroup
From: Mickaël Salaün @ 2016-10-26  6:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

This allows to add new eBPF programs to Landlock hooks dedicated to a
cgroup thanks to the BPF_PROG_ATTACH command. The Landlock hooks
attached to a cgroup are propagated to the children cgroups. When a new
Landlock program is attached to one of this nested cgroup, this cgroup
hierarchy fork the Landlock hooks but will still get the updates from
its parents. This design is easy to deal with. The main difference with
the BPF_PROG_TYPE_CGROUP_SKB lie in the fact that Landlock rules can
only be stacked but not removed. This append-only behavior is consistent
through all the cgroup hierarchy.

A node references a rule list and an optional parent node. A node can be
updated on the fly by its owner to point to a new rule list. This is
useful to be able to atomically and consistently update an inherited
part of a chain of rules. This way, when a parent cgroup add a new
Landlock rule, all the child cgroups atomically update their rules to
include this new one. This is the behavior expected for hierarchy of
rules where the parent can enforce a rule on all its children at any
time.

Changes since v3:
* keep the Landlock rules consistent over all the cgroup hierarchy:
  update/insert new parent rules over all its children
* do not use an union of pointers but a struct (suggested by Kees Cook)
* internal renaming

Changes since v2:
* new design based on BPF_PROG_ATTACH (suggested by Alexei Starovoitov)

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Daniel Mack <daniel@zonque.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Kees Cook <keescook@chromium.org>
Cc: Tejun Heo <tj@kernel.org>
---
 include/linux/bpf-cgroup.h  |   7 +++
 include/linux/cgroup-defs.h |   2 +
 include/linux/landlock.h    |  12 +++++
 include/uapi/linux/bpf.h    |   1 +
 kernel/bpf/cgroup.c         | 117 ++++++++++++++++++++++++++++++++++++--------
 kernel/bpf/syscall.c        |  11 +++++
 security/landlock/lsm.c     |  34 ++++++++++++-
 security/landlock/manager.c |  63 ++++++++++++++++++++++++
 8 files changed, 226 insertions(+), 21 deletions(-)

diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index aab1aa91c064..1bf77c5a6895 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -14,8 +14,15 @@ struct sk_buff;
 extern struct static_key_false cgroup_bpf_enabled_key;
 #define cgroup_bpf_enabled static_branch_unlikely(&cgroup_bpf_enabled_key)
 
+#ifdef CONFIG_SECURITY_LANDLOCK
+struct landlock_hooks;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 struct bpf_object {
 	struct bpf_prog *prog;
+#ifdef CONFIG_SECURITY_LANDLOCK
+	struct landlock_hooks *hooks;
+#endif /* CONFIG_SECURITY_LANDLOCK */
 };
 
 struct cgroup_bpf {
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 861b4677fc5b..fe1023bf7b9d 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -301,8 +301,10 @@ struct cgroup {
 	/* used to schedule release agent */
 	struct work_struct release_agent_work;
 
+#ifdef CONFIG_CGROUP_BPF
 	/* used to store eBPF programs */
 	struct cgroup_bpf bpf;
+#endif /* CONFIG_CGROUP_BPF */
 
 	/* ids of the ancestors at each level including self */
 	int ancestor_ids[];
diff --git a/include/linux/landlock.h b/include/linux/landlock.h
index 72b4235d255f..eb2d5986c980 100644
--- a/include/linux/landlock.h
+++ b/include/linux/landlock.h
@@ -19,6 +19,10 @@
 #include <linux/seccomp.h> /* struct seccomp_filter */
 #endif /* CONFIG_SECCOMP_FILTER */
 
+#ifdef CONFIG_CGROUP_BPF
+#include <linux/cgroup-defs.h> /* struct cgroup */
+#endif /* CONFIG_CGROUP_BPF */
+
 struct landlock_rule;
 
 /**
@@ -73,11 +77,19 @@ struct landlock_hooks {
 };
 
 void put_landlock_hooks(struct landlock_hooks *hooks);
+void get_landlock_hooks(struct landlock_hooks *hooks);
 
 #ifdef CONFIG_SECCOMP_FILTER
 int landlock_seccomp_append_prog(unsigned int flags,
 		const char __user *user_bpf_fd);
 #endif /* CONFIG_SECCOMP_FILTER */
 
+#ifdef CONFIG_CGROUP_BPF
+struct landlock_hooks *landlock_cgroup_append_prog(struct cgroup *cgrp,
+		struct bpf_prog *prog);
+void landlock_insert_node(struct landlock_hooks *dst,
+		enum landlock_hook hook, struct landlock_hooks *src);
+#endif /* CONFIG_CGROUP_BPF */
+
 #endif /* CONFIG_SECURITY_LANDLOCK */
 #endif /* _LINUX_LANDLOCK_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 5f09eda3ab68..1d36f7d99288 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -124,6 +124,7 @@ enum bpf_prog_type {
 enum bpf_attach_type {
 	BPF_CGROUP_INET_INGRESS,
 	BPF_CGROUP_INET_EGRESS,
+	BPF_CGROUP_LANDLOCK,
 	__MAX_BPF_ATTACH_TYPE
 };
 
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 269b410d890c..c2417416abdf 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -15,6 +15,7 @@
 #include <linux/bpf.h>
 #include <linux/bpf-cgroup.h>
 #include <net/sock.h>
+#include <linux/landlock.h>
 
 DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key);
 EXPORT_SYMBOL(cgroup_bpf_enabled_key);
@@ -31,7 +32,15 @@ void cgroup_bpf_put(struct cgroup *cgrp)
 		struct bpf_object pinned = cgrp->bpf.pinned[type];
 
 		if (pinned.prog) {
-			bpf_prog_put(pinned.prog);
+			switch (type) {
+			case BPF_CGROUP_LANDLOCK:
+#ifdef CONFIG_SECURITY_LANDLOCK
+				put_landlock_hooks(pinned.hooks);
+				break;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+			default:
+				bpf_prog_put(pinned.prog);
+			}
 			static_branch_dec(&cgroup_bpf_enabled_key);
 		}
 	}
@@ -48,11 +57,30 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
 
 	for (type = 0; type < ARRAY_SIZE(cgrp->bpf.effective); type++) {
 		struct bpf_prog *prog;
-
-		prog = rcu_dereference_protected(
-				parent->bpf.effective[type].prog,
-				lockdep_is_held(&cgroup_mutex));
-		rcu_assign_pointer(cgrp->bpf.effective[type].prog, prog);
+#ifdef CONFIG_SECURITY_LANDLOCK
+		struct landlock_hooks *hooks;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
+		switch (type) {
+		case BPF_CGROUP_INET_INGRESS:
+		case BPF_CGROUP_INET_EGRESS:
+			prog = rcu_dereference_protected(
+					parent->bpf.effective[type].prog,
+					lockdep_is_held(&cgroup_mutex));
+			rcu_assign_pointer(cgrp->bpf.effective[type].prog, prog);
+			break;
+		case BPF_CGROUP_LANDLOCK:
+#ifdef CONFIG_SECURITY_LANDLOCK
+			hooks = rcu_dereference_protected(
+					parent->bpf.effective[type].hooks,
+					lockdep_is_held(&cgroup_mutex));
+			rcu_assign_pointer(cgrp->bpf.effective[type].hooks, hooks);
+			get_landlock_hooks(hooks);
+			break;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+		default:
+			WARN_ON(1);
+		}
 	}
 }
 
@@ -89,31 +117,80 @@ int __cgroup_bpf_update(struct cgroup *cgrp,
 			 enum bpf_attach_type type)
 {
 	struct bpf_prog *old_prog = NULL, *effective_prog;
+#ifdef CONFIG_SECURITY_LANDLOCK
+	struct landlock_hooks *effective_hooks;
+#endif /* CONFIG_SECURITY_LANDLOCK */
 	struct cgroup_subsys_state *pos;
-
-	old_prog = xchg(&cgrp->bpf.pinned[type].prog, prog);
-
-	effective_prog = (!prog && parent) ?
-		rcu_dereference_protected(parent->bpf.effective[type].prog,
-					  lockdep_is_held(&cgroup_mutex)) :
-		prog;
+	bool had_obj = false;
+
+	switch (type) {
+	case BPF_CGROUP_INET_INGRESS:
+	case BPF_CGROUP_INET_EGRESS:
+		old_prog = xchg(&cgrp->bpf.pinned[type].prog, prog);
+		if (old_prog)
+			had_obj = true;
+		effective_prog = (!prog && parent) ? rcu_dereference_protected(
+				parent->bpf.effective[type].prog,
+				lockdep_is_held(&cgroup_mutex)) : prog;
+		break;
+	case BPF_CGROUP_LANDLOCK:
+#ifdef CONFIG_SECURITY_LANDLOCK
+		/* append hook */
+		had_obj = !!rcu_dereference_protected(
+				cgrp->bpf.pinned[type].hooks,
+				lockdep_is_held(&cgroup_mutex));
+		effective_hooks = landlock_cgroup_append_prog(cgrp, prog);
+		if (IS_ERR(effective_hooks))
+			return PTR_ERR(effective_hooks);
+		break;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+	default:
+		return -EINVAL;
+	}
 
 	css_for_each_descendant_pre(pos, &cgrp->self) {
 		struct cgroup *desc = container_of(pos, struct cgroup, self);
 
-		/* skip the subtree if the descendant has its own program */
-		if (desc->bpf.pinned[type].prog && desc != cgrp)
-			pos = css_rightmost_descendant(pos);
-		else
+		switch (type) {
+		case BPF_CGROUP_INET_INGRESS:
+		case BPF_CGROUP_INET_EGRESS:
+			/*
+			 * skip the subtree if the descendant has its own
+			 * program
+			 */
+			if (desc->bpf.pinned[type].prog && desc != cgrp) {
+				pos = css_rightmost_descendant(pos);
+				break;
+			}
 			rcu_assign_pointer(desc->bpf.effective[type].prog,
 					   effective_prog);
+			break;
+		case BPF_CGROUP_LANDLOCK:
+#ifdef CONFIG_SECURITY_LANDLOCK
+			/*
+			 * extend the subtree hooks if the descendant has its
+			 * own hooks
+			 */
+			if (desc->bpf.pinned[type].hooks && desc != cgrp) {
+				landlock_insert_node(desc->bpf.pinned[type].hooks,
+						prog->subtype.landlock_rule.hook,
+						effective_hooks);
+				break;
+			}
+			rcu_assign_pointer(desc->bpf.effective[type].hooks,
+					effective_hooks);
+			break;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+		default:
+			WARN_ON(1);
+		}
 	}
 
 	if (prog)
 		static_branch_inc(&cgroup_bpf_enabled_key);
-
-	if (old_prog) {
-		bpf_prog_put(old_prog);
+	if (had_obj) {
+		if (old_prog)
+			bpf_prog_put(old_prog);
 		static_branch_dec(&cgroup_bpf_enabled_key);
 	}
 	return 0;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 128acb4f7177..8980b3218203 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -846,6 +846,16 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 					 BPF_PROG_TYPE_CGROUP_SKB);
 		break;
 
+	case BPF_CGROUP_LANDLOCK:
+#ifdef CONFIG_SECURITY_LANDLOCK
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		prog = bpf_prog_get_type(attr->attach_bpf_fd,
+				BPF_PROG_TYPE_LANDLOCK);
+		break;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 	default:
 		return -EINVAL;
 	}
@@ -889,6 +899,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 		cgroup_put(cgrp);
 		break;
 
+	case BPF_CGROUP_LANDLOCK:
 	default:
 		return -EINVAL;
 	}
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index 572f4f7f9f19..b5180aa7291f 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -9,6 +9,7 @@
  */
 
 #include <asm/current.h>
+#include <linux/bpf-cgroup.h> /* cgroup_bpf_enabled */
 #include <linux/bpf.h> /* enum bpf_reg_type, struct landlock_data */
 #include <linux/cred.h>
 #include <linux/err.h> /* MAX_ERRNO */
@@ -24,6 +25,10 @@
 #include <linux/fs.h> /* struct inode */
 #include <linux/path.h> /* struct path */
 
+#ifdef CONFIG_CGROUP_BPF
+#include <linux/cgroup-defs.h> /* struct cgroup */
+#endif /* CONFIG_CGROUP_BPF */
+
 #include "checker_fs.h"
 #include "common.h"
 
@@ -151,6 +156,9 @@ static u32 landlock_run_prog(u32 hook_idx, const struct landlock_data *ctx,
 static int landlock_enforce(enum landlock_hook hook, __u64 args[6])
 {
 	u32 ret = 0;
+#ifdef CONFIG_CGROUP_BPF
+	struct cgroup *cgrp;
+#endif /* CONFIG_CGROUP_BPF */
 	u32 hook_idx = get_index(hook);
 
 	struct landlock_data ctx = {
@@ -166,8 +174,20 @@ static int landlock_enforce(enum landlock_hook hook, __u64 args[6])
 #ifdef CONFIG_SECCOMP_FILTER
 	ret = landlock_run_prog(hook_idx, &ctx,
 			current->seccomp.landlock_hooks);
+	if (ret)
+		goto out;
 #endif /* CONFIG_SECCOMP_FILTER */
 
+#ifdef CONFIG_CGROUP_BPF
+	if (cgroup_bpf_enabled) {
+		/* get the default cgroup associated with the current thread */
+		cgrp = task_css_set(current)->dfl_cgrp;
+		ret = landlock_run_prog(hook_idx, &ctx,
+				cgrp->bpf.effective[BPF_CGROUP_LANDLOCK].hooks);
+	}
+#endif /* CONFIG_CGROUP_BPF */
+
+out:
 	return -ret;
 }
 
@@ -282,9 +302,21 @@ static struct security_hook_list landlock_hooks[] = {
 	LANDLOCK_HOOK_INIT(inode_getattr),
 };
 
+#ifdef CONFIG_SECCOMP_FILTER
+#ifdef CONFIG_CGROUP_BPF
+#define LANDLOCK_MANAGERS "seccomp and cgroups"
+#else /* CONFIG_CGROUP_BPF */
+#define LANDLOCK_MANAGERS "seccomp"
+#endif /* CONFIG_CGROUP_BPF */
+#elif define(CONFIG_CGROUP_BPF)
+#define LANDLOCK_MANAGERS "cgroups"
+#else
+#error "Need CONFIG_SECCOMP_FILTER or CONFIG_CGROUP_BPF"
+#endif /* CONFIG_SECCOMP_FILTER */
+
 void __init landlock_add_hooks(void)
 {
-	pr_info("landlock: Becoming ready to sandbox with seccomp\n");
+	pr_info("landlock: Becoming ready to sandbox with " LANDLOCK_MANAGERS "\n");
 	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks));
 }
 
diff --git a/security/landlock/manager.c b/security/landlock/manager.c
index 56e99ccd5708..18ae6c0c4dbf 100644
--- a/security/landlock/manager.c
+++ b/security/landlock/manager.c
@@ -20,6 +20,11 @@
 #include <linux/types.h> /* atomic_t */
 #include <linux/uaccess.h> /* copy_from_user() */
 
+#ifdef CONFIG_CGROUP_BPF
+#include <linux/bpf-cgroup.h> /* struct cgroup_bpf */
+#include <linux/cgroup-defs.h> /* struct cgroup */
+#endif /* CONFIG_CGROUP_BPF */
+
 #include "common.h"
 
 static void put_landlock_rule(struct landlock_rule *rule)
@@ -68,6 +73,12 @@ void put_landlock_hooks(struct landlock_hooks *hooks)
 	}
 }
 
+void get_landlock_hooks(struct landlock_hooks *hooks)
+{
+	if (hooks)
+		atomic_inc(&hooks->usage);
+}
+
 static struct landlock_hooks *new_raw_landlock_hooks(void)
 {
 	struct landlock_hooks *ret;
@@ -314,3 +325,55 @@ int landlock_seccomp_append_prog(unsigned int flags, const char __user *user_bpf
 	return 0;
 }
 #endif /* CONFIG_SECCOMP_FILTER */
+
+/**
+ * landlock_cgroup_set_hook - attach a Landlock program to a cgroup
+ *
+ * Must be called with cgroup_mutex held.
+ *
+ * @crgp: non-NULL cgroup pointer to attach to
+ * @prog: Landlock program pointer
+ */
+#ifdef CONFIG_CGROUP_BPF
+struct landlock_hooks *landlock_cgroup_append_prog(struct cgroup *cgrp,
+		struct bpf_prog *prog)
+{
+	if (!prog)
+		return ERR_PTR(-EINVAL);
+
+	/* copy the inherited hooks and append a new one */
+	return landlock_append_prog(cgrp->bpf.effective[BPF_CGROUP_LANDLOCK].hooks,
+			prog);
+}
+
+/**
+ * landlock_insert_node - insert a Landlock node in an existing hook
+ *
+ * This is useful to keep a consistent hierarchy tree whenever a branch add
+ * its one rules. However, this must be called at every new rule addition to
+ * keep it consistent.
+ *
+ * @dst: Landlock hooks to update. They must not have more than one
+ *       missing/desynchronized node to keep the same hierarchy than @src.
+ * @hook: hook to synchronize.
+ * @src: Landlock hooks reference.
+ */
+void landlock_insert_node(struct landlock_hooks *dst,
+		enum landlock_hook hook, struct landlock_hooks *src)
+{
+	struct landlock_node **walker;
+	u32 hook_idx = get_index(hook);
+
+	for (walker = &dst->nodes[hook_idx]; *walker;
+			walker = &(*walker)->prev) {
+		if (*walker == src->nodes[hook_idx])
+			return;
+		/* assume that the parent node was inherited */
+		if (*walker == src->nodes[hook_idx]->prev)
+			break;
+	}
+	atomic_inc(&src->nodes[hook_idx]->usage);
+	put_landlock_node(*walker);
+	smp_store_release(walker, src->nodes[hook_idx]);
+}
+#endif /* CONFIG_CGROUP_BPF */
-- 
2.9.3

^ permalink raw reply related

* [RFC v4 14/18] bpf/cgroup: Make cgroup_bpf_update() return an error code
From: Mickaël Salaün @ 2016-10-26  6:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

This will be useful to support Landlock for the next commits.

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Daniel Mack <daniel@zonque.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Tejun Heo <tj@kernel.org>
---
 include/linux/bpf-cgroup.h |  4 ++--
 kernel/bpf/cgroup.c        |  3 ++-
 kernel/bpf/syscall.c       | 10 ++++++----
 kernel/cgroup.c            |  6 ++++--
 4 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index 2f608e5d94e9..aab1aa91c064 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -31,13 +31,13 @@ struct cgroup_bpf {
 void cgroup_bpf_put(struct cgroup *cgrp);
 void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent);
 
-void __cgroup_bpf_update(struct cgroup *cgrp,
+int __cgroup_bpf_update(struct cgroup *cgrp,
 			 struct cgroup *parent,
 			 struct bpf_prog *prog,
 			 enum bpf_attach_type type);
 
 /* Wrapper for __cgroup_bpf_update() protected by cgroup_mutex */
-void cgroup_bpf_update(struct cgroup *cgrp,
+int cgroup_bpf_update(struct cgroup *cgrp,
 		       struct bpf_prog *prog,
 		       enum bpf_attach_type type);
 
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 75482cd92d56..269b410d890c 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -83,7 +83,7 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
  *
  * Must be called with cgroup_mutex held.
  */
-void __cgroup_bpf_update(struct cgroup *cgrp,
+int __cgroup_bpf_update(struct cgroup *cgrp,
 			 struct cgroup *parent,
 			 struct bpf_prog *prog,
 			 enum bpf_attach_type type)
@@ -116,6 +116,7 @@ void __cgroup_bpf_update(struct cgroup *cgrp,
 		bpf_prog_put(old_prog);
 		static_branch_dec(&cgroup_bpf_enabled_key);
 	}
+	return 0;
 }
 
 /**
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index ac4cbb98596d..e62123aeb202 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -831,6 +831,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 {
 	struct bpf_prog *prog;
 	struct cgroup *cgrp;
+	int result;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -858,10 +859,10 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 		return PTR_ERR(cgrp);
 	}
 
-	cgroup_bpf_update(cgrp, prog, attr->attach_type);
+	result = cgroup_bpf_update(cgrp, prog, attr->attach_type);
 	cgroup_put(cgrp);
 
-	return 0;
+	return result;
 }
 
 #define BPF_PROG_DETACH_LAST_FIELD attach_type
@@ -869,6 +870,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 static int bpf_prog_detach(const union bpf_attr *attr)
 {
 	struct cgroup *cgrp;
+	int result = 0;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -883,7 +885,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 		if (IS_ERR(cgrp))
 			return PTR_ERR(cgrp);
 
-		cgroup_bpf_update(cgrp, NULL, attr->attach_type);
+		result = cgroup_bpf_update(cgrp, NULL, attr->attach_type);
 		cgroup_put(cgrp);
 		break;
 
@@ -891,7 +893,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 		return -EINVAL;
 	}
 
-	return 0;
+	return result;
 }
 #endif /* CONFIG_CGROUP_BPF */
 
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 2ee9ec3051b2..f77a974eb960 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6501,15 +6501,17 @@ static __init int cgroup_namespaces_init(void)
 subsys_initcall(cgroup_namespaces_init);
 
 #ifdef CONFIG_CGROUP_BPF
-void cgroup_bpf_update(struct cgroup *cgrp,
+int cgroup_bpf_update(struct cgroup *cgrp,
 		       struct bpf_prog *prog,
 		       enum bpf_attach_type type)
 {
 	struct cgroup *parent = cgroup_parent(cgrp);
+	int result;
 
 	mutex_lock(&cgroup_mutex);
-	__cgroup_bpf_update(cgrp, parent, prog, type);
+	result = __cgroup_bpf_update(cgrp, parent, prog, type);
 	mutex_unlock(&cgroup_mutex);
+	return result;
 }
 #endif /* CONFIG_CGROUP_BPF */
 
-- 
2.9.3

^ permalink raw reply related

* [RFC v4 13/18] bpf/cgroup: Replace struct bpf_prog with struct bpf_object
From: Mickaël Salaün @ 2016-10-26  6:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

This allows CONFIG_CGROUP_BPF to manage different type of pointers
instead of only eBPF programs. This will be useful for the next commits
to support Landlock with cgroups.

Changes since v3:
* do not use an union of pointers but a struct (suggested by Kees Cook)

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Daniel Mack <daniel@zonque.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Tejun Heo <tj@kernel.org>
Link: https://lkml.kernel.org/r/CAGXu5j+F80XCPSVL0VxAAoTiYk5D1NKKC3jyAU=Z0Gi7L9S0aw@mail.gmail.com
---
 include/linux/bpf-cgroup.h |  8 ++++++--
 kernel/bpf/cgroup.c        | 35 ++++++++++++++++++-----------------
 2 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index fc076de74ab9..2f608e5d94e9 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -14,14 +14,18 @@ struct sk_buff;
 extern struct static_key_false cgroup_bpf_enabled_key;
 #define cgroup_bpf_enabled static_branch_unlikely(&cgroup_bpf_enabled_key)
 
+struct bpf_object {
+	struct bpf_prog *prog;
+};
+
 struct cgroup_bpf {
 	/*
 	 * Store two sets of bpf_prog pointers, one for programs that are
 	 * pinned directly to this cgroup, and one for those that are effective
 	 * when this cgroup is accessed.
 	 */
-	struct bpf_prog *prog[MAX_BPF_ATTACH_TYPE];
-	struct bpf_prog *effective[MAX_BPF_ATTACH_TYPE];
+	struct bpf_object pinned[MAX_BPF_ATTACH_TYPE];
+	struct bpf_object effective[MAX_BPF_ATTACH_TYPE];
 };
 
 void cgroup_bpf_put(struct cgroup *cgrp);
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index a0ab43f264b0..75482cd92d56 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -20,18 +20,18 @@ DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key);
 EXPORT_SYMBOL(cgroup_bpf_enabled_key);
 
 /**
- * cgroup_bpf_put() - put references of all bpf programs
+ * cgroup_bpf_put() - put references of all bpf objects
  * @cgrp: the cgroup to modify
  */
 void cgroup_bpf_put(struct cgroup *cgrp)
 {
 	unsigned int type;
 
-	for (type = 0; type < ARRAY_SIZE(cgrp->bpf.prog); type++) {
-		struct bpf_prog *prog = cgrp->bpf.prog[type];
+	for (type = 0; type < ARRAY_SIZE(cgrp->bpf.pinned); type++) {
+		struct bpf_object pinned = cgrp->bpf.pinned[type];
 
-		if (prog) {
-			bpf_prog_put(prog);
+		if (pinned.prog) {
+			bpf_prog_put(pinned.prog);
 			static_branch_dec(&cgroup_bpf_enabled_key);
 		}
 	}
@@ -47,11 +47,12 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
 	unsigned int type;
 
 	for (type = 0; type < ARRAY_SIZE(cgrp->bpf.effective); type++) {
-		struct bpf_prog *e;
+		struct bpf_prog *prog;
 
-		e = rcu_dereference_protected(parent->bpf.effective[type],
-					      lockdep_is_held(&cgroup_mutex));
-		rcu_assign_pointer(cgrp->bpf.effective[type], e);
+		prog = rcu_dereference_protected(
+				parent->bpf.effective[type].prog,
+				lockdep_is_held(&cgroup_mutex));
+		rcu_assign_pointer(cgrp->bpf.effective[type].prog, prog);
 	}
 }
 
@@ -87,13 +88,13 @@ void __cgroup_bpf_update(struct cgroup *cgrp,
 			 struct bpf_prog *prog,
 			 enum bpf_attach_type type)
 {
-	struct bpf_prog *old_prog, *effective;
+	struct bpf_prog *old_prog = NULL, *effective_prog;
 	struct cgroup_subsys_state *pos;
 
-	old_prog = xchg(cgrp->bpf.prog + type, prog);
+	old_prog = xchg(&cgrp->bpf.pinned[type].prog, prog);
 
-	effective = (!prog && parent) ?
-		rcu_dereference_protected(parent->bpf.effective[type],
+	effective_prog = (!prog && parent) ?
+		rcu_dereference_protected(parent->bpf.effective[type].prog,
 					  lockdep_is_held(&cgroup_mutex)) :
 		prog;
 
@@ -101,11 +102,11 @@ void __cgroup_bpf_update(struct cgroup *cgrp,
 		struct cgroup *desc = container_of(pos, struct cgroup, self);
 
 		/* skip the subtree if the descendant has its own program */
-		if (desc->bpf.prog[type] && desc != cgrp)
+		if (desc->bpf.pinned[type].prog && desc != cgrp)
 			pos = css_rightmost_descendant(pos);
 		else
-			rcu_assign_pointer(desc->bpf.effective[type],
-					   effective);
+			rcu_assign_pointer(desc->bpf.effective[type].prog,
+					   effective_prog);
 	}
 
 	if (prog)
@@ -151,7 +152,7 @@ int __cgroup_bpf_run_filter(struct sock *sk,
 
 	rcu_read_lock();
 
-	prog = rcu_dereference(cgrp->bpf.effective[type]);
+	prog = rcu_dereference(cgrp->bpf.effective[type].prog);
 	if (prog) {
 		unsigned int offset = skb->data - skb_network_header(skb);
 
-- 
2.9.3

^ permalink raw reply related

* [RFC v4 12/18] bpf: Cosmetic change for bpf_prog_attach()
From: Mickaël Salaün @ 2016-10-26  6:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Alexei Starovoitov, Andy Lutomirski,
	Daniel Borkmann, Daniel Mack, David Drysdale, David S . Miller,
	Eric W . Biederman, James Morris, Jann Horn, Kees Cook,
	Paul Moore, Sargun Dhillon, Serge E . Hallyn, Tejun Heo,
	Thomas Graf, Will Drewry, kernel-hardening, linux-api,
	linux-security-module, netdev, cgroups
In-Reply-To: <20161026065654.19166-1-mic@digikod.net>

Move code outside a switch/case to ease code factoring (cf. next
commit).

This apply on Daniel Mack's "Add eBPF hooks for cgroups" v7:
https://lkml.kernel.org/r/1477390454-12553-1-git-send-email-daniel@zonque.org

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Daniel Mack <daniel@zonque.org>
---
 kernel/bpf/syscall.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0f7faa9d2262..ac4cbb98596d 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -843,23 +843,24 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 	case BPF_CGROUP_INET_EGRESS:
 		prog = bpf_prog_get_type(attr->attach_bpf_fd,
 					 BPF_PROG_TYPE_CGROUP_SKB);
-		if (IS_ERR(prog))
-			return PTR_ERR(prog);
-
-		cgrp = cgroup_get_from_fd(attr->target_fd);
-		if (IS_ERR(cgrp)) {
-			bpf_prog_put(prog);
-			return PTR_ERR(cgrp);
-		}
-
-		cgroup_bpf_update(cgrp, prog, attr->attach_type);
-		cgroup_put(cgrp);
 		break;
 
 	default:
 		return -EINVAL;
 	}
 
+	if (IS_ERR(prog))
+		return PTR_ERR(prog);
+
+	cgrp = cgroup_get_from_fd(attr->target_fd);
+	if (IS_ERR(cgrp)) {
+		bpf_prog_put(prog);
+		return PTR_ERR(cgrp);
+	}
+
+	cgroup_bpf_update(cgrp, prog, attr->attach_type);
+	cgroup_put(cgrp);
+
 	return 0;
 }
 
-- 
2.9.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox