diff options
Diffstat (limited to 'kernel/bpf/sockmap.c')
-rw-r--r-- | kernel/bpf/sockmap.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 6424ce0e4969..2b6eb35ae5d3 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/workqueue.h> | 39 | #include <linux/workqueue.h> |
40 | #include <linux/list.h> | 40 | #include <linux/list.h> |
41 | #include <net/strparser.h> | 41 | #include <net/strparser.h> |
42 | #include <net/tcp.h> | ||
42 | 43 | ||
43 | struct bpf_stab { | 44 | struct bpf_stab { |
44 | struct bpf_map map; | 45 | struct bpf_map map; |
@@ -101,9 +102,16 @@ static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) | |||
101 | return SK_DROP; | 102 | return SK_DROP; |
102 | 103 | ||
103 | skb_orphan(skb); | 104 | skb_orphan(skb); |
105 | /* We need to ensure that BPF metadata for maps is also cleared | ||
106 | * when we orphan the skb so that we don't have the possibility | ||
107 | * to reference a stale map. | ||
108 | */ | ||
109 | TCP_SKB_CB(skb)->bpf.map = NULL; | ||
104 | skb->sk = psock->sock; | 110 | skb->sk = psock->sock; |
105 | bpf_compute_data_end(skb); | 111 | bpf_compute_data_end(skb); |
112 | preempt_disable(); | ||
106 | rc = (*prog->bpf_func)(skb, prog->insnsi); | 113 | rc = (*prog->bpf_func)(skb, prog->insnsi); |
114 | preempt_enable(); | ||
107 | skb->sk = NULL; | 115 | skb->sk = NULL; |
108 | 116 | ||
109 | return rc; | 117 | return rc; |
@@ -114,17 +122,10 @@ static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) | |||
114 | struct sock *sk; | 122 | struct sock *sk; |
115 | int rc; | 123 | int rc; |
116 | 124 | ||
117 | /* Because we use per cpu values to feed input from sock redirect | ||
118 | * in BPF program to do_sk_redirect_map() call we need to ensure we | ||
119 | * are not preempted. RCU read lock is not sufficient in this case | ||
120 | * with CONFIG_PREEMPT_RCU enabled so we must be explicit here. | ||
121 | */ | ||
122 | preempt_disable(); | ||
123 | rc = smap_verdict_func(psock, skb); | 125 | rc = smap_verdict_func(psock, skb); |
124 | switch (rc) { | 126 | switch (rc) { |
125 | case SK_REDIRECT: | 127 | case SK_REDIRECT: |
126 | sk = do_sk_redirect_map(); | 128 | sk = do_sk_redirect_map(skb); |
127 | preempt_enable(); | ||
128 | if (likely(sk)) { | 129 | if (likely(sk)) { |
129 | struct smap_psock *peer = smap_psock_sk(sk); | 130 | struct smap_psock *peer = smap_psock_sk(sk); |
130 | 131 | ||
@@ -141,8 +142,6 @@ static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) | |||
141 | /* Fall through and free skb otherwise */ | 142 | /* Fall through and free skb otherwise */ |
142 | case SK_DROP: | 143 | case SK_DROP: |
143 | default: | 144 | default: |
144 | if (rc != SK_REDIRECT) | ||
145 | preempt_enable(); | ||
146 | kfree_skb(skb); | 145 | kfree_skb(skb); |
147 | } | 146 | } |
148 | } | 147 | } |
@@ -487,6 +486,9 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) | |||
487 | int err = -EINVAL; | 486 | int err = -EINVAL; |
488 | u64 cost; | 487 | u64 cost; |
489 | 488 | ||
489 | if (!capable(CAP_NET_ADMIN)) | ||
490 | return ERR_PTR(-EPERM); | ||
491 | |||
490 | /* check sanity of attributes */ | 492 | /* check sanity of attributes */ |
491 | if (attr->max_entries == 0 || attr->key_size != 4 || | 493 | if (attr->max_entries == 0 || attr->key_size != 4 || |
492 | attr->value_size != 4 || attr->map_flags & ~BPF_F_NUMA_NODE) | 494 | attr->value_size != 4 || attr->map_flags & ~BPF_F_NUMA_NODE) |
@@ -840,6 +842,12 @@ static int sock_map_update_elem(struct bpf_map *map, | |||
840 | return -EINVAL; | 842 | return -EINVAL; |
841 | } | 843 | } |
842 | 844 | ||
845 | if (skops.sk->sk_type != SOCK_STREAM || | ||
846 | skops.sk->sk_protocol != IPPROTO_TCP) { | ||
847 | fput(socket->file); | ||
848 | return -EOPNOTSUPP; | ||
849 | } | ||
850 | |||
843 | err = sock_map_ctx_update_elem(&skops, map, key, flags); | 851 | err = sock_map_ctx_update_elem(&skops, map, key, flags); |
844 | fput(socket->file); | 852 | fput(socket->file); |
845 | return err; | 853 | return err; |