diff options
Diffstat (limited to 'net/ipv4/inet_diag.c')
-rw-r--r-- | net/ipv4/inet_diag.c | 45 |
1 files changed, 24 insertions, 21 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index e5fa2ddce320..3267d3898437 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
@@ -124,7 +124,7 @@ static int inet_csk_diag_fill(struct sock *sk, | |||
124 | 124 | ||
125 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | 125 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) |
126 | if (r->idiag_family == AF_INET6) { | 126 | if (r->idiag_family == AF_INET6) { |
127 | struct ipv6_pinfo *np = inet6_sk(sk); | 127 | const struct ipv6_pinfo *np = inet6_sk(sk); |
128 | 128 | ||
129 | ipv6_addr_copy((struct in6_addr *)r->id.idiag_src, | 129 | ipv6_addr_copy((struct in6_addr *)r->id.idiag_src, |
130 | &np->rcv_saddr); | 130 | &np->rcv_saddr); |
@@ -425,7 +425,7 @@ static int inet_diag_bc_run(const void *bc, int len, | |||
425 | bc += op->no; | 425 | bc += op->no; |
426 | } | 426 | } |
427 | } | 427 | } |
428 | return (len == 0); | 428 | return len == 0; |
429 | } | 429 | } |
430 | 430 | ||
431 | static int valid_cc(const void *bc, int len, int cc) | 431 | static int valid_cc(const void *bc, int len, int cc) |
@@ -437,7 +437,7 @@ static int valid_cc(const void *bc, int len, int cc) | |||
437 | return 0; | 437 | return 0; |
438 | if (cc == len) | 438 | if (cc == len) |
439 | return 1; | 439 | return 1; |
440 | if (op->yes < 4) | 440 | if (op->yes < 4 || op->yes & 3) |
441 | return 0; | 441 | return 0; |
442 | len -= op->yes; | 442 | len -= op->yes; |
443 | bc += op->yes; | 443 | bc += op->yes; |
@@ -447,11 +447,11 @@ static int valid_cc(const void *bc, int len, int cc) | |||
447 | 447 | ||
448 | static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) | 448 | static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) |
449 | { | 449 | { |
450 | const unsigned char *bc = bytecode; | 450 | const void *bc = bytecode; |
451 | int len = bytecode_len; | 451 | int len = bytecode_len; |
452 | 452 | ||
453 | while (len > 0) { | 453 | while (len > 0) { |
454 | struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)bc; | 454 | const struct inet_diag_bc_op *op = bc; |
455 | 455 | ||
456 | //printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len); | 456 | //printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len); |
457 | switch (op->code) { | 457 | switch (op->code) { |
@@ -462,22 +462,20 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) | |||
462 | case INET_DIAG_BC_S_LE: | 462 | case INET_DIAG_BC_S_LE: |
463 | case INET_DIAG_BC_D_GE: | 463 | case INET_DIAG_BC_D_GE: |
464 | case INET_DIAG_BC_D_LE: | 464 | case INET_DIAG_BC_D_LE: |
465 | if (op->yes < 4 || op->yes > len + 4) | ||
466 | return -EINVAL; | ||
467 | case INET_DIAG_BC_JMP: | 465 | case INET_DIAG_BC_JMP: |
468 | if (op->no < 4 || op->no > len + 4) | 466 | if (op->no < 4 || op->no > len + 4 || op->no & 3) |
469 | return -EINVAL; | 467 | return -EINVAL; |
470 | if (op->no < len && | 468 | if (op->no < len && |
471 | !valid_cc(bytecode, bytecode_len, len - op->no)) | 469 | !valid_cc(bytecode, bytecode_len, len - op->no)) |
472 | return -EINVAL; | 470 | return -EINVAL; |
473 | break; | 471 | break; |
474 | case INET_DIAG_BC_NOP: | 472 | case INET_DIAG_BC_NOP: |
475 | if (op->yes < 4 || op->yes > len + 4) | ||
476 | return -EINVAL; | ||
477 | break; | 473 | break; |
478 | default: | 474 | default: |
479 | return -EINVAL; | 475 | return -EINVAL; |
480 | } | 476 | } |
477 | if (op->yes < 4 || op->yes > len + 4 || op->yes & 3) | ||
478 | return -EINVAL; | ||
481 | bc += op->yes; | 479 | bc += op->yes; |
482 | len -= op->yes; | 480 | len -= op->yes; |
483 | } | 481 | } |
@@ -490,9 +488,11 @@ static int inet_csk_diag_dump(struct sock *sk, | |||
490 | { | 488 | { |
491 | struct inet_diag_req *r = NLMSG_DATA(cb->nlh); | 489 | struct inet_diag_req *r = NLMSG_DATA(cb->nlh); |
492 | 490 | ||
493 | if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) { | 491 | if (nlmsg_attrlen(cb->nlh, sizeof(*r))) { |
494 | struct inet_diag_entry entry; | 492 | struct inet_diag_entry entry; |
495 | struct rtattr *bc = (struct rtattr *)(r + 1); | 493 | const struct nlattr *bc = nlmsg_find_attr(cb->nlh, |
494 | sizeof(*r), | ||
495 | INET_DIAG_REQ_BYTECODE); | ||
496 | struct inet_sock *inet = inet_sk(sk); | 496 | struct inet_sock *inet = inet_sk(sk); |
497 | 497 | ||
498 | entry.family = sk->sk_family; | 498 | entry.family = sk->sk_family; |
@@ -512,7 +512,7 @@ static int inet_csk_diag_dump(struct sock *sk, | |||
512 | entry.dport = ntohs(inet->inet_dport); | 512 | entry.dport = ntohs(inet->inet_dport); |
513 | entry.userlocks = sk->sk_userlocks; | 513 | entry.userlocks = sk->sk_userlocks; |
514 | 514 | ||
515 | if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry)) | 515 | if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry)) |
516 | return 0; | 516 | return 0; |
517 | } | 517 | } |
518 | 518 | ||
@@ -527,9 +527,11 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw, | |||
527 | { | 527 | { |
528 | struct inet_diag_req *r = NLMSG_DATA(cb->nlh); | 528 | struct inet_diag_req *r = NLMSG_DATA(cb->nlh); |
529 | 529 | ||
530 | if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) { | 530 | if (nlmsg_attrlen(cb->nlh, sizeof(*r))) { |
531 | struct inet_diag_entry entry; | 531 | struct inet_diag_entry entry; |
532 | struct rtattr *bc = (struct rtattr *)(r + 1); | 532 | const struct nlattr *bc = nlmsg_find_attr(cb->nlh, |
533 | sizeof(*r), | ||
534 | INET_DIAG_REQ_BYTECODE); | ||
533 | 535 | ||
534 | entry.family = tw->tw_family; | 536 | entry.family = tw->tw_family; |
535 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | 537 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) |
@@ -548,7 +550,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw, | |||
548 | entry.dport = ntohs(tw->tw_dport); | 550 | entry.dport = ntohs(tw->tw_dport); |
549 | entry.userlocks = 0; | 551 | entry.userlocks = 0; |
550 | 552 | ||
551 | if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry)) | 553 | if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry)) |
552 | return 0; | 554 | return 0; |
553 | } | 555 | } |
554 | 556 | ||
@@ -618,7 +620,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, | |||
618 | struct inet_diag_req *r = NLMSG_DATA(cb->nlh); | 620 | struct inet_diag_req *r = NLMSG_DATA(cb->nlh); |
619 | struct inet_connection_sock *icsk = inet_csk(sk); | 621 | struct inet_connection_sock *icsk = inet_csk(sk); |
620 | struct listen_sock *lopt; | 622 | struct listen_sock *lopt; |
621 | struct rtattr *bc = NULL; | 623 | const struct nlattr *bc = NULL; |
622 | struct inet_sock *inet = inet_sk(sk); | 624 | struct inet_sock *inet = inet_sk(sk); |
623 | int j, s_j; | 625 | int j, s_j; |
624 | int reqnum, s_reqnum; | 626 | int reqnum, s_reqnum; |
@@ -638,8 +640,9 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, | |||
638 | if (!lopt || !lopt->qlen) | 640 | if (!lopt || !lopt->qlen) |
639 | goto out; | 641 | goto out; |
640 | 642 | ||
641 | if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) { | 643 | if (nlmsg_attrlen(cb->nlh, sizeof(*r))) { |
642 | bc = (struct rtattr *)(r + 1); | 644 | bc = nlmsg_find_attr(cb->nlh, sizeof(*r), |
645 | INET_DIAG_REQ_BYTECODE); | ||
643 | entry.sport = inet->inet_num; | 646 | entry.sport = inet->inet_num; |
644 | entry.userlocks = sk->sk_userlocks; | 647 | entry.userlocks = sk->sk_userlocks; |
645 | } | 648 | } |
@@ -672,8 +675,8 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, | |||
672 | &ireq->rmt_addr; | 675 | &ireq->rmt_addr; |
673 | entry.dport = ntohs(ireq->rmt_port); | 676 | entry.dport = ntohs(ireq->rmt_port); |
674 | 677 | ||
675 | if (!inet_diag_bc_run(RTA_DATA(bc), | 678 | if (!inet_diag_bc_run(nla_data(bc), |
676 | RTA_PAYLOAD(bc), &entry)) | 679 | nla_len(bc), &entry)) |
677 | continue; | 680 | continue; |
678 | } | 681 | } |
679 | 682 | ||