Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 16 Dec 2005 11:55:32 +0300
From:      "Andrey V. Elsukov" <bu7cher@yandex.ru>
To:        Maxim Konovalov <maxim@FreeBSD.org>
Cc:        freebsd-ipfw@FreeBSD.org
Subject:   Re: kern/60154: [ipfw] ipfw core (crash)
Message-ID:  <43A28104.7050407@yandex.ru>
In-Reply-To: <200512080626.jB86QxRl069343@freefall.freebsd.org>
References:  <200512080626.jB86QxRl069343@freefall.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
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, <bu7cher@yandex.ru>
#      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--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?43A28104.7050407>