diff options
-rw-r--r-- | net/tipc/msg.c | 24 | ||||
-rw-r--r-- | net/tipc/msg.h | 7 | ||||
-rw-r--r-- | net/tipc/node.c | 2 |
3 files changed, 24 insertions, 9 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 1649d456e22d..b0d07b35909d 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
@@ -174,7 +174,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | |||
174 | 174 | ||
175 | if (fragid == LAST_FRAGMENT) { | 175 | if (fragid == LAST_FRAGMENT) { |
176 | TIPC_SKB_CB(head)->validated = false; | 176 | TIPC_SKB_CB(head)->validated = false; |
177 | if (unlikely(!tipc_msg_validate(head))) | 177 | if (unlikely(!tipc_msg_validate(&head))) |
178 | goto err; | 178 | goto err; |
179 | *buf = head; | 179 | *buf = head; |
180 | TIPC_SKB_CB(head)->tail = NULL; | 180 | TIPC_SKB_CB(head)->tail = NULL; |
@@ -201,11 +201,21 @@ err: | |||
201 | * TIPC will ignore the excess, under the assumption that it is optional info | 201 | * TIPC will ignore the excess, under the assumption that it is optional info |
202 | * introduced by a later release of the protocol. | 202 | * introduced by a later release of the protocol. |
203 | */ | 203 | */ |
204 | bool tipc_msg_validate(struct sk_buff *skb) | 204 | bool tipc_msg_validate(struct sk_buff **_skb) |
205 | { | 205 | { |
206 | struct tipc_msg *msg; | 206 | struct sk_buff *skb = *_skb; |
207 | struct tipc_msg *hdr; | ||
207 | int msz, hsz; | 208 | int msz, hsz; |
208 | 209 | ||
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 | |||
209 | if (unlikely(TIPC_SKB_CB(skb)->validated)) | 219 | if (unlikely(TIPC_SKB_CB(skb)->validated)) |
210 | return true; | 220 | return true; |
211 | if (unlikely(!pskb_may_pull(skb, MIN_H_SIZE))) | 221 | if (unlikely(!pskb_may_pull(skb, MIN_H_SIZE))) |
@@ -217,11 +227,11 @@ bool tipc_msg_validate(struct sk_buff *skb) | |||
217 | if (unlikely(!pskb_may_pull(skb, hsz))) | 227 | if (unlikely(!pskb_may_pull(skb, hsz))) |
218 | return false; | 228 | return false; |
219 | 229 | ||
220 | msg = buf_msg(skb); | 230 | hdr = buf_msg(skb); |
221 | if (unlikely(msg_version(msg) != TIPC_VERSION)) | 231 | if (unlikely(msg_version(hdr) != TIPC_VERSION)) |
222 | return false; | 232 | return false; |
223 | 233 | ||
224 | msz = msg_size(msg); | 234 | msz = msg_size(hdr); |
225 | if (unlikely(msz < hsz)) | 235 | if (unlikely(msz < hsz)) |
226 | return false; | 236 | return false; |
227 | if (unlikely((msz - hsz) > TIPC_MAX_USER_MSG_SIZE)) | 237 | 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) | |||
411 | skb_pull(*iskb, offset); | 421 | skb_pull(*iskb, offset); |
412 | imsz = msg_size(buf_msg(*iskb)); | 422 | imsz = msg_size(buf_msg(*iskb)); |
413 | skb_trim(*iskb, imsz); | 423 | skb_trim(*iskb, imsz); |
414 | if (unlikely(!tipc_msg_validate(*iskb))) | 424 | if (unlikely(!tipc_msg_validate(iskb))) |
415 | goto none; | 425 | goto none; |
416 | *pos += align(imsz); | 426 | *pos += align(imsz); |
417 | return true; | 427 | return true; |
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index bf8f57ccc70c..3e4384c222f7 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
@@ -926,7 +926,7 @@ static inline bool msg_is_reset(struct tipc_msg *hdr) | |||
926 | } | 926 | } |
927 | 927 | ||
928 | struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp); | 928 | 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); |
930 | bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); | 930 | bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); |
931 | void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb, | 931 | void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb, |
932 | struct sk_buff_head *xmitq); | 932 | struct sk_buff_head *xmitq); |
@@ -954,6 +954,11 @@ static inline u16 buf_seqno(struct sk_buff *skb) | |||
954 | return msg_seqno(buf_msg(skb)); | 954 | return msg_seqno(buf_msg(skb)); |
955 | } | 955 | } |
956 | 956 | ||
957 | static inline int buf_roundup_len(struct sk_buff *skb) | ||
958 | { | ||
959 | return (skb->len / 1024 + 1) * 1024; | ||
960 | } | ||
961 | |||
957 | /* tipc_skb_peek(): peek and reserve first buffer in list | 962 | /* tipc_skb_peek(): peek and reserve first buffer in list |
958 | * @list: list to be peeked in | 963 | * @list: list to be peeked in |
959 | * Returns pointer to first buffer in list, if any | 964 | * Returns pointer to first buffer in list, if any |
diff --git a/net/tipc/node.c b/net/tipc/node.c index 009a81631280..507017fe0f1b 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
@@ -1539,7 +1539,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) | |||
1539 | __skb_queue_head_init(&xmitq); | 1539 | __skb_queue_head_init(&xmitq); |
1540 | 1540 | ||
1541 | /* Ensure message is well-formed before touching the header */ | 1541 | /* Ensure message is well-formed before touching the header */ |
1542 | if (unlikely(!tipc_msg_validate(skb))) | 1542 | if (unlikely(!tipc_msg_validate(&skb))) |
1543 | goto discard; | 1543 | goto discard; |
1544 | hdr = buf_msg(skb); | 1544 | hdr = buf_msg(skb); |
1545 | usr = msg_user(hdr); | 1545 | usr = msg_user(hdr); |