diff options
author | melifaro <melifaro@FreeBSD.org> | 2013-11-28 10:28:28 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2013-11-28 10:28:28 +0000 |
commit | c9cfc8e3226ba615d3221cb9c74e66d69b9c70c5 (patch) | |
tree | a562142d1ba7f7fe6224c65be6117ae4e5f5b20e | |
parent | 38607685e1476d896e08d2967010a65970fde85d (diff) | |
download | FreeBSD-src-c9cfc8e3226ba615d3221cb9c74e66d69b9c70c5.zip FreeBSD-src-c9cfc8e3226ba615d3221cb9c74e66d69b9c70c5.tar.gz |
Check ipfw table numbers in both user and kernel space before rule addition.
Found by: Saychik Pavel <umka@localka.net>
MFC after: 2 weeks
Sponsored by: Yandex LLC
-rw-r--r-- | sbin/ipfw/ipfw2.c | 45 | ||||
-rw-r--r-- | sbin/ipfw/ipfw2.h | 2 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_sockopt.c | 2 |
3 files changed, 38 insertions, 11 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 196067d..98b25b3 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -60,6 +60,8 @@ int resvd_set_number = RESVD_SET; int ipfw_socket = -1; +uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */ + #ifndef s6_addr32 #define s6_addr32 __u6_addr.__u6_addr32 #endif @@ -2203,6 +2205,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int cblen) { int len = 0; uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; + uint32_t tables_max; cmd->o.len &= ~F_LEN_MASK; /* zero len */ @@ -2221,6 +2224,10 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int cblen) *p++ = '\0'; cmd->o.opcode = O_IP_DST_LOOKUP; cmd->o.arg1 = strtoul(av + 6, NULL, 0); + tables_max = ipfw_get_tables_max(); + if (cmd->o.arg1 > tables_max) + errx(EX_USAGE, "The table number exceeds the maximum " + "allowed value (%u)", tables_max - 1); if (p) { cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); d[0] = strtoul(p, NULL, 0); @@ -4119,6 +4126,33 @@ static void table_list(uint16_t num, int need_header); static void table_fill_xentry(char *arg, ipfw_table_xentry *xent); /* + * Retrieve maximum number of tables supported by ipfw(4) module. + */ +uint32_t +ipfw_get_tables_max() +{ + size_t len; + uint32_t tables_max; + + if (ipfw_tables_max != 0) + return (ipfw_tables_max); + + len = sizeof(tables_max); + if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len, + NULL, 0) == -1) { + if (co.test_only) + tables_max = 128; /* Old conservative default */ + else + errx(1, "Can't determine maximum number of ipfw tables." + " Perhaps you forgot to load ipfw module?"); + } + + ipfw_tables_max = tables_max; + + return (ipfw_tables_max); +} + +/* * This one handles all table-related commands * ipfw table N add addr[/masklen] [value] * ipfw table N delete addr[/masklen] @@ -4131,19 +4165,10 @@ ipfw_table_handler(int ac, char *av[]) ipfw_table_xentry xent; int do_add; int is_all; - size_t len; uint32_t a; uint32_t tables_max; - len = sizeof(tables_max); - if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len, - NULL, 0) == -1) { - if (co.test_only) - tables_max = 128; /* Old conservative default */ - else - errx(1, "Can't determine maximum number of ipfw tables." - " Perhaps you forgot to load ipfw module?"); - } + tables_max = ipfw_get_tables_max(); memset(&xent, 0, sizeof(xent)); diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index d592930..2c70bbd 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -228,6 +228,8 @@ char const *match_value(struct _s_x *p, int value); int do_cmd(int optname, void *optval, uintptr_t optlen); +uint32_t ipfw_get_tables_max(void); + struct in6_addr; void n2mask(struct in6_addr *mask, int n); int contigmask(uint8_t *p, int len); diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 64f09a5..38ee2af 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -653,7 +653,7 @@ check_ipfw_struct(struct ip_fw *rule, int size) case O_IP_SRC_LOOKUP: case O_IP_DST_LOOKUP: - if (cmd->arg1 >= IPFW_TABLES_MAX) { + if (cmd->arg1 >= V_fw_tables_max) { printf("ipfw: invalid table number %d\n", cmd->arg1); return (EINVAL); |