aboutsummaryrefslogtreecommitdiffstats
path: root/net/rose/rose_subr.c
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2011-03-20 02:48:05 -0400
committerDavid S. Miller <davem@davemloft.net>2011-03-27 20:59:04 -0400
commite0bccd315db0c2f919e7fcf9cb60db21d9986f52 (patch)
tree8cf512f43221087f964c0f55c7665e293e96921b /net/rose/rose_subr.c
parentbe20250c13f88375345ad99950190685eda51eb8 (diff)
rose: Add length checks to CALL_REQUEST parsing
Define some constant offsets for CALL_REQUEST based on the description at <http://www.techfest.com/networking/wan/x25plp.htm> and the definition of ROSE as using 10-digit (5-byte) addresses. Use them consistently. Validate all implicit and explicit facilities lengths. Validate the address length byte rather than either trusting or assuming its value. Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rose/rose_subr.c')
-rw-r--r--net/rose/rose_subr.c91
1 files changed, 57 insertions, 34 deletions
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index 174d51c9ce37..f6c71caa94b9 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -142,7 +142,7 @@ void rose_write_internal(struct sock *sk, int frametype)
142 *dptr++ = ROSE_GFI | lci1; 142 *dptr++ = ROSE_GFI | lci1;
143 *dptr++ = lci2; 143 *dptr++ = lci2;
144 *dptr++ = frametype; 144 *dptr++ = frametype;
145 *dptr++ = 0xAA; 145 *dptr++ = ROSE_CALL_REQ_ADDR_LEN_VAL;
146 memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); 146 memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN);
147 dptr += ROSE_ADDR_LEN; 147 dptr += ROSE_ADDR_LEN;
148 memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); 148 memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN);
@@ -246,12 +246,16 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *
246 do { 246 do {
247 switch (*p & 0xC0) { 247 switch (*p & 0xC0) {
248 case 0x00: 248 case 0x00:
249 if (len < 2)
250 return -1;
249 p += 2; 251 p += 2;
250 n += 2; 252 n += 2;
251 len -= 2; 253 len -= 2;
252 break; 254 break;
253 255
254 case 0x40: 256 case 0x40:
257 if (len < 3)
258 return -1;
255 if (*p == FAC_NATIONAL_RAND) 259 if (*p == FAC_NATIONAL_RAND)
256 facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); 260 facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
257 p += 3; 261 p += 3;
@@ -260,32 +264,48 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *
260 break; 264 break;
261 265
262 case 0x80: 266 case 0x80:
267 if (len < 4)
268 return -1;
263 p += 4; 269 p += 4;
264 n += 4; 270 n += 4;
265 len -= 4; 271 len -= 4;
266 break; 272 break;
267 273
268 case 0xC0: 274 case 0xC0:
275 if (len < 2)
276 return -1;
269 l = p[1]; 277 l = p[1];
278 if (len < 2 + l)
279 return -1;
270 if (*p == FAC_NATIONAL_DEST_DIGI) { 280 if (*p == FAC_NATIONAL_DEST_DIGI) {
271 if (!fac_national_digis_received) { 281 if (!fac_national_digis_received) {
282 if (l < AX25_ADDR_LEN)
283 return -1;
272 memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); 284 memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
273 facilities->source_ndigis = 1; 285 facilities->source_ndigis = 1;
274 } 286 }
275 } 287 }
276 else if (*p == FAC_NATIONAL_SRC_DIGI) { 288 else if (*p == FAC_NATIONAL_SRC_DIGI) {
277 if (!fac_national_digis_received) { 289 if (!fac_national_digis_received) {
290 if (l < AX25_ADDR_LEN)
291 return -1;
278 memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); 292 memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
279 facilities->dest_ndigis = 1; 293 facilities->dest_ndigis = 1;
280 } 294 }
281 } 295 }
282 else if (*p == FAC_NATIONAL_FAIL_CALL) { 296 else if (*p == FAC_NATIONAL_FAIL_CALL) {
297 if (l < AX25_ADDR_LEN)
298 return -1;
283 memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); 299 memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
284 } 300 }
285 else if (*p == FAC_NATIONAL_FAIL_ADD) { 301 else if (*p == FAC_NATIONAL_FAIL_ADD) {
302 if (l < 1 + ROSE_ADDR_LEN)
303 return -1;
286 memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); 304 memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
287 } 305 }
288 else if (*p == FAC_NATIONAL_DIGIS) { 306 else if (*p == FAC_NATIONAL_DIGIS) {
307 if (l % AX25_ADDR_LEN)
308 return -1;
289 fac_national_digis_received = 1; 309 fac_national_digis_received = 1;
290 facilities->source_ndigis = 0; 310 facilities->source_ndigis = 0;
291 facilities->dest_ndigis = 0; 311 facilities->dest_ndigis = 0;
@@ -319,24 +339,32 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac
319 do { 339 do {
320 switch (*p & 0xC0) { 340 switch (*p & 0xC0) {
321 case 0x00: 341 case 0x00:
342 if (len < 2)
343 return -1;
322 p += 2; 344 p += 2;
323 n += 2; 345 n += 2;
324 len -= 2; 346 len -= 2;
325 break; 347 break;
326 348
327 case 0x40: 349 case 0x40:
350 if (len < 3)
351 return -1;
328 p += 3; 352 p += 3;
329 n += 3; 353 n += 3;
330 len -= 3; 354 len -= 3;
331 break; 355 break;
332 356
333 case 0x80: 357 case 0x80:
358 if (len < 4)
359 return -1;
334 p += 4; 360 p += 4;
335 n += 4; 361 n += 4;
336 len -= 4; 362 len -= 4;
337 break; 363 break;
338 364
339 case 0xC0: 365 case 0xC0:
366 if (len < 2)
367 return -1;
340 l = p[1]; 368 l = p[1];
341 369
342 /* Prevent overflows*/ 370 /* Prevent overflows*/
@@ -365,49 +393,44 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac
365 return n; 393 return n;
366} 394}
367 395
368int rose_parse_facilities(unsigned char *p, 396int rose_parse_facilities(unsigned char *p, unsigned packet_len,
369 struct rose_facilities_struct *facilities) 397 struct rose_facilities_struct *facilities)
370{ 398{
371 int facilities_len, len; 399 int facilities_len, len;
372 400
373 facilities_len = *p++; 401 facilities_len = *p++;
374 402
375 if (facilities_len == 0) 403 if (facilities_len == 0 || (unsigned)facilities_len > packet_len)
376 return 0; 404 return 0;
377 405
378 while (facilities_len > 0) { 406 while (facilities_len >= 3 && *p == 0x00) {
379 if (*p == 0x00) { 407 facilities_len--;
380 facilities_len--; 408 p++;
381 p++; 409
382 410 switch (*p) {
383 switch (*p) { 411 case FAC_NATIONAL: /* National */
384 case FAC_NATIONAL: /* National */ 412 len = rose_parse_national(p + 1, facilities, facilities_len - 1);
385 len = rose_parse_national(p + 1, facilities, facilities_len - 1); 413 break;
386 if (len < 0) 414
387 return 0; 415 case FAC_CCITT: /* CCITT */
388 facilities_len -= len + 1; 416 len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
389 p += len + 1; 417 break;
390 break; 418
391 419 default:
392 case FAC_CCITT: /* CCITT */ 420 printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
393 len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); 421 len = 1;
394 if (len < 0) 422 break;
395 return 0; 423 }
396 facilities_len -= len + 1; 424
397 p += len + 1; 425 if (len < 0)
398 break; 426 return 0;
399 427 if (WARN_ON(len >= facilities_len))
400 default: 428 return 0;
401 printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); 429 facilities_len -= len + 1;
402 facilities_len--; 430 p += len + 1;
403 p++;
404 break;
405 }
406 } else
407 break; /* Error in facilities format */
408 } 431 }
409 432
410 return 1; 433 return facilities_len == 0;
411} 434}
412 435
413static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) 436static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)