diff options
Diffstat (limited to 'kernel/bpf/sockmap.c')
-rw-r--r-- | kernel/bpf/sockmap.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 2b6eb35ae5d3..dbd7b322a86b 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -93,13 +93,27 @@ static inline struct smap_psock *smap_psock_sk(const struct sock *sk) | |||
93 | return rcu_dereference_sk_user_data(sk); | 93 | return rcu_dereference_sk_user_data(sk); |
94 | } | 94 | } |
95 | 95 | ||
96 | /* compute the linear packet data range [data, data_end) for skb when | ||
97 | * sk_skb type programs are in use. | ||
98 | */ | ||
99 | static inline void bpf_compute_data_end_sk_skb(struct sk_buff *skb) | ||
100 | { | ||
101 | TCP_SKB_CB(skb)->bpf.data_end = skb->data + skb_headlen(skb); | ||
102 | } | ||
103 | |||
104 | enum __sk_action { | ||
105 | __SK_DROP = 0, | ||
106 | __SK_PASS, | ||
107 | __SK_REDIRECT, | ||
108 | }; | ||
109 | |||
96 | static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) | 110 | static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) |
97 | { | 111 | { |
98 | struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); | 112 | struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); |
99 | int rc; | 113 | int rc; |
100 | 114 | ||
101 | if (unlikely(!prog)) | 115 | if (unlikely(!prog)) |
102 | return SK_DROP; | 116 | return __SK_DROP; |
103 | 117 | ||
104 | skb_orphan(skb); | 118 | skb_orphan(skb); |
105 | /* We need to ensure that BPF metadata for maps is also cleared | 119 | /* We need to ensure that BPF metadata for maps is also cleared |
@@ -108,13 +122,16 @@ static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) | |||
108 | */ | 122 | */ |
109 | TCP_SKB_CB(skb)->bpf.map = NULL; | 123 | TCP_SKB_CB(skb)->bpf.map = NULL; |
110 | skb->sk = psock->sock; | 124 | skb->sk = psock->sock; |
111 | bpf_compute_data_end(skb); | 125 | bpf_compute_data_end_sk_skb(skb); |
112 | preempt_disable(); | 126 | preempt_disable(); |
113 | rc = (*prog->bpf_func)(skb, prog->insnsi); | 127 | rc = (*prog->bpf_func)(skb, prog->insnsi); |
114 | preempt_enable(); | 128 | preempt_enable(); |
115 | skb->sk = NULL; | 129 | skb->sk = NULL; |
116 | 130 | ||
117 | return rc; | 131 | /* Moving return codes from UAPI namespace into internal namespace */ |
132 | return rc == SK_PASS ? | ||
133 | (TCP_SKB_CB(skb)->bpf.map ? __SK_REDIRECT : __SK_PASS) : | ||
134 | __SK_DROP; | ||
118 | } | 135 | } |
119 | 136 | ||
120 | static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) | 137 | static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) |
@@ -124,7 +141,7 @@ static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) | |||
124 | 141 | ||
125 | rc = smap_verdict_func(psock, skb); | 142 | rc = smap_verdict_func(psock, skb); |
126 | switch (rc) { | 143 | switch (rc) { |
127 | case SK_REDIRECT: | 144 | case __SK_REDIRECT: |
128 | sk = do_sk_redirect_map(skb); | 145 | sk = do_sk_redirect_map(skb); |
129 | if (likely(sk)) { | 146 | if (likely(sk)) { |
130 | struct smap_psock *peer = smap_psock_sk(sk); | 147 | struct smap_psock *peer = smap_psock_sk(sk); |
@@ -140,7 +157,7 @@ static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) | |||
140 | } | 157 | } |
141 | } | 158 | } |
142 | /* Fall through and free skb otherwise */ | 159 | /* Fall through and free skb otherwise */ |
143 | case SK_DROP: | 160 | case __SK_DROP: |
144 | default: | 161 | default: |
145 | kfree_skb(skb); | 162 | kfree_skb(skb); |
146 | } | 163 | } |
@@ -368,7 +385,7 @@ static int smap_parse_func_strparser(struct strparser *strp, | |||
368 | * any socket yet. | 385 | * any socket yet. |
369 | */ | 386 | */ |
370 | skb->sk = psock->sock; | 387 | skb->sk = psock->sock; |
371 | bpf_compute_data_end(skb); | 388 | bpf_compute_data_end_sk_skb(skb); |
372 | rc = (*prog->bpf_func)(skb, prog->insnsi); | 389 | rc = (*prog->bpf_func)(skb, prog->insnsi); |
373 | skb->sk = NULL; | 390 | skb->sk = NULL; |
374 | rcu_read_unlock(); | 391 | rcu_read_unlock(); |