netfilter firewalling problems and solutions

Dagmar d'Surreal dagmar.wants at
Tue Feb 17 09:09:05 PST 2004

Okay, I'm going to take the problems I know about and solve them one at
a time, with explanations as to why...  Sorry for the delay in posting
this...  (note that there will be a distinct lack of code in this email,
see previous email)

#1. Netfilter needs to implement a deny-by-default policy, but currently
no hook exists in the init.d scripts.  

    Seeing as how this is atomically tied to the initialization of the
network, I suspect the best place for this is simply going to be by
patching the init.d/network script to execute the seven or so lines it
takes to set the default policy to deny, to dump all rules and wipe all
chains (in that order) before going on to initialize any interfaces. 
(The same thing should also be done when bringing down the interfaces). 
This *would* be a problem for service daemons, since we'll need to have
rules for them, but when the interfaces are down, many of them crash
and/or die the next time they look at their sockets, so it's not as if
doing an init.d/network stop && init.d/network start is as trouble-free
as it would first appear.  (People who do this by using telinit to
change to runlevel 2, and back again will not have this problem, which
is the cleanest way to do that anyway).  The only inobvious thing here
is that at this time we should also (on multiple interface boxen) build
a chain for each interface for INPUT, FORWARD, and OUTPUT for the sake
of optimizing filter flow.  (I should probably break this last bit out
into it's own justification bullet-point)

#2. We may have interfaces which need to be initialized using DHCP and a
default drop policy will prevent this from happening (although there are
circumstances with older kernels in which this wouldn't actually happen
with some DHCP implementations).

  Well, since I scribbled together the service/dhclient script in about
two minutes and we know the interface name at that time, there's no
reason we can't add a hook into service/dhclient to add the two allow
rules necessary to facilitate DHCP requests and responses, tied to that
interface.   Since we'll have already added our chains in
init.d/network, the rules can be dropped into the proper chain.  The
script should also flush and destroy the custom chains after a dhclient
-r for network stop.  (*1)

#3. Handling service daemons is slightly more complex in that each is
likely to need a few rules of it's own.

  While it might seem more convenient to lob all of these rules into one
script so they are all in the same place, their existence is atomically
tied to the active presence of a service daemon.  For this reason we're
better off putting rules to allow each activity into the init.d script
for that daemon.  Starting them at this time means that all our IP
addresses should be available (and identifiable) allowing us to be more
specific in our rules.  It doesn't appear that we will run into trouble
with windows of opportunity since our default policies will still be
DROP from before the interfaces are brought up.

#4. Admins may use the kill command to stop daemons, or they may die,
and be started (quite properly) by invoking init.d/whateverservice
start, while firewalling rules are already present to allow their
traffic, duplicating existing firewalling rules.

  Since there is no case in which the daemon should be running before
the init.d/whateverservice start script is invoked, until we start
adding surefire checks into these to avoid starting the same service
when it's already running, the simplest (and probably best) solution to
this is to run a set of rule deletions for that service prior to adding
the allow rules for it.

#5. Something may have broken and netfilter may not currently be
available for the kernel on boot-up (administrator error, filesystem
corruption, malicious user, etc), leaving the possibility that services
may start without firewall rules to limit their access.

  This is a pretty serious issue.  For this reason, we should probably
be checking the exit status of all rule insert/appends (although not for
any rule deletions or flushes, since these can exit with non-zero status
without actually indicating a show-stopper) and bail with exit status 1
if an error occurs.  Lack of in-kernel firewalling (even for a
particular type of traffic, for example, if someone oopses and forgets
to add TCP support to netfilter) when the configuration expects
netfilter to be available should be considered a show-stopper and
require immediate administrative intervention ...however the machine
should not _stop_ booting entirely, but continue so that the
administrator can login to a console to fix things.

#6. Even though a service daemon may be chrooted, it could still be
compromised and the uid used to make connections to other machines on
our network or on other networks.

  Thankfully netfilter has a facility that allows it to see which
uid/gid is tied to traffic on the local machine.  We can use this to our
advantage in the case of things like bind, where we can not only add
allow rules to let it query external nameservers, but limit it so that
it _only_ be used to talk to external nameservers.  This is going to
require a little more complexity than some people are used to, but is
good stuff for implementing mandatory controls.  If the default policy
is to DROP packets, then using "--uid-owner named" when we add the allow
rule will prevent say, squid's role account from being used to exploit
remote nameservers either externally or internally on our network
without a complete root compromise.  Obversely, a nameserver making
queries to the internet and serving queries to the intranet might not
have any reason whatsoever to be initiating nameservice queries to
anything on the intranet.  This specific a rule can also be applied to
the localhost interface to (for example) restrict service daemons
ability to access other service daemons (again, squid would have no
business talking to portmap, but could be allowed to make nameservice
queries on the localhost interface).  -m owner should be used whenever
we can do so cleanly.  (...although this seems really anal-retentive, it
still appears to add value to the configuration.  Don't think these
kinds of exploits don't happen.  I've seen all of this in the past year
at least once.)

Note that what I'm laying out here is _not_ as simple as the use of
fwbuilder would be compatible with, but since we're hardening existing
systems (and services) and not just throwing stuff in, we can IMHO
afford to be quite a bit more precise about in what order and when
things get done.

I will attempt to create patches against BLFS for as much as I can, but
in the case of some services, BLFS isn't as anal about things as we can
probably get away with and it may make sense to simply publish
replacements for some of their init.d scripts.  Once I'm totally
satisfied with the way my service firewall is functioning I'll start
posting my versions of the actual code that implements these directives.
Something that's also bugging me at the moment is that LFS puts ifconfig
into /usr/sbin (or so it seems) in net-tools.  After double-checking
that I've not overlooked something, we should get them to change that so
it goes into /sbin (functionality increase being that remotely mounting
/usr is then doable, same goes for iptables in BLFS) and for the
meantime assume that iptables and friends are in /sbin instead of
/usr/sbin.  This would also be more in accord with the FHS.  (Nevermind,
I'll take care of this now)

*1 - At some point, some right-thinking person might wish to simplify
some of this by putting together a wrapper script that takes less arcane
options to create filtering rules, like `scriptname allow echo on
eth0`.  If they want to see it adopted by lots of people, the surefire
thing will be to add something a bit more complex than the norm so that
a new /etc/service-groups file can be scanned to facilitate something
like service *groups* named http-server, http-query, dns-server,
dns-query, ping, etc which would need otherwise require multiple rules
at a time.  hint hint *kof*I'm too qlazy*kof* hint hint
The email address above is phony because my penis is already large enough, kthx. 
              AIM: evilDagmar  Jabber: evilDagmar at

More information about the hlfs-dev mailing list