aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/inet_diag.c31
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. */
561static 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
560static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) 571static 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;