From owner-freebsd-security@FreeBSD.ORG Tue Jul 29 00:25:24 2008 Return-Path: Delivered-To: freebsd-security@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8E9011065676 for ; Tue, 29 Jul 2008 00:25:24 +0000 (UTC) (envelope-from jeff+freebsd@wagsky.com) Received: from mail.wagsky.com (wildside.wagsky.com [64.220.148.97]) by mx1.freebsd.org (Postfix) with ESMTP id 308D68FC13 for ; Tue, 29 Jul 2008 00:25:24 +0000 (UTC) (envelope-from jeff+freebsd@wagsky.com) Received: from port5.pn.wagsky.com (port5.pn.wagsky.com [192.168.6.5]) by mail.wagsky.com (Postfix) with ESMTPSA id 6D19D28445; Mon, 28 Jul 2008 17:07:53 -0700 (PDT) Message-ID: <488E5F5A.3050209@wagsky.com> Date: Mon, 28 Jul 2008 17:07:54 -0700 From: Jeff Kletsky User-Agent: Thunderbird 2.0.0.16 (Macintosh/20080707) MIME-Version: 1.0 To: freebsd-security@freebsd.org Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Subject: ipfw "bug" - recv any = not recv any X-BeenThere: freebsd-security@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Security issues \[members-only posting\]" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 29 Jul 2008 00:25:24 -0000 I hesitate to call this a "bug" as I don't know all the history behind the ipfw2 decisions, so let me toss this out there and see I'm just missing something. Overview ======== The negated operator, "not recv any" was taken to mean "any packet never received by an interface" believed to be equivalent to "any packet that originated on the current machine's interfaces" My logic being: * If "recv any" means "received by any interface" * then "not recv any" means "not received by any interface" (which should be locally-generated packets) In practice, both "recv any" and "not recv any" appear to be "no-op" phrases. Application was to be able to discriminate between: * Packets from the current host that are going out (and need stateful rules of the form my.outside.IP <==> some.rest.of.world.host) * Packets received from "inside" hosts that had been NAT-ed (and need to be let out without another stateful rule, as one was created when the packet was received of the form my.private.net.IP <==> some.rest.of.world.host) Agreed, there are ways to solve this in ipfw2 (tagging, for one), but the issue is that there is at least one "reasonable" application for the phrase and that the behavior is not what one might expect, in a potentially dangerous way. To replicate ============ 1) Identify a "blank" rule [root@wildside /etc/firewall]# ipfw list 20000 ipfw: rule 20000 does not exist 2) create a rule that does not modify traffic, but logs matches, using "not recv any" [root@wildside /etc/firewall]# ipfw add 20000 count all from any to any out not recv any 20000 count ip from any to any out 2a) Expect that (2) would have indication that "not recv any" was present 3) delete the rule just created and create another that is identical, but without the "not" modifier [root@wildside /etc/firewall]# ipfw delete 20000 [root@wildside /etc/firewall]# ipfw add 20000 count all from any to any out recv any 20000 count ip from any to any out 3a) Note that the generated rule is the same (enabling logging confirms that both "recv any" and "not recv any" appear to be NOOPs) Discussion ========== I didn't find much here, but did dig up an older post that looked to be discussing this kind of thing > From: Patrick O'Reilly > Date: 11 Mar 2001 23:47:44 In my opinion, the following would be "ideal" 1) "recv any" -- matches packets that have been received by the host through one of its interfaces 2) "not recv any" -- does not match packets that have been received by the host through one of its interfaces Unfortunately, implementing (1) would likely break a lot of people's rule sets (2), however, I can't immediately see being used without expecting that it would fail to match packets that were received by the current host, so its implementation would be a bit "safer" for the community I took a quick look at the code, as Patrick's message suggests matching "NULL" > Likewise, Rod Grimes suggested: > ------------------ > No, but it should be trivial to patch the code to allow your !any, if > you consider that !any is the same as =null: > > ipfw count ip from any to any in recv null > > Ie, the recv keyword looks at the ifp in the mbuff, the ifp will be null > for packets originated on the local machine. /usr/src/sys/netinet/ip_fw2.c -- seemed to be the place, but the start of the s/r that caught my eye is not immediately suggesting that there is a way to match a null ifp without patching code as its trapped before the check is done static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd) { if (ifp == NULL) /* no iface with this packet, match fails */ return 0; /* Check by name or by IP address */ if (cmd->name[0] != '\0') { /* match by name */ /* Check name */ if (cmd->p.glob) { if (fnmatch(cmd->name, ifp->if_xname, 0) == 0) return(1); } else { if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) return(1); } Thoughts? Worth more than just a doc change? Thanks for the time, Jeff