summaryrefslogtreecommitdiffstats
path: root/kernel/bpf/sockmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/sockmap.c')
-rw-r--r--kernel/bpf/sockmap.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 86ec846f2d5e..eef843c3b419 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#define SOCK_CREATE_FLAG_MASK \ 44#define SOCK_CREATE_FLAG_MASK \
44 (BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY) 45 (BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)
@@ -104,9 +105,16 @@ static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb)
104 return SK_DROP; 105 return SK_DROP;
105 106
106 skb_orphan(skb); 107 skb_orphan(skb);
108 /* We need to ensure that BPF metadata for maps is also cleared
109 * when we orphan the skb so that we don't have the possibility
110 * to reference a stale map.
111 */
112 TCP_SKB_CB(skb)->bpf.map = NULL;
107 skb->sk = psock->sock; 113 skb->sk = psock->sock;
108 bpf_compute_data_pointers(skb); 114 bpf_compute_data_pointers(skb);
115 preempt_disable();
109 rc = (*prog->bpf_func)(skb, prog->insnsi); 116 rc = (*prog->bpf_func)(skb, prog->insnsi);
117 preempt_enable();
110 skb->sk = NULL; 118 skb->sk = NULL;
111 119
112 return rc; 120 return rc;
@@ -117,17 +125,10 @@ static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb)
117 struct sock *sk; 125 struct sock *sk;
118 int rc; 126 int rc;
119 127
120 /* Because we use per cpu values to feed input from sock redirect
121 * in BPF program to do_sk_redirect_map() call we need to ensure we
122 * are not preempted. RCU read lock is not sufficient in this case
123 * with CONFIG_PREEMPT_RCU enabled so we must be explicit here.
124 */
125 preempt_disable();
126 rc = smap_verdict_func(psock, skb); 128 rc = smap_verdict_func(psock, skb);
127 switch (rc) { 129 switch (rc) {
128 case SK_REDIRECT: 130 case SK_REDIRECT:
129 sk = do_sk_redirect_map(); 131 sk = do_sk_redirect_map(skb);
130 preempt_enable();
131 if (likely(sk)) { 132 if (likely(sk)) {
132 struct smap_psock *peer = smap_psock_sk(sk); 133 struct smap_psock *peer = smap_psock_sk(sk);
133 134
@@ -144,8 +145,6 @@ static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb)
144 /* Fall through and free skb otherwise */ 145 /* Fall through and free skb otherwise */
145 case SK_DROP: 146 case SK_DROP:
146 default: 147 default:
147 if (rc != SK_REDIRECT)
148 preempt_enable();
149 kfree_skb(skb); 148 kfree_skb(skb);
150 } 149 }
151} 150}
@@ -490,6 +489,9 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
490 int err = -EINVAL; 489 int err = -EINVAL;
491 u64 cost; 490 u64 cost;
492 491
492 if (!capable(CAP_NET_ADMIN))
493 return ERR_PTR(-EPERM);
494
493 /* check sanity of attributes */ 495 /* check sanity of attributes */
494 if (attr->max_entries == 0 || attr->key_size != 4 || 496 if (attr->max_entries == 0 || attr->key_size != 4 ||
495 attr->value_size != 4 || attr->map_flags & ~SOCK_CREATE_FLAG_MASK) 497 attr->value_size != 4 || attr->map_flags & ~SOCK_CREATE_FLAG_MASK)
@@ -843,6 +845,12 @@ static int sock_map_update_elem(struct bpf_map *map,
843 return -EINVAL; 845 return -EINVAL;
844 } 846 }
845 847
848 if (skops.sk->sk_type != SOCK_STREAM ||
849 skops.sk->sk_protocol != IPPROTO_TCP) {
850 fput(socket->file);
851 return -EOPNOTSUPP;
852 }
853
846 err = sock_map_ctx_update_elem(&skops, map, key, flags); 854 err = sock_map_ctx_update_elem(&skops, map, key, flags);
847 fput(socket->file); 855 fput(socket->file);
848 return err; 856 return err;