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

Showing the changes to include/linux (1 of 4 files). Show all

Unified · Split

include/linux/skmsg.h+14−14
@@ -14,6 +14,7 @@ · 13 unmodified lines
14#include <net/strparser.h>14#include <net/strparser.h>
15 15
16#define MAX_MSG_FRAGS MAX_SKB_FRAGS16#define MAX_MSG_FRAGS MAX_SKB_FRAGS
17#define NR_MSG_FRAG_IDS (MAX_MSG_FRAGS + 1)
17 18
18enum __sk_action {19enum __sk_action {
19 __SK_DROP = 0,20 __SK_DROP = 0,
@@ -29,13 +30,15 @@ struct sk_msg_sg { · 9 unmodified lines
29 u32 size;30 u32 size;
30 u32 copybreak;31 u32 copybreak;
31 unsigned long copy;32 unsigned long copy;
32 /* The extra element is used for chaining the front and sections when33 /* The extra two elements:
33 * the list becomes partitioned (e.g. end < start). The crypto APIs34 * 1) used for chaining the front and sections when the list becomes
34 * require the chaining.35 * partitioned (e.g. end < start). The crypto APIs require the
36 * chaining;
37 * 2) to chain tailer SG entries after the message.
35 */38 */
36 struct scatterlist data[MAX_MSG_FRAGS + 1];39 struct scatterlist data[MAX_MSG_FRAGS + 2];
37};40};
38static_assert(BITS_PER_LONG >= MAX_MSG_FRAGS);41static_assert(BITS_PER_LONG >= NR_MSG_FRAG_IDS);
39 42
40/* UAPI in filter.c depends on struct sk_msg_sg being first element. */43/* UAPI in filter.c depends on struct sk_msg_sg being first element. */
41struct sk_msg {44struct sk_msg {
@@ -142,13 +145,13 @@ static inline void sk_msg_apply_bytes(struct sk_psock *psock, u32 bytes) · 100 unmodified lines
142 145
143static inline u32 sk_msg_iter_dist(u32 start, u32 end)146static inline u32 sk_msg_iter_dist(u32 start, u32 end)
144{147{
145 return end >= start ? end - start : end + (MAX_MSG_FRAGS - start);148 return end >= start ? end - start : end + (NR_MSG_FRAG_IDS - start);
146}149}
147 150
148#define sk_msg_iter_var_prev(var) \151#define sk_msg_iter_var_prev(var) \
149 do { \152 do { \
150 if (var == 0) \153 if (var == 0) \
151 var = MAX_MSG_FRAGS - 1; \154 var = NR_MSG_FRAG_IDS - 1; \
152 else \155 else \
153 var--; \156 var--; \
154 } while (0)157 } while (0)
@@ -156,7 +159,7 @@ static inline u32 sk_msg_iter_dist(u32 start, u32 end) · 1 unmodified line
156#define sk_msg_iter_var_next(var) \159#define sk_msg_iter_var_next(var) \
157 do { \160 do { \
158 var++; \161 var++; \
159 if (var == MAX_MSG_FRAGS) \162 if (var == NR_MSG_FRAG_IDS) \
160 var = 0; \163 var = 0; \
161 } while (0)164 } while (0)
162 165
@@ -173,9 +176,9 @@ static inline void sk_msg_clear_meta(struct sk_msg *msg) · 10 unmodified lines
173 176
174static inline void sk_msg_init(struct sk_msg *msg)177static inline void sk_msg_init(struct sk_msg *msg)
175{178{
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);
177 memset(msg, 0, sizeof(*msg));180 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);
179}182}
180 183
181static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src,184static 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
196 199
197static inline bool sk_msg_full(const struct sk_msg *msg)200static inline bool sk_msg_full(const struct sk_msg *msg)
198{201{
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;
200}203}
201 204
202static inline u32 sk_msg_elem_used(const struct sk_msg *msg)205static inline u32 sk_msg_elem_used(const struct sk_msg *msg)
203{206{
204 if (sk_msg_full(msg))
205 return MAX_MSG_FRAGS;
206
207 return sk_msg_iter_dist(msg->sg.start, msg->sg.end);207 return sk_msg_iter_dist(msg->sg.start, msg->sg.end);
208}208}
209 209

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