History

net: skmsg: fix TLS 1.3 crash with full sk_msg

TLS 1.3 started using the entry at the end of the SG array for chaining-in the single byte content type entry. This mostly works: [ E E E E E E . . ] ^ ^ start end E < content type / [ E E E E E E C . ] ^ ^ start end (Where E denotes a populated SG entry; C denotes a chaining entry.) If the array is full, however, the end will point to the start: [ E E E E E E E E ] ^ start end And we end up overwriting the start: E < content type / [ C E E E E E E E ] ^ start end The sg array is supposed to be a circular buffer with start and end markers pointing anywhere. In case where start > end (i.e. the circular buffer has "wrapped") there is an extra entry reserved at the end to chain the two halves together. [ E E E E E E . . l ] (Where l is the reserved entry for "looping" back to front. As suggested by John, let's reserve another entry for chaining SG entries after the main circular buffer. Note that this entry has to be pointed to by the end entry so its position is not fixed. Examples of full messages: [ E E E E E E E E . l ] ^ ^ start end <---------------. [ E E . E E E E E E l ] ^ ^ end start Now the end will always point to an unused entry, so TLS 1.3 can always use it.

Jakub Kicinski committed 6 years ago

Commit 031097d1 parent d10523d4 files · +20 −20Browse files

Unified · Split

4 files
  1. include/linux/skmsg.h +14 −14
  2. net/core/filter.c +4 −4
  3. net/core/skmsg.c +1 −1
  4. net/ipv4/tcp_bpf.c +1 −1
include/linux/skmsg.h+14−14
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <net/strparser.h>
1515
1616 #define MAX_MSG_FRAGS MAX_SKB_FRAGS
17+#define NR_MSG_FRAG_IDS (MAX_MSG_FRAGS + 1)
1718
1819 enum __sk_action {
1920 __SK_DROP = 0,
@@ -29,13 +30,15 @@ struct sk_msg_sg { · 9 unmodified lines
2930 u32 size;
3031 u32 copybreak;
3132 unsigned long copy;
32− /* The extra element is used for chaining the front and sections when
33− * the list becomes partitioned (e.g. end < start). The crypto APIs
34− * require the chaining.
33+ /* The extra two elements:
34+ * 1) used for chaining the front and sections when the list becomes
35+ * partitioned (e.g. end < start). The crypto APIs require the
36+ * chaining;
37+ * 2) to chain tailer SG entries after the message.
3538 */
36− struct scatterlist data[MAX_MSG_FRAGS + 1];
39+ struct scatterlist data[MAX_MSG_FRAGS + 2];
3740 };
38−static_assert(BITS_PER_LONG >= MAX_MSG_FRAGS);
41+static_assert(BITS_PER_LONG >= NR_MSG_FRAG_IDS);
3942
4043 /* UAPI in filter.c depends on struct sk_msg_sg being first element. */
4144 struct sk_msg {
@@ -142,13 +145,13 @@ static inline void sk_msg_apply_bytes(struct sk_psock *psock, u32 bytes) · 100 unmodified lines
142145
143146 static inline u32 sk_msg_iter_dist(u32 start, u32 end)
144147 {
145− return end >= start ? end - start : end + (MAX_MSG_FRAGS - start);
148+ return end >= start ? end - start : end + (NR_MSG_FRAG_IDS - start);
146149 }
147150
148151 #define sk_msg_iter_var_prev(var) \
149152 do { \
150153 if (var == 0) \
151− var = MAX_MSG_FRAGS - 1; \
154+ var = NR_MSG_FRAG_IDS - 1; \
152155 else \
153156 var--; \
154157 } while (0)
@@ -156,7 +159,7 @@ static inline u32 sk_msg_iter_dist(u32 start, u32 end) · 1 unmodified line
156159 #define sk_msg_iter_var_next(var) \
157160 do { \
158161 var++; \
159− if (var == MAX_MSG_FRAGS) \
162+ if (var == NR_MSG_FRAG_IDS) \
160163 var = 0; \
161164 } while (0)
162165
@@ -173,9 +176,9 @@ static inline void sk_msg_clear_meta(struct sk_msg *msg) · 10 unmodified lines
173176
174177 static inline void sk_msg_init(struct sk_msg *msg)
175178 {
176− BUILD_BUG_ON(ARRAY_SIZE(msg->sg.data) - 1 != MAX_MSG_FRAGS);
179+ BUILD_BUG_ON(ARRAY_SIZE(msg->sg.data) - 1 != NR_MSG_FRAG_IDS);
177180 memset(msg, 0, sizeof(*msg));
178− sg_init_marker(msg->sg.data, MAX_MSG_FRAGS);
181+ sg_init_marker(msg->sg.data, NR_MSG_FRAG_IDS);
179182 }
180183
181184 static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src,
@@ -196,14 +199,11 @@ static inline void sk_msg_xfer_full(struct sk_msg *dst, struct sk_msg *src) · 14 unmodified lines
196199
197200 static inline bool sk_msg_full(const struct sk_msg *msg)
198201 {
199− return (msg->sg.end == msg->sg.start) && msg->sg.size;
202+ return sk_msg_iter_dist(msg->sg.start, msg->sg.end) == MAX_MSG_FRAGS;
200203 }
201204
202205 static inline u32 sk_msg_elem_used(const struct sk_msg *msg)
203206 {
204− if (sk_msg_full(msg))
205− return MAX_MSG_FRAGS;
206−
207207 return sk_msg_iter_dist(msg->sg.start, msg->sg.end);
208208 }
209209
net/core/filter.c+4−4
@@ -2299,7 +2299,7 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start, · 2298 unmodified lines
22992299 WARN_ON_ONCE(last_sge == first_sge);
23002300 shift = last_sge > first_sge ?
23012301 last_sge - first_sge - 1 :
2302− MAX_SKB_FRAGS - first_sge + last_sge - 1;
2302+ NR_MSG_FRAG_IDS - first_sge + last_sge - 1;
23032303 if (!shift)
23042304 goto out;
23052305
@@ -2308,8 +2308,8 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start, · 2 unmodified lines
23082308 do {
23092309 u32 move_from;
23102310
2311− if (i + shift >= MAX_MSG_FRAGS)
2312− move_from = i + shift - MAX_MSG_FRAGS;
2311+ if (i + shift >= NR_MSG_FRAG_IDS)
2312+ move_from = i + shift - NR_MSG_FRAG_IDS;
23132313 else
23142314 move_from = i + shift;
23152315 if (move_from == msg->sg.end)
@@ -2323,7 +2323,7 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start, · 7 unmodified lines
23232323 } while (1);
23242324
23252325 msg->sg.end = msg->sg.end - shift > msg->sg.end ?
2326− msg->sg.end - shift + MAX_MSG_FRAGS :
2326+ msg->sg.end - shift + NR_MSG_FRAG_IDS :
23272327 msg->sg.end - shift;
23282328 out:
23292329 msg->data = sg_virt(&msg->sg.data[first_sge]) + start - offset;
net/core/skmsg.c+1−1
@@ -421,7 +421,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb) · 420 unmodified lines
421421 copied = skb->len;
422422 msg->sg.start = 0;
423423 msg->sg.size = copied;
424− msg->sg.end = num_sge == MAX_MSG_FRAGS ? 0 : num_sge;
424+ msg->sg.end = num_sge;
425425 msg->skb = skb;
426426
427427 sk_psock_queue_msg(psock, msg);
net/ipv4/tcp_bpf.c+1−1
@@ -301,7 +301,7 @@ EXPORT_SYMBOL_GPL(tcp_bpf_sendmsg_redir); · 300 unmodified lines
301301 static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
302302 struct sk_msg *msg, int *copied, int flags)
303303 {
304− bool cork = false, enospc = msg->sg.start == msg->sg.end;
304+ bool cork = false, enospc = sk_msg_full(msg);
305305 struct sock *sk_redir;
306306 u32 tosend, delta = 0;
307307 int ret;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t