From owner-freebsd-ipfw@FreeBSD.ORG Fri Dec 16 08:57:16 2005 Return-Path: X-Original-To: freebsd-ipfw@FreeBSD.org Delivered-To: freebsd-ipfw@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 69F9416A41F; Fri, 16 Dec 2005 08:57:16 +0000 (GMT) (envelope-from bu7cher@yandex.ru) Received: from mail.rdu.kirov.ru (ns.rdu.kirov.ru [217.9.151.217]) by mx1.FreeBSD.org (Postfix) with ESMTP id AA9AD43D45; Fri, 16 Dec 2005 08:56:08 +0000 (GMT) (envelope-from bu7cher@yandex.ru) Received: from kirov.so-cdu.ru (kirov [172.21.81.1]) by mail.rdu.kirov.ru (Postfix) with ESMTP id 7D17B33ABD; Fri, 16 Dec 2005 11:55:33 +0300 (MSK) Received: from kirov.so-cdu.ru (localhost [127.0.0.1]) by rdu.kirov.ru (Postfix) with SMTP id 5907B15CC0; Fri, 16 Dec 2005 11:55:33 +0300 (MSK) Received: by rdu.kirov.ru (Postfix, from userid 1014) id B843415CBF; Fri, 16 Dec 2005 11:55:32 +0300 (MSK) Received: from [172.21.81.52] (elsukov.kirov.so-cdu.ru [172.21.81.52]) by rdu.kirov.ru (Postfix) with ESMTP id 9817C15CA2; Fri, 16 Dec 2005 11:55:32 +0300 (MSK) Message-ID: <43A28104.7050407@yandex.ru> Date: Fri, 16 Dec 2005 11:55:32 +0300 From: "Andrey V. Elsukov" User-Agent: Thunderbird 1.5 (Windows/20051025) MIME-Version: 1.0 To: Maxim Konovalov References: <200512080626.jB86QxRl069343@freefall.freebsd.org> In-Reply-To: <200512080626.jB86QxRl069343@freefall.freebsd.org> Content-Type: multipart/mixed; boundary="------------020005090707060107070104" Cc: freebsd-ipfw@FreeBSD.org Subject: Re: kern/60154: [ipfw] ipfw core (crash) X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 Dec 2005 08:57:16 -0000 This is a multi-part message in MIME format. --------------020005090707060107070104 Content-Type: text/plain; charset=KOI8-R; format=flowed Content-Transfer-Encoding: 7bit Maxim Konovalov wrote: > Synopsis: [ipfw] ipfw core (crash) > http://www.freebsd.org/cgi/query-pr.cgi?pr=60154 I have updated patch and make the perl script for testing. -- WBR, Andrey V. Elsukov --------------020005090707060107070104 Content-Type: text/plain; name="test.pl" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="test.pl" #!/usr/local/bin/perl -w #=============================================================================== # # FILE: test.pl # DESCRIPTION: ipfw parser test # AUTHOR: (c) Andrey V. Elsukov, # CREATED: 16.12.2005 06:05:09 UTC #=============================================================================== use strict; sub result { if ($? == -1) { print "ipfw failed to execute: $!\n"; } elsif ($? & 127) { printf "ipfw died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with':'without'; } else { printf "ipfw exited with value %d\n", $? >> 8; } } sub ip($$) { my $dig = shift; my $separator = shift; my $str; $str .= "10.0.0.$_$separator" foreach(1..$dig-1); $str .= "10.0.0.$dig"; return $str; } sub port($$) { my $dig = shift; my $separator = shift; my $str; $str .= "$_$separator" foreach(1..$dig-1); $str .= $dig; return $str; } my $rule; my @cnt = (5, 10, 25, 50, 100, 250, 500); my @tests = ( { description => "protocols", rule => "allow {\$ } from any to any", func => \&port, separator => ' or ' }, { description => "source addresses (or block)", rule => "allow ip from { \$ } to any", func => \&ip, separator => ' or ' }, { description => "source addresses (list)", rule => "allow ip from { \$ } to any", func => \&ip, separator => ',' }, { description => "source addresses (sets)", rule => "allow ip from 10.0.0.0/24{\$} to any", func => \&port, separator => ',' }, { description => "source ports (list)", rule => "allow ip from 10.0.0.1 \$ to any", func => \&port, separator => ',' }, { description => "destination addresses (or block)", rule => "allow ip from any to { \$ }", func => \&ip, separator => ' or ' }, { description => "destination addresses (lists)", rule => "allow ip from any to { \$ }", func => \&ip, separator => ',' } ); foreach my $test (@tests) { print "Check with multiple ", $test->{description}, ":\n"; foreach my $c (@cnt) { print "try $c count ... "; my $rule = $test->{rule}; my $substr = $test->{func}($c, $test->{separator}); $rule =~ s/\$/$substr/; # print "ipfw -q add $rule\n"; system("ipfw -q add $rule"); &result(); } } --------------020005090707060107070104 Content-Type: text/plain; name="ipfw2.c.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ipfw2.c.diff" --- ipfw2.c.orig Tue Dec 13 12:16:02 2005 +++ ipfw2.c Fri Dec 16 11:39:44 2005 @@ -83,6 +83,26 @@ #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} /* + * Some functions here get as argumet an ipfw_insn pointer + * and fills him. This pointer typically stored in statical + * buffer with fixed size. And some ipfw_insn can have a + * variable size (for example, ipfw_insn_u16, ipfw_insn_u32,..). + * Free left space of this buffers do not controlled. + * As result we have some stange core dumps when user try + * add rules. To fix this errors we add the "size_left" + * paramter to thises functions. size_left indicates which + * size we can write into buffer. Before any writes we + * must check this size and update him after each write. + * + */ +#define CHECK_SIZE(size) \ + { \ + if ((int)(size_left - (size)) < 0) \ + errx(EX_DATAERR, "too big rule size\n"); \ + } +#define UPDATE_SIZE(size) size_left -= (size) + +/* * _s_x is a structure that stores a string <-> token pairs, used in * various places in the parser. Entries are stored in arrays, * with an entry with s=NULL as terminator. @@ -777,12 +797,14 @@ * Fill the body of the command with the list of port ranges. */ static int -fill_newports(ipfw_insn_u16 *cmd, char *av, int proto) +fill_newports(ipfw_insn_u16 *cmd, char *av, int proto, int size_left) { uint16_t a, b, *p = cmd->ports; int i = 0; char *s = av; + CHECK_SIZE(F_INSN_SIZE(*cmd)); + UPDATE_SIZE(F_INSN_SIZE(ipfw_insn)); while (*s) { a = strtoport(av, &s, 0, proto); if (s == av) /* no parameter */ @@ -802,12 +824,14 @@ i++; p += 2; av = s+1; - } - if (i > 0) { + /* sizeof(u_int16_t[2]) = sizeof(u_int32_t) */ + UPDATE_SIZE(F_INSN_SIZE(u_int32_t)); + CHECK_SIZE(F_INSN_SIZE(u_int32_t)); if (i+1 > F_LEN_MASK) errx(EX_DATAERR, "too many ports/ranges\n"); - cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */ } + if (i > 0) + cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */ return i; } @@ -1055,10 +1079,11 @@ } static void -fill_icmptypes(ipfw_insn_u32 *cmd, char *av) +fill_icmptypes(ipfw_insn_u32 *cmd, char *av, int size_left) { uint8_t type; + CHECK_SIZE(F_INSN_SIZE(*cmd)); cmd->d[0] = 0; while (*av) { if (*av == ',') @@ -1148,10 +1173,11 @@ } static void -fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) +fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int size_left) { uint8_t type; + CHECK_SIZE(F_INSN_SIZE(*cmd)); cmd->d[0] = 0; while (*av) { if (*av == ',') @@ -1217,11 +1243,12 @@ /* fills command for the extension header filtering */ int -fill_ext6hdr( ipfw_insn *cmd, char *av) +fill_ext6hdr( ipfw_insn *cmd, char *av, int size_left) { int tok; char *s = av; + CHECK_SIZE(F_INSN_SIZE(*cmd)); cmd->arg1 = 0; while(s) { @@ -2595,11 +2622,12 @@ * We can have multiple comma-separated address/mask entries. */ static void -fill_ip(ipfw_insn_ip *cmd, char *av) +fill_ip(ipfw_insn_ip *cmd, char *av, int size_left) { int len = 0; uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; + CHECK_SIZE(F_INSN_SIZE(ipfw_insn)); cmd->o.len &= ~F_LEN_MASK; /* zero len */ if (_substrcmp(av, "any") == 0) @@ -2610,6 +2638,7 @@ return; } + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_u32)); if (strncmp(av, "table(", 6) == 0) { char *p = strchr(av + 6, ','); @@ -2625,6 +2654,7 @@ return; } + UPDATE_SIZE(F_INSN_SIZE(ipfw_insn)); while (av) { /* * After the address we can have '/' or ':' indicating a mask, @@ -2695,6 +2725,7 @@ d[0] = ntohl(d[0]); /* base addr in host format */ cmd->o.opcode = O_IP_DST_SET; /* default */ cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; + CHECK_SIZE(cmd->o.len); for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) map[i] = 0; /* clear map */ @@ -2766,8 +2797,16 @@ cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); return; } - len += 2; /* two words... */ - d += 2; + len += F_INSN_SIZE(u_int32_t)*2; /* two words... */ + d += F_INSN_SIZE(u_int32_t)*2; + UPDATE_SIZE(F_INSN_SIZE(u_int32_t)*2); + CHECK_SIZE(F_INSN_SIZE(u_int32_t)*2); + /* + * O_IP_SRC_MASK and O_IP_DST_MASK can not have length + * greater that 31 + */ + if (len > 30) + errx(EX_DATAERR, "too many addresses\n"); } /* end while */ cmd->o.len |= len+1; } @@ -2824,7 +2863,7 @@ * Return 1 on success, 0 on failure. */ static int -fill_ip6(ipfw_insn_ip6 *cmd, char *av) +fill_ip6(ipfw_insn_ip6 *cmd, char *av, int size_left) { int len = 0; struct in6_addr *d = &(cmd->addr6); @@ -2833,6 +2872,7 @@ * Note d[1] points to struct in6_add r mask6 of cmd */ + CHECK_SIZE(F_INSN_SIZE(ipfw_insn)); cmd->o.len &= ~F_LEN_MASK; /* zero len */ if (strcmp(av, "any") == 0) @@ -2850,6 +2890,9 @@ } av = strdup(av); + + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_ip6)); + UPDATE_SIZE(F_INSN_SIZE(ipfw_insn)); while (av) { /* * After the address we can have '/' indicating a mask, @@ -2914,6 +2957,10 @@ /* Update length and pointer to arguments */ len += F_INSN_SIZE(struct in6_addr)*2; d += 2; + UPDATE_SIZE(F_INSN_SIZE(struct in6_addr)*2); + CHECK_SIZE(F_INSN_SIZE(struct in6_addr)*2); + if (len + 1 > F_LEN_MASK) + errx(EX_DATAERR, "too many addresses\n"); } /* end while */ /* @@ -2932,13 +2979,15 @@ * additional flow-id we want to filter, the basic is 1 */ void -fill_flow6( ipfw_insn_u32 *cmd, char *av ) +fill_flow6(ipfw_insn_u32 *cmd, char *av, int size_left) { u_int32_t type; /* Current flow number */ u_int16_t nflow = 0; /* Current flow index */ char *s = av; - cmd->d[0] = 0; /* Initializing the base number*/ + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_u32)); + UPDATE_SIZE(F_INSN_SIZE(ipfw_insn)); + cmd->d[0] = 0; /* Initializing the base number*/ while (s) { av = strsep( &s, ",") ; type = strtoul(av, &av, 0); @@ -2947,6 +2996,8 @@ if (type > 0xfffff) errx(EX_DATAERR, "flow number out of range %s", av); cmd->d[nflow] |= type; + UPDATE_SIZE(F_INSN_SIZE(u_int32_t)); + CHECK_SIZE(F_INSN_SIZE(u_int32_t)); nflow++; } if( nflow > 0 ) { @@ -2960,10 +3011,10 @@ } static ipfw_insn * -add_srcip6(ipfw_insn *cmd, char *av) +add_srcip6(ipfw_insn *cmd, char *av, int size_left) { - fill_ip6((ipfw_insn_ip6 *)cmd, av); + fill_ip6((ipfw_insn_ip6 *)cmd, av, size_left); if (F_LEN(cmd) == 0) /* any */ ; if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ @@ -2979,10 +3030,10 @@ } static ipfw_insn * -add_dstip6(ipfw_insn *cmd, char *av) +add_dstip6(ipfw_insn *cmd, char *av, int size_left) { - fill_ip6((ipfw_insn_ip6 *)cmd, av); + fill_ip6((ipfw_insn_ip6 *)cmd, av, size_left); if (F_LEN(cmd) == 0) /* any */ ; if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ @@ -3088,8 +3139,9 @@ * patterns which match interfaces. */ static void -fill_iface(ipfw_insn_if *cmd, char *arg) +fill_iface(ipfw_insn_if *cmd, char *arg, int size_left) { + CHECK_SIZE(F_INSN_SIZE(*cmd)); cmd->name[0] = '\0'; cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); @@ -3511,11 +3563,12 @@ * Takes arguments and copies them into a comment */ static void -fill_comment(ipfw_insn *cmd, int ac, char **av) +fill_comment(ipfw_insn *cmd, int ac, char **av, int size_left) { int i, l; char *p = (char *)(cmd + 1); + CHECK_SIZE(F_INSN_SIZE(*cmd)) cmd->opcode = O_NOP; cmd->len = (cmd->len & (F_NOT | F_OR)); @@ -3528,6 +3581,7 @@ errx(EX_DATAERR, "comment too long (max 80 chars)"); l = 1 + (l+3)/4; + CHECK_SIZE(l); cmd->len = (cmd->len & (F_NOT | F_OR)) | l; for (i = 0; i < ac; i++) { strcpy(p, av[i]); @@ -3554,10 +3608,11 @@ * two microinstructions, and returns the pointer to the last one. */ static ipfw_insn * -add_mac(ipfw_insn *cmd, int ac, char *av[]) +add_mac(ipfw_insn *cmd, int ac, char *av[], int size_left) { ipfw_insn_mac *mac; + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_mac)); if (ac < 2) errx(EX_DATAERR, "MAC dst src"); @@ -3571,12 +3626,14 @@ } static ipfw_insn * -add_mactype(ipfw_insn *cmd, int ac, char *av) +add_mactype(ipfw_insn *cmd, int ac, char *av, int size_left) { if (ac < 1) errx(EX_DATAERR, "missing MAC type"); if (strcmp(av, "any") != 0) { /* we have a non-null type */ - fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); + fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE, size_left); + if (F_LEN(cmd) > 31) + errx(EX_DATAERR, "too many MAC types\n"); cmd->opcode = O_MAC_TYPE; return cmd; } else @@ -3645,9 +3702,9 @@ } static ipfw_insn * -add_srcip(ipfw_insn *cmd, char *av) +add_srcip(ipfw_insn *cmd, char *av, int size_left) { - fill_ip((ipfw_insn_ip *)cmd, av); + fill_ip((ipfw_insn_ip *)cmd, av, size_left); if (cmd->opcode == O_IP_DST_SET) /* set */ cmd->opcode = O_IP_SRC_SET; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ @@ -3662,9 +3719,9 @@ } static ipfw_insn * -add_dstip(ipfw_insn *cmd, char *av) +add_dstip(ipfw_insn *cmd, char *av, int size_left) { - fill_ip((ipfw_insn_ip *)cmd, av); + fill_ip((ipfw_insn_ip *)cmd, av, size_left); if (cmd->opcode == O_IP_DST_SET) /* set */ ; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ @@ -3679,30 +3736,42 @@ } static ipfw_insn * -add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) +add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int size_left) { - if (_substrcmp(av, "any") == 0) { + if (_substrcmp(av, "any") == 0) return NULL; - } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { + + if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, size_left)) { /* XXX todo: check that we have a protocol with ports */ cmd->opcode = opcode; + if(F_LEN(cmd) > 31) + switch(opcode) { + case O_IPID: + case O_IPTTL: + case O_IPLEN: + case O_TCPDATALEN: + errx(EX_DATAERR, "too many options\n"); + case O_IP_SRCPORT: + case O_IP_DSTPORT: + errx(EX_DATAERR, "too many ports\n"); + }; return cmd; } return NULL; } static ipfw_insn * -add_src(ipfw_insn *cmd, char *av, u_char proto) +add_src(ipfw_insn *cmd, char *av, u_char proto, int size_left) { struct in6_addr a; if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || inet_pton(AF_INET6, av, &a)) - return add_srcip6(cmd, av); + return add_srcip6(cmd, av, size_left); /* XXX: should check for IPv4, not !IPv6 */ if (proto == IPPROTO_IP || strcmp(av, "me") == 0 || !inet_pton(AF_INET6, av, &a)) - return add_srcip(cmd, av); + return add_srcip(cmd, av, size_left); if (strcmp(av, "any") != 0) return cmd; @@ -3710,17 +3779,17 @@ } static ipfw_insn * -add_dst(ipfw_insn *cmd, char *av, u_char proto) +add_dst(ipfw_insn *cmd, char *av, u_char proto, int size_left) { struct in6_addr a; if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || inet_pton(AF_INET6, av, &a)) - return add_dstip6(cmd, av); + return add_dstip6(cmd, av, size_left); /* XXX: should check for IPv4, not !IPv6 */ if (proto == IPPROTO_IP || strcmp(av, "me") == 0 || !inet_pton(AF_INET6, av, &a)) - return add_dstip(cmd, av); + return add_dstip(cmd, av, size_left); if (strcmp(av, "any") != 0) return cmd; @@ -3748,7 +3817,11 @@ * Some things that need to go out of order (prob, action etc.) * go into actbuf[]. */ - static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; + +#define MAX_INSN 255 + static uint32_t rulebuf[MAX_INSN], actbuf[MAX_INSN], cmdbuf[MAX_INSN]; + int size_left = MAX_INSN; + int off; /* av offset */ ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; ipfw_insn *first_cmd; /* first match pattern */ @@ -3780,6 +3853,7 @@ action = (ipfw_insn *)actbuf; av++; ac--; + CHECK_SIZE(F_INSN_SIZE(struct ip_fw)); /* [rule N] -- Rule number optional */ if (ac && isdigit(**av)) { @@ -3797,12 +3871,15 @@ av += 2; ac -= 2; } + UPDATE_SIZE(F_INSN_SIZE(struct ip_fw) - F_INSN_SIZE(ipfw_insn)); /* [prob D] -- match probability, optional */ if (ac > 1 && _substrcmp(*av, "prob") == 0) { match_prob = strtod(av[1], NULL); if (match_prob <= 0 || match_prob > 1) errx(EX_DATAERR, "illegal match prob. %s", av[1]); + /* reserve size for O_PROB */ + UPDATE_SIZE(F_INSN_SIZE(ipfw_insn_u32)); av += 2; ac -= 2; } @@ -3810,7 +3887,8 @@ NEED1("missing action"); i = match_token(rule_actions, *av); ac--; av++; - action->len = 1; /* default */ + CHECK_SIZE(F_INSN_SIZE(ipfw_insn)); + action->len = F_INSN_SIZE(ipfw_insn); /* default */ switch(i) { case TOK_CHECKSTATE: have_state = action; @@ -3907,6 +3985,7 @@ char *s, *end; NEED1("missing forward address[:port]"); + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_sa)); action->opcode = O_FORWARD_IP; action->len = F_INSN_SIZE(ipfw_insn_sa); @@ -3942,6 +4021,8 @@ default: errx(EX_DATAERR, "invalid action %s\n", av[-1]); } + UPDATE_SIZE(action->len); + CHECK_SIZE(F_INSN_SIZE(ipfw_insn)); action = next_cmd(action); /* @@ -3962,6 +4043,7 @@ if (have_log) errx(EX_DATAERR, "log cannot be specified more than once"); + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_log)); have_log = (ipfw_insn *)c; cmd->len = F_INSN_SIZE(ipfw_insn_log); cmd->opcode = O_LOG; @@ -3992,6 +4074,7 @@ if (have_altq) errx(EX_DATAERR, "altq cannot be specified more than once"); + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_altq)); have_altq = (ipfw_insn *)a; cmd->len = F_INSN_SIZE(ipfw_insn_altq); cmd->opcode = O_ALTQ; @@ -4003,6 +4086,7 @@ default: abort(); } + UPDATE_SIZE(F_LEN(cmd)); cmd = next_cmd(cmd); } @@ -4016,9 +4100,9 @@ prev = NULL; \ open_par = 1; \ if ( (av[0])[1] == '\0') { \ - ac--; av++; \ + ac--; av++; off = 0; \ } else \ - (*av)++; \ + off = 1; \ } \ target: \ @@ -4044,6 +4128,7 @@ } #define OR_BLOCK(target) \ + off = 0; \ if (ac && _substrcmp(*av, "or") == 0) { \ if (prev == NULL || open_par == 0) \ errx(EX_DATAERR, "invalid OR block"); \ @@ -4084,9 +4169,11 @@ OR_START(get_proto); NOT_BLOCK; NEED1("missing protocol"); - if (add_proto_compat(cmd, *av, &proto)) { + CHECK_SIZE(F_INSN_SIZE(ipfw_insn)); + if (add_proto_compat(cmd, *av + off, &proto)) { av++; ac--; if (F_LEN(cmd) != 0) { + UPDATE_SIZE(F_LEN(cmd)); prev = cmd; cmd = next_cmd(cmd); } @@ -4109,9 +4196,10 @@ OR_START(source_ip); NOT_BLOCK; /* optional "not" */ NEED1("missing source address"); - if (add_src(cmd, *av, proto)) { + if (add_src(cmd, *av + off, proto, size_left)) { ac--; av++; if (F_LEN(cmd) != 0) { /* ! any */ + UPDATE_SIZE(F_LEN(cmd)); prev = cmd; cmd = next_cmd(cmd); } @@ -4125,12 +4213,14 @@ NOT_BLOCK; /* optional "not" */ if (ac) { if (_substrcmp(*av, "any") == 0 || - add_ports(cmd, *av, proto, O_IP_SRCPORT)) { + add_ports(cmd, *av, proto, O_IP_SRCPORT, size_left)) { ac--; av++; - if (F_LEN(cmd) != 0) + if (F_LEN(cmd) != 0) { + UPDATE_SIZE(F_LEN(cmd)); cmd = next_cmd(cmd); } } + } /* * "to", mandatory @@ -4145,9 +4235,10 @@ OR_START(dest_ip); NOT_BLOCK; /* optional "not" */ NEED1("missing dst address"); - if (add_dst(cmd, *av, proto)) { + if (add_dst(cmd, *av + off, proto, size_left)) { ac--; av++; if (F_LEN(cmd) != 0) { /* ! any */ + UPDATE_SIZE(F_LEN(cmd)); prev = cmd; cmd = next_cmd(cmd); } @@ -4161,12 +4252,14 @@ NOT_BLOCK; /* optional "not" */ if (ac) { if (_substrcmp(*av, "any") == 0 || - add_ports(cmd, *av, proto, O_IP_DSTPORT)) { + add_ports(cmd, *av, proto, O_IP_DSTPORT, size_left)) { ac--; av++; - if (F_LEN(cmd) != 0) + if (F_LEN(cmd) != 0) { + UPDATE_SIZE(F_LEN(cmd)); cmd = next_cmd(cmd); } } + } read_options: if (ac && first_cmd == cmd) { @@ -4184,6 +4277,8 @@ s = *av; cmd32 = (ipfw_insn_u32 *)cmd; + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_u32)); + if (*s == '!') { /* alternate syntax for NOT */ if (cmd->len & F_NOT) errx(EX_USAGE, "double \"not\" not allowed\n"); @@ -4252,7 +4347,7 @@ case TOK_VIA: NEED1("recv, xmit, via require interface name" " or address"); - fill_iface((ipfw_insn_if *)cmd, av[0]); + fill_iface((ipfw_insn_if *)cmd, av[0], size_left); ac--; av++; if (F_LEN(cmd) == 0) /* not a valid address */ break; @@ -4266,20 +4361,20 @@ case TOK_ICMPTYPES: NEED1("icmptypes requires list of types"); - fill_icmptypes((ipfw_insn_u32 *)cmd, *av); + fill_icmptypes((ipfw_insn_u32 *)cmd, *av, size_left); av++; ac--; break; case TOK_ICMP6TYPES: NEED1("icmptypes requires list of types"); - fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); + fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av, size_left); av++; ac--; break; case TOK_IPTTL: NEED1("ipttl requires TTL"); if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_IPTTL)) + if (!add_ports(cmd, *av, 0, O_IPTTL, size_left)) errx(EX_DATAERR, "invalid ipttl %s", *av); } else fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); @@ -4289,7 +4384,7 @@ case TOK_IPID: NEED1("ipid requires id"); if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_IPID)) + if (!add_ports(cmd, *av, 0, O_IPID, size_left)) errx(EX_DATAERR, "invalid ipid %s", *av); } else fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); @@ -4299,7 +4394,7 @@ case TOK_IPLEN: NEED1("iplen requires length"); if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_IPLEN)) + if (!add_ports(cmd, *av, 0, O_IPLEN, size_left)) errx(EX_DATAERR, "invalid ip len %s", *av); } else fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); @@ -4395,7 +4490,7 @@ case TOK_TCPDATALEN: NEED1("tcpdatalen requires length"); if (strpbrk(*av, "-,")) { - if (!add_ports(cmd, *av, 0, O_TCPDATALEN)) + if (!add_ports(cmd, *av, 0, O_TCPDATALEN, size_left)) errx(EX_DATAERR, "invalid tcpdata len %s", *av); } else fill_cmd(cmd, O_TCPDATALEN, 0, @@ -4451,6 +4546,7 @@ errx(EX_USAGE, "only one of keep-state " "and limit is allowed"); NEED1("limit needs mask and # of connections"); + CHECK_SIZE(F_INSN_SIZE(ipfw_insn_limit)); have_state = cmd; { ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; @@ -4488,28 +4584,28 @@ case TOK_SRCIP: NEED1("missing source IP"); - if (add_srcip(cmd, *av)) { + if (add_srcip(cmd, *av, size_left)) { ac--; av++; } break; case TOK_DSTIP: NEED1("missing destination IP"); - if (add_dstip(cmd, *av)) { + if (add_dstip(cmd, *av, size_left)) { ac--; av++; } break; case TOK_SRCIP6: NEED1("missing source IP6"); - if (add_srcip6(cmd, *av)) { + if (add_srcip6(cmd, *av, size_left)) { ac--; av++; } break; case TOK_DSTIP6: NEED1("missing destination IP6"); - if (add_dstip6(cmd, *av)) { + if (add_dstip6(cmd, *av, size_left)) { ac--; av++; } break; @@ -4517,7 +4613,7 @@ case TOK_SRCPORT: NEED1("missing source port"); if (_substrcmp(*av, "any") == 0 || - add_ports(cmd, *av, proto, O_IP_SRCPORT)) { + add_ports(cmd, *av, proto, O_IP_SRCPORT, size_left)) { ac--; av++; } else errx(EX_DATAERR, "invalid source port %s", *av); @@ -4526,7 +4622,7 @@ case TOK_DSTPORT: NEED1("missing destination port"); if (_substrcmp(*av, "any") == 0 || - add_ports(cmd, *av, proto, O_IP_DSTPORT)) { + add_ports(cmd, *av, proto, O_IP_DSTPORT, size_left)) { ac--; av++; } else errx(EX_DATAERR, "invalid destination port %s", @@ -4534,14 +4630,14 @@ break; case TOK_MAC: - if (add_mac(cmd, ac, av)) { + if (add_mac(cmd, ac, av, size_left)) { ac -= 2; av += 2; } break; case TOK_MACTYPE: NEED1("missing mac type"); - if (!add_mactype(cmd, ac, *av)) + if (!add_mactype(cmd, ac, *av, size_left)) errx(EX_DATAERR, "invalid mac type %s", *av); ac--; av++; break; @@ -4571,7 +4667,7 @@ break; case TOK_EXT6HDR: - fill_ext6hdr( cmd, *av ); + fill_ext6hdr(cmd, *av, size_left); ac--; av++; break; @@ -4579,12 +4675,12 @@ if (proto != IPPROTO_IPV6 ) errx( EX_USAGE, "flow-id filter is active " "only for ipv6 protocol\n"); - fill_flow6( (ipfw_insn_u32 *) cmd, *av ); + fill_flow6((ipfw_insn_u32 *)cmd, *av, size_left); ac--; av++; break; case TOK_COMMENT: - fill_comment(cmd, ac, av); + fill_comment(cmd, ac, av, size_left); av += ac; ac = 0; break; @@ -4593,6 +4689,7 @@ errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); } if (F_LEN(cmd) > 0) { /* prepare to advance */ + UPDATE_SIZE(F_LEN(cmd)); prev = cmd; cmd = next_cmd(cmd); } --------------020005090707060107070104--