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 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; |