aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMatthew Daley <mattjd@gmail.com>2011-10-14 14:45:04 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-17 19:31:39 -0400
commitcb101ed2c3c7c0224d16953fe77bfb9d6c2cb9df (patch)
tree3d266ac18673ebc85a99e4d10d8d381ff1ebd782 /net
parentc7fd0d48bde943e228e9c28ce971a22d6a1744c4 (diff)
x25: Handle undersized/fragmented skbs
There are multiple locations in the X.25 packet layer where a skb is assumed to be of at least a certain size and that all its data is currently available at skb->data. These assumptions are not checked, hence buffer overreads may occur. Use pskb_may_pull to check these minimal size assumptions and ensure that data is available at skb->data when necessary, as well as use skb_copy_bits where needed. Signed-off-by: Matthew Daley <mattjd@gmail.com> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Andrew Hendry <andrew.hendry@gmail.com> Cc: stable <stable@kernel.org> Acked-by: Andrew Hendry <andrew.hendry@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/x25/af_x25.c31
-rw-r--r--net/x25/x25_dev.c6
-rw-r--r--net/x25/x25_facilities.c10
-rw-r--r--net/x25/x25_in.c40
-rw-r--r--net/x25/x25_link.c3
-rw-r--r--net/x25/x25_subr.c14
6 files changed, 87 insertions, 17 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index a4bd1720e39b..aa567b09ea9a 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -91,7 +91,7 @@ int x25_parse_address_block(struct sk_buff *skb,
91 int needed; 91 int needed;
92 int rc; 92 int rc;
93 93
94 if (skb->len < 1) { 94 if (!pskb_may_pull(skb, 1)) {
95 /* packet has no address block */ 95 /* packet has no address block */
96 rc = 0; 96 rc = 0;
97 goto empty; 97 goto empty;
@@ -100,7 +100,7 @@ int x25_parse_address_block(struct sk_buff *skb,
100 len = *skb->data; 100 len = *skb->data;
101 needed = 1 + (len >> 4) + (len & 0x0f); 101 needed = 1 + (len >> 4) + (len & 0x0f);
102 102
103 if (skb->len < needed) { 103 if (!pskb_may_pull(skb, needed)) {
104 /* packet is too short to hold the addresses it claims 104 /* packet is too short to hold the addresses it claims
105 to hold */ 105 to hold */
106 rc = -1; 106 rc = -1;
@@ -951,10 +951,10 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
951 * 951 *
952 * Facilities length is mandatory in call request packets 952 * Facilities length is mandatory in call request packets
953 */ 953 */
954 if (skb->len < 1) 954 if (!pskb_may_pull(skb, 1))
955 goto out_clear_request; 955 goto out_clear_request;
956 len = skb->data[0] + 1; 956 len = skb->data[0] + 1;
957 if (skb->len < len) 957 if (!pskb_may_pull(skb, len))
958 goto out_clear_request; 958 goto out_clear_request;
959 skb_pull(skb,len); 959 skb_pull(skb,len);
960 960
@@ -965,6 +965,13 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
965 goto out_clear_request; 965 goto out_clear_request;
966 966
967 /* 967 /*
968 * Get all the call user data so it can be used in
969 * x25_find_listener and skb_copy_from_linear_data up ahead.
970 */
971 if (!pskb_may_pull(skb, skb->len))
972 goto out_clear_request;
973
974 /*
968 * Find a listener for the particular address/cud pair. 975 * Find a listener for the particular address/cud pair.
969 */ 976 */
970 sk = x25_find_listener(&source_addr,skb); 977 sk = x25_find_listener(&source_addr,skb);
@@ -1172,6 +1179,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
1172 * byte of the user data is the logical value of the Q Bit. 1179 * byte of the user data is the logical value of the Q Bit.
1173 */ 1180 */
1174 if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { 1181 if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
1182 if (!pskb_may_pull(skb, 1))
1183 goto out_kfree_skb;
1184
1175 qbit = skb->data[0]; 1185 qbit = skb->data[0];
1176 skb_pull(skb, 1); 1186 skb_pull(skb, 1);
1177 } 1187 }
@@ -1250,7 +1260,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
1250 struct x25_sock *x25 = x25_sk(sk); 1260 struct x25_sock *x25 = x25_sk(sk);
1251 struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; 1261 struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
1252 size_t copied; 1262 size_t copied;
1253 int qbit; 1263 int qbit, header_len = x25->neighbour->extended ?
1264 X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
1265
1254 struct sk_buff *skb; 1266 struct sk_buff *skb;
1255 unsigned char *asmptr; 1267 unsigned char *asmptr;
1256 int rc = -ENOTCONN; 1268 int rc = -ENOTCONN;
@@ -1271,6 +1283,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
1271 1283
1272 skb = skb_dequeue(&x25->interrupt_in_queue); 1284 skb = skb_dequeue(&x25->interrupt_in_queue);
1273 1285
1286 if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
1287 goto out_free_dgram;
1288
1274 skb_pull(skb, X25_STD_MIN_LEN); 1289 skb_pull(skb, X25_STD_MIN_LEN);
1275 1290
1276 /* 1291 /*
@@ -1291,10 +1306,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
1291 if (!skb) 1306 if (!skb)
1292 goto out; 1307 goto out;
1293 1308
1309 if (!pskb_may_pull(skb, header_len))
1310 goto out_free_dgram;
1311
1294 qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; 1312 qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
1295 1313
1296 skb_pull(skb, x25->neighbour->extended ? 1314 skb_pull(skb, header_len);
1297 X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
1298 1315
1299 if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { 1316 if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
1300 asmptr = skb_push(skb, 1); 1317 asmptr = skb_push(skb, 1);
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index e547ca1578c3..fa2b41888bd9 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -32,6 +32,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
32 unsigned short frametype; 32 unsigned short frametype;
33 unsigned int lci; 33 unsigned int lci;
34 34
35 if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
36 return 0;
37
35 frametype = skb->data[2]; 38 frametype = skb->data[2];
36 lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 39 lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
37 40
@@ -115,6 +118,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
115 goto drop; 118 goto drop;
116 } 119 }
117 120
121 if (!pskb_may_pull(skb, 1))
122 return 0;
123
118 switch (skb->data[0]) { 124 switch (skb->data[0]) {
119 125
120 case X25_IFACE_DATA: 126 case X25_IFACE_DATA:
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index f77e4e75f914..36384a1fa9f2 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -44,7 +44,7 @@
44int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, 44int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
45 struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) 45 struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
46{ 46{
47 unsigned char *p = skb->data; 47 unsigned char *p;
48 unsigned int len; 48 unsigned int len;
49 49
50 *vc_fac_mask = 0; 50 *vc_fac_mask = 0;
@@ -60,14 +60,16 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
60 memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); 60 memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
61 memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); 61 memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
62 62
63 if (skb->len < 1) 63 if (!pskb_may_pull(skb, 1))
64 return 0; 64 return 0;
65 65
66 len = *p++; 66 len = skb->data[0];
67 67
68 if (len >= skb->len) 68 if (!pskb_may_pull(skb, 1 + len))
69 return -1; 69 return -1;
70 70
71 p = skb->data + 1;
72
71 while (len > 0) { 73 while (len > 0) {
72 switch (*p & X25_FAC_CLASS_MASK) { 74 switch (*p & X25_FAC_CLASS_MASK) {
73 case X25_FAC_CLASS_A: 75 case X25_FAC_CLASS_A:
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index 63488fd4885a..a49cd4ec551a 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -107,6 +107,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
107 /* 107 /*
108 * Parse the data in the frame. 108 * Parse the data in the frame.
109 */ 109 */
110 if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
111 goto out_clear;
110 skb_pull(skb, X25_STD_MIN_LEN); 112 skb_pull(skb, X25_STD_MIN_LEN);
111 113
112 len = x25_parse_address_block(skb, &source_addr, 114 len = x25_parse_address_block(skb, &source_addr,
@@ -130,9 +132,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
130 if (skb->len > X25_MAX_CUD_LEN) 132 if (skb->len > X25_MAX_CUD_LEN)
131 goto out_clear; 133 goto out_clear;
132 134
133 skb_copy_from_linear_data(skb, 135 skb_copy_bits(skb, 0, x25->calluserdata.cuddata,
134 x25->calluserdata.cuddata, 136 skb->len);
135 skb->len);
136 x25->calluserdata.cudlength = skb->len; 137 x25->calluserdata.cudlength = skb->len;
137 } 138 }
138 if (!sock_flag(sk, SOCK_DEAD)) 139 if (!sock_flag(sk, SOCK_DEAD))
@@ -140,6 +141,9 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
140 break; 141 break;
141 } 142 }
142 case X25_CLEAR_REQUEST: 143 case X25_CLEAR_REQUEST:
144 if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
145 goto out_clear;
146
143 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 147 x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
144 x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); 148 x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
145 break; 149 break;
@@ -167,6 +171,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
167 switch (frametype) { 171 switch (frametype) {
168 172
169 case X25_CLEAR_REQUEST: 173 case X25_CLEAR_REQUEST:
174 if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
175 goto out_clear;
176
170 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 177 x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
171 x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 178 x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
172 break; 179 break;
@@ -180,6 +187,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
180 } 187 }
181 188
182 return 0; 189 return 0;
190
191out_clear:
192 x25_write_internal(sk, X25_CLEAR_REQUEST);
193 x25_start_t23timer(sk);
194 return 0;
183} 195}
184 196
185/* 197/*
@@ -209,6 +221,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
209 break; 221 break;
210 222
211 case X25_CLEAR_REQUEST: 223 case X25_CLEAR_REQUEST:
224 if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
225 goto out_clear;
226
212 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 227 x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
213 x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 228 x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
214 break; 229 break;
@@ -307,6 +322,12 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
307 } 322 }
308 323
309 return queued; 324 return queued;
325
326out_clear:
327 x25_write_internal(sk, X25_CLEAR_REQUEST);
328 x25->state = X25_STATE_2;
329 x25_start_t23timer(sk);
330 return 0;
310} 331}
311 332
312/* 333/*
@@ -316,13 +337,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
316 */ 337 */
317static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) 338static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
318{ 339{
340 struct x25_sock *x25 = x25_sk(sk);
341
319 switch (frametype) { 342 switch (frametype) {
320 343
321 case X25_RESET_REQUEST: 344 case X25_RESET_REQUEST:
322 x25_write_internal(sk, X25_RESET_CONFIRMATION); 345 x25_write_internal(sk, X25_RESET_CONFIRMATION);
323 case X25_RESET_CONFIRMATION: { 346 case X25_RESET_CONFIRMATION: {
324 struct x25_sock *x25 = x25_sk(sk);
325
326 x25_stop_timer(sk); 347 x25_stop_timer(sk);
327 x25->condition = 0x00; 348 x25->condition = 0x00;
328 x25->va = 0; 349 x25->va = 0;
@@ -334,6 +355,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
334 break; 355 break;
335 } 356 }
336 case X25_CLEAR_REQUEST: 357 case X25_CLEAR_REQUEST:
358 if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
359 goto out_clear;
360
337 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 361 x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
338 x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 362 x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
339 break; 363 break;
@@ -343,6 +367,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
343 } 367 }
344 368
345 return 0; 369 return 0;
370
371out_clear:
372 x25_write_internal(sk, X25_CLEAR_REQUEST);
373 x25->state = X25_STATE_2;
374 x25_start_t23timer(sk);
375 return 0;
346} 376}
347 377
348/* Higher level upcall for a LAPB frame */ 378/* Higher level upcall for a LAPB frame */
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index 037958ff8eed..4acacf3c6617 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -90,6 +90,9 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
90 break; 90 break;
91 91
92 case X25_DIAGNOSTIC: 92 case X25_DIAGNOSTIC:
93 if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4))
94 break;
95
93 printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", 96 printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n",
94 skb->data[3], skb->data[4], 97 skb->data[3], skb->data[4],
95 skb->data[5], skb->data[6]); 98 skb->data[5], skb->data[6]);
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index 24a342ebc7f5..5170d52bfd96 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -269,7 +269,11 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
269 int *d, int *m) 269 int *d, int *m)
270{ 270{
271 struct x25_sock *x25 = x25_sk(sk); 271 struct x25_sock *x25 = x25_sk(sk);
272 unsigned char *frame = skb->data; 272 unsigned char *frame;
273
274 if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
275 return X25_ILLEGAL;
276 frame = skb->data;
273 277
274 *ns = *nr = *q = *d = *m = 0; 278 *ns = *nr = *q = *d = *m = 0;
275 279
@@ -294,6 +298,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
294 if (frame[2] == X25_RR || 298 if (frame[2] == X25_RR ||
295 frame[2] == X25_RNR || 299 frame[2] == X25_RNR ||
296 frame[2] == X25_REJ) { 300 frame[2] == X25_REJ) {
301 if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
302 return X25_ILLEGAL;
303 frame = skb->data;
304
297 *nr = (frame[3] >> 1) & 0x7F; 305 *nr = (frame[3] >> 1) & 0x7F;
298 return frame[2]; 306 return frame[2];
299 } 307 }
@@ -308,6 +316,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
308 316
309 if (x25->neighbour->extended) { 317 if (x25->neighbour->extended) {
310 if ((frame[2] & 0x01) == X25_DATA) { 318 if ((frame[2] & 0x01) == X25_DATA) {
319 if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
320 return X25_ILLEGAL;
321 frame = skb->data;
322
311 *q = (frame[0] & X25_Q_BIT) == X25_Q_BIT; 323 *q = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
312 *d = (frame[0] & X25_D_BIT) == X25_D_BIT; 324 *d = (frame[0] & X25_D_BIT) == X25_D_BIT;
313 *m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT; 325 *m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;