diff options
| -rw-r--r-- | net/ipv4/inet_diag.c | 31 |
1 files changed, 24 insertions, 7 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 95f1a458371d..e23e16dc501d 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
| @@ -557,6 +557,17 @@ static bool valid_hostcond(const struct inet_diag_bc_op *op, int len, | |||
| 557 | return true; | 557 | return true; |
| 558 | } | 558 | } |
| 559 | 559 | ||
| 560 | /* Validate a port comparison operator. */ | ||
| 561 | static inline bool valid_port_comparison(const struct inet_diag_bc_op *op, | ||
| 562 | int len, int *min_len) | ||
| 563 | { | ||
| 564 | /* Port comparisons put the port in a follow-on inet_diag_bc_op. */ | ||
| 565 | *min_len += sizeof(struct inet_diag_bc_op); | ||
| 566 | if (len < *min_len) | ||
| 567 | return false; | ||
| 568 | return true; | ||
| 569 | } | ||
| 570 | |||
| 560 | static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) | 571 | static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) |
| 561 | { | 572 | { |
| 562 | const void *bc = bytecode; | 573 | const void *bc = bytecode; |
| @@ -572,24 +583,30 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) | |||
| 572 | case INET_DIAG_BC_D_COND: | 583 | case INET_DIAG_BC_D_COND: |
| 573 | if (!valid_hostcond(bc, len, &min_len)) | 584 | if (!valid_hostcond(bc, len, &min_len)) |
| 574 | return -EINVAL; | 585 | return -EINVAL; |
| 575 | /* fall through */ | 586 | break; |
| 576 | case INET_DIAG_BC_AUTO: | ||
| 577 | case INET_DIAG_BC_S_GE: | 587 | case INET_DIAG_BC_S_GE: |
| 578 | case INET_DIAG_BC_S_LE: | 588 | case INET_DIAG_BC_S_LE: |
| 579 | case INET_DIAG_BC_D_GE: | 589 | case INET_DIAG_BC_D_GE: |
| 580 | case INET_DIAG_BC_D_LE: | 590 | case INET_DIAG_BC_D_LE: |
| 581 | case INET_DIAG_BC_JMP: | 591 | if (!valid_port_comparison(bc, len, &min_len)) |
| 582 | if (op->no < min_len || op->no > len + 4 || op->no & 3) | ||
| 583 | return -EINVAL; | ||
| 584 | if (op->no < len && | ||
| 585 | !valid_cc(bytecode, bytecode_len, len - op->no)) | ||
| 586 | return -EINVAL; | 592 | return -EINVAL; |
| 587 | break; | 593 | break; |
| 594 | case INET_DIAG_BC_AUTO: | ||
| 595 | case INET_DIAG_BC_JMP: | ||
| 588 | case INET_DIAG_BC_NOP: | 596 | case INET_DIAG_BC_NOP: |
| 589 | break; | 597 | break; |
| 590 | default: | 598 | default: |
| 591 | return -EINVAL; | 599 | return -EINVAL; |
| 592 | } | 600 | } |
| 601 | |||
| 602 | if (op->code != INET_DIAG_BC_NOP) { | ||
| 603 | if (op->no < min_len || op->no > len + 4 || op->no & 3) | ||
| 604 | return -EINVAL; | ||
| 605 | if (op->no < len && | ||
| 606 | !valid_cc(bytecode, bytecode_len, len - op->no)) | ||
| 607 | return -EINVAL; | ||
| 608 | } | ||
| 609 | |||
| 593 | if (op->yes < min_len || op->yes > len + 4 || op->yes & 3) | 610 | if (op->yes < min_len || op->yes > len + 4 || op->yes & 3) |
| 594 | return -EINVAL; | 611 | return -EINVAL; |
| 595 | bc += op->yes; | 612 | bc += op->yes; |
