Skip to content

Commit d618d09

Browse files
Jon Maloydavem330
authored andcommitted
tipc: enforce valid ratio between skb truesize and contents
The socket level flow control is based on the assumption that incoming buffers meet the condition (skb->truesize / roundup(skb->len) <= 4), where the latter value is rounded off upwards to the nearest 1k number. This does empirically hold true for the device drivers we know, but we cannot trust that it will always be so, e.g., in a system with jumbo frames and very small packets. We now introduce a check for this condition at packet arrival, and if we find it to be false, we copy the packet to a new, smaller buffer, where the condition will be true. We expect this to affect only a small fraction of all incoming packets, if at all. Acked-by: Ying Xue <[email protected]> Signed-off-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8252fce commit d618d09

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

net/tipc/msg.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
174174

175175
if (fragid == LAST_FRAGMENT) {
176176
TIPC_SKB_CB(head)->validated = false;
177-
if (unlikely(!tipc_msg_validate(head)))
177+
if (unlikely(!tipc_msg_validate(&head)))
178178
goto err;
179179
*buf = head;
180180
TIPC_SKB_CB(head)->tail = NULL;
@@ -201,11 +201,21 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
201201
* TIPC will ignore the excess, under the assumption that it is optional info
202202
* introduced by a later release of the protocol.
203203
*/
204-
bool tipc_msg_validate(struct sk_buff *skb)
204+
bool tipc_msg_validate(struct sk_buff **_skb)
205205
{
206-
struct tipc_msg *msg;
206+
struct sk_buff *skb = *_skb;
207+
struct tipc_msg *hdr;
207208
int msz, hsz;
208209

210+
/* Ensure that flow control ratio condition is satisfied */
211+
if (unlikely(skb->truesize / buf_roundup_len(skb) > 4)) {
212+
skb = skb_copy(skb, GFP_ATOMIC);
213+
if (!skb)
214+
return false;
215+
kfree_skb(*_skb);
216+
*_skb = skb;
217+
}
218+
209219
if (unlikely(TIPC_SKB_CB(skb)->validated))
210220
return true;
211221
if (unlikely(!pskb_may_pull(skb, MIN_H_SIZE)))
@@ -217,11 +227,11 @@ bool tipc_msg_validate(struct sk_buff *skb)
217227
if (unlikely(!pskb_may_pull(skb, hsz)))
218228
return false;
219229

220-
msg = buf_msg(skb);
221-
if (unlikely(msg_version(msg) != TIPC_VERSION))
230+
hdr = buf_msg(skb);
231+
if (unlikely(msg_version(hdr) != TIPC_VERSION))
222232
return false;
223233

224-
msz = msg_size(msg);
234+
msz = msg_size(hdr);
225235
if (unlikely(msz < hsz))
226236
return false;
227237
if (unlikely((msz - hsz) > TIPC_MAX_USER_MSG_SIZE))
@@ -411,7 +421,7 @@ bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos)
411421
skb_pull(*iskb, offset);
412422
imsz = msg_size(buf_msg(*iskb));
413423
skb_trim(*iskb, imsz);
414-
if (unlikely(!tipc_msg_validate(*iskb)))
424+
if (unlikely(!tipc_msg_validate(iskb)))
415425
goto none;
416426
*pos += align(imsz);
417427
return true;

net/tipc/msg.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ static inline bool msg_is_reset(struct tipc_msg *hdr)
926926
}
927927

928928
struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp);
929-
bool tipc_msg_validate(struct sk_buff *skb);
929+
bool tipc_msg_validate(struct sk_buff **_skb);
930930
bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);
931931
void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
932932
struct sk_buff_head *xmitq);
@@ -954,6 +954,11 @@ static inline u16 buf_seqno(struct sk_buff *skb)
954954
return msg_seqno(buf_msg(skb));
955955
}
956956

957+
static inline int buf_roundup_len(struct sk_buff *skb)
958+
{
959+
return (skb->len / 1024 + 1) * 1024;
960+
}
961+
957962
/* tipc_skb_peek(): peek and reserve first buffer in list
958963
* @list: list to be peeked in
959964
* Returns pointer to first buffer in list, if any

net/tipc/node.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1539,7 +1539,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)
15391539
__skb_queue_head_init(&xmitq);
15401540

15411541
/* Ensure message is well-formed before touching the header */
1542-
if (unlikely(!tipc_msg_validate(skb)))
1542+
if (unlikely(!tipc_msg_validate(&skb)))
15431543
goto discard;
15441544
hdr = buf_msg(skb);
15451545
usr = msg_user(hdr);

0 commit comments

Comments
 (0)