Bug 912782 - Any traffic allowed by default zone is allowed in all other zones
Summary: Any traffic allowed by default zone is allowed in all other zones
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Fedora
Classification: Fedora
Component: firewalld
Version: 18
Hardware: All
OS: Linux
high
urgent
Target Milestone: ---
Assignee: Thomas Woerner
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2013-02-19 16:36 UTC by Quentin Armitage
Modified: 2013-03-16 01:42 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2013-03-16 01:42:11 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
Patch to stop default zone rules being applied to all zones (586 bytes, patch)
2013-02-19 16:36 UTC, Quentin Armitage
no flags Details | Diff
list of FORWARD chains from iptables -nvL (5.53 KB, text/plain)
2013-03-04 08:43 UTC, Leoš Bitto
no flags Details
suggested patch (2.63 KB, patch)
2013-03-06 16:39 UTC, Jiri Popelka
no flags Details | Diff

Description Quentin Armitage 2013-02-19 16:36:25 UTC
Created attachment 699520 [details]
Patch to stop default zone rules being applied to all zones

Description of problem:
Any traffic allowed in the default zone is allowed in all other zones unless explicitly denied in the relevent zone.

Likewise any traffic denied in the default zone is denied in all other zones unless explicitly allowed in the relevent zone.

Version-Release number of selected component (if applicable):
firewalld-0.2.12-2.fc18.noarch

How reproducible:
Always

Steps to Reproduce:
1. For example: 
# firewall-cmd --zone=public --list-services
mdns dhcpv6-client ssh
# firewall-cmd --zone=home --list-services
ipp-client mdns dhcpv6-client ssh samba-client

2. From another host, attempt using ftp to an interface in the home zone:
# ftp 192.168.0.10
ftp: connect: No route to host

3. Add ftp as allowed service in public zone:
# firewall-cmd --zone=public --add-service=ftp

4. Again attempt to connect from another host to ftp via i/f in home zone
# ftp 192.168.0.10
Connected to 192.168.0.10 (192.168.0.10).
220 (vsFTPd 3.0.2)
Name (192.168.0.10:username): 
  
Actual results:
ftp access is permitted via interface in home zone although ftp service is not permitted in home zone.

Expected results:
ftp access denied.

Additional info:

The ftp connection was being made via eth0.50.

The reason the ftp access is permitted is due to the last entry in the INPUT_ZONES chain (see below). The way the chain is constructed is that each entry is checked in turn, even after the relevant interface has been matched. The "+" for the in interface in the last entry matches all interfaces, and so the IN_ZONE_public is called for all interfaces, unless the traffic has already been allowed or denied.

Chain INPUT_ZONES (1 references)
 pkts bytes target     prot opt in     out     source               destination         
  988  107K IN_ZONE_public  all  --  eth1   *       0.0.0.0/0            0.0.0.0/0           
  856 78652 IN_ZONE_home  all  --  eth0.50 *       0.0.0.0/0            0.0.0.0/0           
           0.0.0.0/0           
 5461  514K IN_ZONE_public  all  --  +      *       0.0.0.0/0            0.0.0.0/0         

Not only is the above checking the public zone configuration for all zones, it is unnecessary to check subsequent entries in the chain once it has matched the interface. Rather than doing a JUMP (-j), it would be better to use a GOTO (-g) (it stops the final rule matching for all zones, and is more efficient).

If this change is made, the final entry matching "+" is unnecessary, since explicit rules are created for all interfaces. It may be that the entry is there as a backstop in case for some reason a rule has not been created for a zone, but in that case the safe and secure approach would be to drop or reject the traffic, which will happen by default if the rule with + for the interface is omitted.

The same applies for the FORWARD_ZONES chain.

The attached patch changes the JUMPs to GOTOs in the INPUT_ZONES and FORWARD_ZONES chains, which fixes the problem identified, and improves the efficiency. The patch does not remove the final entry (two for FORWARD_ZONES) since I haven't worked out how to do that yet.

Comment 1 Jiri Popelka 2013-02-20 15:26:48 UTC
Thank you for the thorough investigation and description !

