Skip to content

Commit 5e1f542

Browse files
nealcardwelldavem330
authored andcommitted
inet_diag: validate port comparison byte code to prevent unsafe reads
Add logic to verify that a port comparison byte code operation actually has the second inet_diag_bc_op from which we read the port for such operations. Previously the code blindly referenced op[1] without first checking whether a second inet_diag_bc_op struct could fit there. So a malicious user could make the kernel read 4 bytes beyond the end of the bytecode array by claiming to have a whole port comparison byte code (2 inet_diag_bc_op structs) when in fact the bytecode was not long enough to hold both. Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent f67caec commit 5e1f542

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

net/ipv4/inet_diag.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,17 @@ static bool valid_hostcond(const struct inet_diag_bc_op *op, int len,
557557
return true;
558558
}
559559

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+
560571
static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
561572
{
562573
const void *bc = bytecode;
@@ -572,24 +583,30 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
572583
case INET_DIAG_BC_D_COND:
573584
if (!valid_hostcond(bc, len, &min_len))
574585
return -EINVAL;
575-
/* fall through */
576-
case INET_DIAG_BC_AUTO:
586+
break;
577587
case INET_DIAG_BC_S_GE:
578588
case INET_DIAG_BC_S_LE:
579589
case INET_DIAG_BC_D_GE:
580590
case INET_DIAG_BC_D_LE:
581-
case INET_DIAG_BC_JMP:
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))
591+
if (!valid_port_comparison(bc, len, &min_len))
586592
return -EINVAL;
587593
break;
594+
case INET_DIAG_BC_AUTO:
595+
case INET_DIAG_BC_JMP:
588596
case INET_DIAG_BC_NOP:
589597
break;
590598
default:
591599
return -EINVAL;
592600
}
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+
593610
if (op->yes < min_len || op->yes > len + 4 || op->yes & 3)
594611
return -EINVAL;
595612
bc += op->yes;

0 commit comments

Comments
 (0)