Skip to content

Commit cb101ed

Browse files
Matthew Daleydavem330
authored andcommitted
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 <[email protected]> Cc: Eric Dumazet <[email protected]> Cc: Andrew Hendry <[email protected]> Cc: stable <[email protected]> Acked-by: Andrew Hendry <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c7fd0d4 commit cb101ed

File tree

6 files changed

+87
-17
lines changed

6 files changed

+87
-17
lines changed

net/x25/af_x25.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ int x25_parse_address_block(struct sk_buff *skb,
9191
int needed;
9292
int rc;
9393

94-
if (skb->len < 1) {
94+
if (!pskb_may_pull(skb, 1)) {
9595
/* packet has no address block */
9696
rc = 0;
9797
goto empty;
@@ -100,7 +100,7 @@ int x25_parse_address_block(struct sk_buff *skb,
100100
len = *skb->data;
101101
needed = 1 + (len >> 4) + (len & 0x0f);
102102

103-
if (skb->len < needed) {
103+
if (!pskb_may_pull(skb, needed)) {
104104
/* packet is too short to hold the addresses it claims
105105
to hold */
106106
rc = -1;
@@ -951,10 +951,10 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
951951
*
952952
* Facilities length is mandatory in call request packets
953953
*/
954-
if (skb->len < 1)
954+
if (!pskb_may_pull(skb, 1))
955955
goto out_clear_request;
956956
len = skb->data[0] + 1;
957-
if (skb->len < len)
957+
if (!pskb_may_pull(skb, len))
958958
goto out_clear_request;
959959
skb_pull(skb,len);
960960

@@ -964,6 +964,13 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
964964
if (skb->len > X25_MAX_CUD_LEN)
965965
goto out_clear_request;
966966

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+
967974
/*
968975
* Find a listener for the particular address/cud pair.
969976
*/
@@ -1172,6 +1179,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
11721179
* byte of the user data is the logical value of the Q Bit.
11731180
*/
11741181
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
1182+
if (!pskb_may_pull(skb, 1))
1183+
goto out_kfree_skb;
1184+
11751185
qbit = skb->data[0];
11761186
skb_pull(skb, 1);
11771187
}
@@ -1250,7 +1260,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
12501260
struct x25_sock *x25 = x25_sk(sk);
12511261
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
12521262
size_t copied;
1253-
int qbit;
1263+
int qbit, header_len = x25->neighbour->extended ?
1264+
X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
1265+
12541266
struct sk_buff *skb;
12551267
unsigned char *asmptr;
12561268
int rc = -ENOTCONN;
@@ -1271,6 +1283,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
12711283

12721284
skb = skb_dequeue(&x25->interrupt_in_queue);
12731285

1286+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
1287+
goto out_free_dgram;
1288+
12741289
skb_pull(skb, X25_STD_MIN_LEN);
12751290

12761291
/*
@@ -1291,10 +1306,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
12911306
if (!skb)
12921307
goto out;
12931308

1309+
if (!pskb_may_pull(skb, header_len))
1310+
goto out_free_dgram;
1311+
12941312
qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
12951313

1296-
skb_pull(skb, x25->neighbour->extended ?
1297-
X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
1314+
skb_pull(skb, header_len);
12981315

12991316
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
13001317
asmptr = skb_push(skb, 1);

net/x25/x25_dev.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
3232
unsigned short frametype;
3333
unsigned int lci;
3434

35+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
36+
return 0;
37+
3538
frametype = skb->data[2];
3639
lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
3740

@@ -115,6 +118,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
115118
goto drop;
116119
}
117120

121+
if (!pskb_may_pull(skb, 1))
122+
return 0;
123+
118124
switch (skb->data[0]) {
119125

120126
case X25_IFACE_DATA:

net/x25/x25_facilities.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
4545
struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
4646
{
47-
unsigned char *p = skb->data;
47+
unsigned char *p;
4848
unsigned int len;
4949

5050
*vc_fac_mask = 0;
@@ -60,14 +60,16 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
6060
memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
6161
memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
6262

63-
if (skb->len < 1)
63+
if (!pskb_may_pull(skb, 1))
6464
return 0;
6565

66-
len = *p++;
66+
len = skb->data[0];
6767

68-
if (len >= skb->len)
68+
if (!pskb_may_pull(skb, 1 + len))
6969
return -1;
7070

71+
p = skb->data + 1;
72+
7173
while (len > 0) {
7274
switch (*p & X25_FAC_CLASS_MASK) {
7375
case X25_FAC_CLASS_A:

net/x25/x25_in.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
107107
/*
108108
* Parse the data in the frame.
109109
*/
110+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
111+
goto out_clear;
110112
skb_pull(skb, X25_STD_MIN_LEN);
111113

112114
len = x25_parse_address_block(skb, &source_addr,
@@ -130,16 +132,18 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
130132
if (skb->len > X25_MAX_CUD_LEN)
131133
goto out_clear;
132134

133-
skb_copy_from_linear_data(skb,
134-
x25->calluserdata.cuddata,
135-
skb->len);
135+
skb_copy_bits(skb, 0, x25->calluserdata.cuddata,
136+
skb->len);
136137
x25->calluserdata.cudlength = skb->len;
137138
}
138139
if (!sock_flag(sk, SOCK_DEAD))
139140
sk->sk_state_change(sk);
140141
break;
141142
}
142143
case X25_CLEAR_REQUEST:
144+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
145+
goto out_clear;
146+
143147
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
144148
x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
145149
break;
@@ -167,6 +171,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
167171
switch (frametype) {
168172

169173
case X25_CLEAR_REQUEST:
174+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
175+
goto out_clear;
176+
170177
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
171178
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
172179
break;
@@ -180,6 +187,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
180187
}
181188

182189
return 0;
190+
191+
out_clear:
192+
x25_write_internal(sk, X25_CLEAR_REQUEST);
193+
x25_start_t23timer(sk);
194+
return 0;
183195
}
184196

185197
/*
@@ -209,6 +221,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
209221
break;
210222

211223
case X25_CLEAR_REQUEST:
224+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
225+
goto out_clear;
226+
212227
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
213228
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
214229
break;
@@ -307,6 +322,12 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
307322
}
308323

309324
return queued;
325+
326+
out_clear:
327+
x25_write_internal(sk, X25_CLEAR_REQUEST);
328+
x25->state = X25_STATE_2;
329+
x25_start_t23timer(sk);
330+
return 0;
310331
}
311332

312333
/*
@@ -316,13 +337,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
316337
*/
317338
static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
318339
{
340+
struct x25_sock *x25 = x25_sk(sk);
341+
319342
switch (frametype) {
320343

321344
case X25_RESET_REQUEST:
322345
x25_write_internal(sk, X25_RESET_CONFIRMATION);
323346
case X25_RESET_CONFIRMATION: {
324-
struct x25_sock *x25 = x25_sk(sk);
325-
326347
x25_stop_timer(sk);
327348
x25->condition = 0x00;
328349
x25->va = 0;
@@ -334,6 +355,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
334355
break;
335356
}
336357
case X25_CLEAR_REQUEST:
358+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
359+
goto out_clear;
360+
337361
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
338362
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
339363
break;
@@ -343,6 +367,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
343367
}
344368

345369
return 0;
370+
371+
out_clear:
372+
x25_write_internal(sk, X25_CLEAR_REQUEST);
373+
x25->state = X25_STATE_2;
374+
x25_start_t23timer(sk);
375+
return 0;
346376
}
347377

348378
/* Higher level upcall for a LAPB frame */

net/x25/x25_link.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
9090
break;
9191

9292
case X25_DIAGNOSTIC:
93+
if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4))
94+
break;
95+
9396
printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n",
9497
skb->data[3], skb->data[4],
9598
skb->data[5], skb->data[6]);

net/x25/x25_subr.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,11 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
269269
int *d, int *m)
270270
{
271271
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;
273277

274278
*ns = *nr = *q = *d = *m = 0;
275279

@@ -294,6 +298,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
294298
if (frame[2] == X25_RR ||
295299
frame[2] == X25_RNR ||
296300
frame[2] == X25_REJ) {
301+
if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
302+
return X25_ILLEGAL;
303+
frame = skb->data;
304+
297305
*nr = (frame[3] >> 1) & 0x7F;
298306
return frame[2];
299307
}
@@ -308,6 +316,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
308316

309317
if (x25->neighbour->extended) {
310318
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+
311323
*q = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
312324
*d = (frame[0] & X25_D_BIT) == X25_D_BIT;
313325
*m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;

0 commit comments

Comments
 (0)