(In reply to comment #0)
> Created attachment 699520 [details]
> Patch to stop default zone rules being applied to all zones

Pushed upstream
http://git.fedorahosted.org/cgit/firewalld.git/commit/?id=3253df596ab6f5e43d22dff3049600fc0de9c41b

with a little tweak:
 for example trusted zone has default target ACCEPT, which makes a
 '-A INPUT_ZONES -i <iface> -j ACCEPT' rule. We can't use -g ACCEPT therefore I've added that condition.
 
> If this change is made, the final entry matching "+" is unnecessary, since
> explicit rules are created for all interfaces. It may be that the entry is
> there as a backstop in case for some reason a rule has not been created for
> a zone, but in that case the safe and secure approach would be to drop or
> reject the traffic, which will happen by default if the rule with + for the
> interface is omitted.

This was added with
http://git.fedorahosted.org/cgit/firewalld.git/commit/?id=4ec98e390102b5c065f7b2855204e01c08af88c1
See for example bug #882736, comment #5 or bug #821938, comment #5 for background.

> The patch does not remove the final entry (two for
> FORWARD_ZONES) since I haven't worked out how to do that yet.

You'd need to remove this piece of code
http://git.fedorahosted.org/cgit/firewalld.git/commit/?id=8b7a4902b5c248bb03570d8a6d143d7f75972f29
but I'm afraid we need it ;-)

Comment 2 Fedora Update System 2013-02-20 15:41:32 UTC
firewalld-0.2.12-3.fc18 has been submitted as an update for Fedora 18.
https://admin.fedoraproject.org/updates/firewalld-0.2.12-3.fc18

Comment 3 Fedora Update System 2013-02-21 05:51:10 UTC
Package firewalld-0.2.12-3.fc18:
* should fix your issue,
* was pushed to the Fedora 18 testing repository,
* should be available at your local mirror within two days.
Update it with:
# su -c 'yum update --enablerepo=updates-testing firewalld-0.2.12-3.fc18'
as soon as you are able to.
Please go to the following url:
https://admin.fedoraproject.org/updates/FEDORA-2013-2827/firewalld-0.2.12-3.fc18
then log in and leave karma (feedback).

Comment 4 Fedora Update System 2013-03-02 20:18:48 UTC
firewalld-0.2.12-3.fc18 has been pushed to the Fedora 18 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 5 Leoš Bitto 2013-03-04 08:36:40 UTC
Yum update to firewalld-0.2.12-3.fc18 broke my pretty basic setup with only two ethernet interfaces: one internal (private IPv4 address) and one external (public IPv4 address) with IP masquerading. There seems to be missng some "-j ACCEPT" rule when going from the internal to the external interface. I "fixed" it with "firewall-cmd --direct --passthrough ipv4 -I FORWARD -j ACCEPT".

Comment 6 Leoš Bitto 2013-03-04 08:43:51 UTC
Created attachment 704807 [details]
list of FORWARD chains from iptables -nvL

Check the attached file broken-firewalld-0.2.12-3.fc18.txt - please note that the first rule in the FORWARD chain is the result of "firewall-cmd --direct --passthrough ipv4 -I FORWARD -j ACCEPT" which I had to add to make the IP masquerading work. I have <masquerade enabled="Yes"/> in /etc/firewalld/zones/external.xml and that was enough to make it work before firewalld-0.2.12-3.fc18.

Comment 7 Quentin Armitage 2013-03-04 10:34:39 UTC
Leoš,

The change from jump to goto, although it fixed the problem reported, has introduced a problem in the FORWARD processing, as you identify.

The problem is with the following chain:
Chain FORWARD_ZONES (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FWDI_ZONE_internal  all  --  eth0   *       0.0.0.0/0            0.0.0.0/0           [goto] 
    0     0 FWDO_ZONE_internal  all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           [goto] 
    0     0 FWDI_ZONE_external  all  --  eth1   *       0.0.0.0/0            0.0.0.0/0           [goto] 
    0     0 FWDO_ZONE_external  all  --  *      eth1    0.0.0.0/0            0.0.0.0/0           [goto] 
    0     0 FWDO_ZONE_public  all  --  *      +       0.0.0.0/0            0.0.0.0/0           [goto] 
    0     0 FWDI_ZONE_public  all  --  +      *       0.0.0.0/0            0.0.0.0/0           [goto] 

The [goto] entries mean the if, or example, a packet matches on eth0 input, then it will not check the out entry for eth1.

The only way I can see to make this work would be the following iptables commands:

iptables -Z FORWARD_ZONES
iptables -A FORWARD_ZONES -i eth0 -j FWDI_ZONE_internal
iptables -A FORWARD_ZONES -o eth0 -j FWDO_ZONE_internal
iptables -A FORWARD_ZONES -i eth1 -j FWDI_ZONE_external
iptables -A FORWARD_ZONES -o eth1 -j FWDO_ZONE_external
iptables -A FORWARD_ZONES -i eth0 -j RETURN
iptables -A FORWARD_ZONES -o eth0 -j RETURN
iptables -A FORWARD_ZONES -i eth1 -j RETURN
iptables -A FORWARD_ZONES -o eth1 -j RETURN
iptables -A FORWARD_ZONES -o + -j FWDO_ZONE_public
iptables -A FORWARD_ZONES -i + -j FWDI_ZONE_public

This would then look like:

Chain FORWARD_ZONES (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FWDI_ZONE_internal  all  --  eth0   *       0.0.0.0/0            0.0.0.0/0 
    0     0 FWDO_ZONE_internal  all  --  *      eth0    0.0.0.0/0            0.0.0.0/0
    0     0 FWDI_ZONE_external  all  --  eth1   *       0.0.0.0/0            0.0.0.0/0  
    0     0 FWDO_ZONE_external  all  --  *      eth1    0.0.0.0/0            0.0.0.0/0
    0     0 RETURN     all  --  eth0   *       0.0.0.0/0            0.0.0.0/0 
    0     0 RETURN     all  --  *      eth0    0.0.0.0/0            0.0.0.0/0
    0     0 RETURN     all  --  eth1   *       0.0.0.0/0            0.0.0.0/0  
    0     0 RETURN     all  --  *      eth1    0.0.0.0/0            0.0.0.0/0
    0     0 FWDO_ZONE_public  all  --  *      +       0.0.0.0/0            0.0.0.0/0 
    0     0 FWDI_ZONE_public  all  --  +      *       0.0.0.0/0            0.0.0.0/0  

The same approach could be taken for the INPUT_ZONES and OUTPUT_ZONES chains, but with a loss of efficiency compared to the gotos.

Comment 8 Leoš Bitto 2013-03-04 10:55:23 UTC
Quentin,

I was happily composing my own iptables rules before firewalld existed, and I guess that I will have to revert to that again. "rpm -e firewalld" seems to be the key command I need to execute.

Another weirdness - why are there these two last rules in the FORWARD chain?

    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited 

This explains why traceroute was working for me, but everything else was not. That is just plain wrong...

Comment 9 Quentin Armitage 2013-03-05 00:38:59 UTC
Further to my comment #c7, on further investigation I cannot see any way to configure rules to be added into the FWDI_ZONE_* and FWDO_ZONE_* chains, although the full structure of the chains is set up.

The changes I have outlined above are necessary though since the rule that allows outgoing traffic to the external zone is the ACCEPT in the FWDO_ZONE_external chain, and with the rules as they are that is never reached following the goto to FWDI_ZONE_external.

Is it correct that it is not possible to configure allowing forwarding other than traffic forwarded out on the external zone?

I also overlooked in my previous comment that there are no equivalent chains for filtering OUTPUT packets and so the comment regarding OUTPUT_ZONES isn't relevant.

Comment 10 Jiri Popelka 2013-03-05 18:34:38 UTC
Thomas has suggested:

-A FORWARD_ZONES -i eth1 -j FWDI_ZONE_external
-A FORWARD_ZONES -o eth1 -g FWDO_ZONE_external
-A FORWARD_ZONES -i eth0 -j FWDI_ZONE_internal
-A FORWARD_ZONES -o eth0 -g FWDO_ZONE_internal

that way we wouldn't need the -j RETURN

The patch would be something like:
src/firewall/core/fw_zone.py @@ -275
- action = "-g" if "_ZONE_" in target else "-j"
+ action = "-g" if ("_ZONE_" in target and "FWDI" not in target) else "-j"

What do you think Quentin ?

Comment 11 Quentin Armitage 2013-03-06 03:08:54 UTC
Jiri,

Unfortunately I don't think that works.

Consider the situation where a packet comes in on eth0 and goes out on eth1; the 3rd rule, covering the packet incoming, will not be hit due to the goto in the second rule.

An alternative that is closer would be:

-A FORWARD_ZONES -i eth1 -j FWDI_ZONE_external
-A FORWARD_ZONES -i eth0 -j FWDI_ZONE_internal
-A FORWARD_ZONES -o eth1 -g FWDO_ZONE_external
-A FORWARD_ZONES -o eth0 -g FWDO_ZONE_internal

so all the checks in one direction are done first with a jump, and then a goto for the second direction. This would ensure that the two chains that are supposed to be called are indeed called. The problem with this is that if a packet comes in on an interface other than eth0 or eth1, but leaves on, say eth1, then the final two rules, viz

iptables -A FORWARD_ZONES -o + -j FWDO_ZONE_public
iptables -A FORWARD_ZONES -i + -j FWDI_ZONE_public

won't get hit, which I understand from earlier comments are needed. However, as per my initial bug report, it is essential that these last two rules aren't hit for a packet direction for which there has already been a match.

Having thought about it further, my original suggestion in comment #7 has the same problem. I think what is needed is
iptables -A FORWARD_ZONES -j FWDI_ZONES
iptables -A FORWARD_ZONES -g FWDO_ZONES
iptables -A FWDI_ZONES -i eth0 -g FWDI_ZONE_internal
iptables -A FWDO_ZONES -o eth0 -g FWDO_ZONE_internal
iptables -A FWDI_ZONES -i eth1 -g FWDI_ZONE_external
iptables -A FWDO_ZONES -o eth1 -g FWDO_ZONE_external
iptables -A FWDI_ZONES -i + -g FWDI_ZONE_public
iptables -A FWDO_ZONES -o + -g FWDO_ZONE_public

The above is probably the sequence you would want to generate it, but it would result in the following (note the one JUMP, the remaining are GOTOs):

Chain FORWARD_ZONES (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FWDI_ZONES all  --  *      *       0.0.0.0/0            0.0.0.0/0 
    0     0 FWDO_ZONES all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]

Chain FWDI_ZONES (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FWDI_ZONE_internal  all  --  eth0   *       0.0.0.0/0            0.0.0.0/0           [goto] 
    0     0 FWDI_ZONE_external  all  --  eth1   *       0.0.0.0/0            0.0.0.0/0           [goto]  
    0     0 FWDI_ZONE_public  all  --  +      *       0.0.0.0/0            0.0.0.0/0           [goto]  

Chain FWDO_ZONES (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FWDO_ZONE_internal  all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           [goto]
    0     0 FWDO_ZONE_external  all  --  *      eth1    0.0.0.0/0            0.0.0.0/0           [goto]
    0     0 FWDO_ZONE_public  all  --  *      +       0.0.0.0/0            0.0.0.0/0           [goto] 

I think that's about as neat as its going to get.

As an aside, can you confirm whether I am right that at the moment, using the GUI or firewall-cmd, there is no way to configure any rules for forwarding, or for OUTPUT, in other words it isn't possible to generate any entries for the chains we are discussing above?

Comment 12 Jiri Popelka 2013-03-06 16:39:52 UTC
Created attachment 706135 [details]
suggested patch

Great idea !

This patch creates the following rules:

-A FORWARD -j FORWARD_IN_ZONES
-A FORWARD -j FORWARD_OUT_ZONES
-A FORWARD_IN_ZONES -i eth1 -g FWDI_ZONE_external
-A FORWARD_IN_ZONES -i eth0 -g FWDI_ZONE_internal
-A FORWARD_IN_ZONES -g FWDI_ZONE_public
-A FORWARD_OUT_ZONES -o eth1 -g FWDO_ZONE_external
-A FORWARD_OUT_ZONES -o eth0 -g FWDO_ZONE_internal
-A FORWARD_OUT_ZONES -g FWDO_ZONE_public

which should be basically the same as you suggested.

Comment 13 Jiri Popelka 2013-03-06 16:41:36 UTC
(In reply to comment #11)
> there is no way to configure any rules for
> forwarding, or for OUTPUT, in other words it isn't possible to generate any
> entries for the chains we are discussing above?

I think no, there's no way yet, but I may be wrong. Thomas ?

Comment 14 Quentin Armitage 2013-03-06 17:11:19 UTC
(In reply to comment #12)
> Created attachment 706135 [details]
> suggested patch
> 
> Great idea !
> 
> This patch creates the following rules:
> 
> -A FORWARD -j FORWARD_IN_ZONES
> -A FORWARD -j FORWARD_OUT_ZONES
> -A FORWARD_IN_ZONES -i eth1 -g FWDI_ZONE_external
> -A FORWARD_IN_ZONES -i eth0 -g FWDI_ZONE_internal
> -A FORWARD_IN_ZONES -g FWDI_ZONE_public
> -A FORWARD_OUT_ZONES -o eth1 -g FWDO_ZONE_external
> -A FORWARD_OUT_ZONES -o eth0 -g FWDO_ZONE_internal
> -A FORWARD_OUT_ZONES -g FWDO_ZONE_public
> 
> which should be basically the same as you suggested.

That looks good to me. It's nice to see the "+"s not there, since they are acting as "*", and the only other change as I see it is a change of the zone names that I used.

Comment 15 Fedora Update System 2013-03-07 10:08:14 UTC
firewalld-0.2.12-4.fc18 has been submitted as an update for Fedora 18.
https://admin.fedoraproject.org/updates/firewalld-0.2.12-4.fc18

Comment 16 Fedora Update System 2013-03-08 00:01:30 UTC
Package firewalld-0.2.12-4.fc18:
* should fix your issue,
* was pushed to the Fedora 18 testing repository,
* should be available at your local mirror within two days.
Update it with:
# su -c 'yum update --enablerepo=updates-testing firewalld-0.2.12-4.fc18'
as soon as you are able to.
Please go to the following url:
https://admin.fedoraproject.org/updates/FEDORA-2013-3535/firewalld-0.2.12-4.fc18
then log in and leave karma (feedback).

Comment 17 Fedora Update System 2013-03-16 01:42:13 UTC
firewalld-0.2.12-4.fc18 has been pushed to the Fedora 18 stable repository.  If problems still persist, please make note of it in this bug report.


Note You need to log in before you can comment on or make changes to this bug.