Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Matthew Daley and committed by
David S. Miller
cb101ed2 c7fd0d48

+87 -17
+24 -7
net/x25/af_x25.c
··· 91 91 int needed; 92 92 int rc; 93 93 94 - if (skb->len < 1) { 94 + if (!pskb_may_pull(skb, 1)) { 95 95 /* packet has no address block */ 96 96 rc = 0; 97 97 goto empty; ··· 100 100 len = *skb->data; 101 101 needed = 1 + (len >> 4) + (len & 0x0f); 102 102 103 - if (skb->len < needed) { 103 + if (!pskb_may_pull(skb, needed)) { 104 104 /* packet is too short to hold the addresses it claims 105 105 to hold */ 106 106 rc = -1; ··· 951 951 * 952 952 * Facilities length is mandatory in call request packets 953 953 */ 954 - if (skb->len < 1) 954 + if (!pskb_may_pull(skb, 1)) 955 955 goto out_clear_request; 956 956 len = skb->data[0] + 1; 957 - if (skb->len < len) 957 + if (!pskb_may_pull(skb, len)) 958 958 goto out_clear_request; 959 959 skb_pull(skb,len); 960 960 ··· 962 962 * Ensure that the amount of call user data is valid. 963 963 */ 964 964 if (skb->len > X25_MAX_CUD_LEN) 965 + goto out_clear_request; 966 + 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)) 965 972 goto out_clear_request; 966 973 967 974 /* ··· 1179 1172 * byte of the user data is the logical value of the Q Bit. 1180 1173 */ 1181 1174 if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { 1175 + if (!pskb_may_pull(skb, 1)) 1176 + goto out_kfree_skb; 1177 + 1182 1178 qbit = skb->data[0]; 1183 1179 skb_pull(skb, 1); 1184 1180 } ··· 1260 1250 struct x25_sock *x25 = x25_sk(sk); 1261 1251 struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; 1262 1252 size_t copied; 1263 - int qbit; 1253 + int qbit, header_len = x25->neighbour->extended ? 1254 + X25_EXT_MIN_LEN : X25_STD_MIN_LEN; 1255 + 1264 1256 struct sk_buff *skb; 1265 1257 unsigned char *asmptr; 1266 1258 int rc = -ENOTCONN; ··· 1282 1270 goto out; 1283 1271 1284 1272 skb = skb_dequeue(&x25->interrupt_in_queue); 1273 + 1274 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) 1275 + goto out_free_dgram; 1285 1276 1286 1277 skb_pull(skb, X25_STD_MIN_LEN); 1287 1278 ··· 1306 1291 if (!skb) 1307 1292 goto out; 1308 1293 1294 + if (!pskb_may_pull(skb, header_len)) 1295 + goto out_free_dgram; 1296 + 1309 1297 qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; 1310 1298 1311 - skb_pull(skb, x25->neighbour->extended ? 1312 - X25_EXT_MIN_LEN : X25_STD_MIN_LEN); 1299 + skb_pull(skb, header_len); 1313 1300 1314 1301 if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { 1315 1302 asmptr = skb_push(skb, 1);
+6
net/x25/x25_dev.c
··· 32 32 unsigned short frametype; 33 33 unsigned int lci; 34 34 35 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) 36 + return 0; 37 + 35 38 frametype = skb->data[2]; 36 39 lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 37 40 ··· 117 114 printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name); 118 115 goto drop; 119 116 } 117 + 118 + if (!pskb_may_pull(skb, 1)) 119 + return 0; 120 120 121 121 switch (skb->data[0]) { 122 122
+6 -4
net/x25/x25_facilities.c
··· 44 44 int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, 45 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 48 unsigned int len; 49 49 50 50 *vc_fac_mask = 0; ··· 60 60 memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); 61 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 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 69 return -1; 70 + 71 + p = skb->data + 1; 70 72 71 73 while (len > 0) { 72 74 switch (*p & X25_FAC_CLASS_MASK) {
+35 -5
net/x25/x25_in.c
··· 107 107 /* 108 108 * Parse the data in the frame. 109 109 */ 110 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) 111 + goto out_clear; 110 112 skb_pull(skb, X25_STD_MIN_LEN); 111 113 112 114 len = x25_parse_address_block(skb, &source_addr, ··· 132 130 if (skb->len > X25_MAX_CUD_LEN) 133 131 goto out_clear; 134 132 135 - skb_copy_from_linear_data(skb, 136 - x25->calluserdata.cuddata, 137 - skb->len); 133 + skb_copy_bits(skb, 0, x25->calluserdata.cuddata, 134 + skb->len); 138 135 x25->calluserdata.cudlength = skb->len; 139 136 } 140 137 if (!sock_flag(sk, SOCK_DEAD)) ··· 141 140 break; 142 141 } 143 142 case X25_CLEAR_REQUEST: 143 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 144 + goto out_clear; 145 + 144 146 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 145 147 x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); 146 148 break; ··· 171 167 switch (frametype) { 172 168 173 169 case X25_CLEAR_REQUEST: 170 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 171 + goto out_clear; 172 + 174 173 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 175 174 x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 176 175 break; ··· 186 179 break; 187 180 } 188 181 182 + return 0; 183 + 184 + out_clear: 185 + x25_write_internal(sk, X25_CLEAR_REQUEST); 186 + x25_start_t23timer(sk); 189 187 return 0; 190 188 } 191 189 ··· 221 209 break; 222 210 223 211 case X25_CLEAR_REQUEST: 212 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 213 + goto out_clear; 214 + 224 215 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 225 216 x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 226 217 break; ··· 322 307 } 323 308 324 309 return queued; 310 + 311 + out_clear: 312 + x25_write_internal(sk, X25_CLEAR_REQUEST); 313 + x25->state = X25_STATE_2; 314 + x25_start_t23timer(sk); 315 + return 0; 325 316 } 326 317 327 318 /* ··· 337 316 */ 338 317 static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) 339 318 { 319 + struct x25_sock *x25 = x25_sk(sk); 320 + 340 321 switch (frametype) { 341 322 342 323 case X25_RESET_REQUEST: 343 324 x25_write_internal(sk, X25_RESET_CONFIRMATION); 344 325 case X25_RESET_CONFIRMATION: { 345 - struct x25_sock *x25 = x25_sk(sk); 346 - 347 326 x25_stop_timer(sk); 348 327 x25->condition = 0x00; 349 328 x25->va = 0; ··· 355 334 break; 356 335 } 357 336 case X25_CLEAR_REQUEST: 337 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) 338 + goto out_clear; 339 + 358 340 x25_write_internal(sk, X25_CLEAR_CONFIRMATION); 359 341 x25_disconnect(sk, 0, skb->data[3], skb->data[4]); 360 342 break; ··· 366 342 break; 367 343 } 368 344 345 + return 0; 346 + 347 + out_clear: 348 + x25_write_internal(sk, X25_CLEAR_REQUEST); 349 + x25->state = X25_STATE_2; 350 + x25_start_t23timer(sk); 369 351 return 0; 370 352 } 371 353
+3
net/x25/x25_link.c
··· 90 90 break; 91 91 92 92 case X25_DIAGNOSTIC: 93 + if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4)) 94 + break; 95 + 93 96 printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", 94 97 skb->data[3], skb->data[4], 95 98 skb->data[5], skb->data[6]);
+13 -1
net/x25/x25_subr.c
··· 269 269 int *d, int *m) 270 270 { 271 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 278 *ns = *nr = *q = *d = *m = 0; 275 279 ··· 298 294 if (frame[2] == X25_RR || 299 295 frame[2] == X25_RNR || 300 296 frame[2] == X25_REJ) { 297 + if (!pskb_may_pull(skb, X25_EXT_MIN_LEN)) 298 + return X25_ILLEGAL; 299 + frame = skb->data; 300 + 301 301 *nr = (frame[3] >> 1) & 0x7F; 302 302 return frame[2]; 303 303 } ··· 316 308 317 309 if (x25->neighbour->extended) { 318 310 if ((frame[2] & 0x01) == X25_DATA) { 311 + if (!pskb_may_pull(skb, X25_EXT_MIN_LEN)) 312 + return X25_ILLEGAL; 313 + frame = skb->data; 314 + 319 315 *q = (frame[0] & X25_Q_BIT) == X25_Q_BIT; 320 316 *d = (frame[0] & X25_D_BIT) == X25_D_BIT; 321 317 *m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;