diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-07-25 11:41:35 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-07-25 12:49:35 +0200 |
commit | 4b6df760e3b19ec522b66cbbb5b280fec7c0405b (patch) | |
tree | c649ed518e701d0f8d4ef8deb56afe6c3b20e40a | |
parent | d4dbc65c965cb4d94fb5967095e7aa1713ca57c6 (diff) |
conntrack: fix autogenerated BPF code for IPv6 filtering
BPF code generated for IPv6 filtering was wrong.
Assuming you want to allow all traffic except ::1, the filter that
libnetfilter_conntrack generates for the IPv6 address part looks like:
[...]
(0032) code= BPF_LD|BPF_W|BPF_IND jt=00 jf=00 k=00000004
(0033) code= BPF_ALU|BPF_AND|BPF_K jt=00 jf=00 k=ffffffff
(0034) code= BPF_JMP|BPF_JEQ|BPF_K jt=00 jf=0a k=00000000
(0035) code= BPF_LD|BPF_W|BPF_IND jt=00 jf=00 k=00000008 [0]
(0036) code= BPF_ALU|BPF_AND|BPF_K jt=00 jf=00 k=ffffffff [1]
(0037) code= BPF_JMP|BPF_JEQ|BPF_K jt=00 jf=07 k=00000000 [2]
(0038) code= BPF_LD|BPF_W|BPF_IND jt=00 jf=00 k=0000000c [3]
(0039) code= BPF_ALU|BPF_AND|BPF_K jt=00 jf=00 k=ffffffff [4]
(003a) code= BPF_JMP|BPF_JEQ|BPF_K jt=00 jf=04 k=00000000 [5]
(003b) code= BPF_LD|BPF_W|BPF_IND jt=00 jf=00 k=00000010 [6]
(003c) code= BPF_ALU|BPF_AND|BPF_K jt=00 jf=00 k=ffffffff [7]
(003d) code= BPF_JMP|BPF_JEQ|BPF_K jt=01 jf=00 k=00000001 [8]
(003e) code= BPF_JMP|BPF_JA jt=00 jf=00 k=00000001 [9]
(003f) code= BPF_RET|BPF_K jt=00 jf=00 k=00000000 [A]
Line 32 loads the first 4 bytes for the 32 bytes IPv6 address, then
line 33 performs the binary AND with the first 4 bytes of the mask.
Line 34 evaluated false for the case 2::1 that Eric reported (since 0x2
is not 0x0). Thus, jumping to line 3f that returns reject. However,
2::1 should be allowed.
This false-jump case depends on the logic we're using, for the negative
logic case, the jump offset is 9 to accept it. In the positive case
(ie. accept this event message if matching happens), it has to be 10 (A),
to reject it.
Reported-by: Eric Leblond <eric@regit.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | src/conntrack/bsf.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/src/conntrack/bsf.c b/src/conntrack/bsf.c index 846b6f9..c14531e 100644 --- a/src/conntrack/bsf.c +++ b/src/conntrack/bsf.c @@ -562,7 +562,7 @@ bsf_add_addr_ipv6_filter(const struct nfct_filter *f, unsigned int type) { unsigned int i, j, dir, attr; - unsigned int label_continue, jf; + unsigned int label_continue[2], jf; struct stack *s; struct jump jmp; @@ -591,21 +591,24 @@ bsf_add_addr_ipv6_filter(const struct nfct_filter *f, } jf = 1; - if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE) - label_continue = 1; - else - label_continue = 2; + if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE) { + label_continue[0] = 1; + label_continue[1] = 2; + } else { + label_continue[0] = 2; + label_continue[1] = 1; + } j = 0; j += nfct_bsf_load_payload_offset(this, j); j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j); - j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s); + j += nfct_bsf_cmp_k_stack(this, 0, label_continue[0] - j, j, s); /* no need to access attribute payload, we are using nest-based finder * j += nfct_bsf_add_attr_data_offset(this, j); */ j += nfct_bsf_find_attr_nest(this, CTA_TUPLE_IP, j); - j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s); + j += nfct_bsf_cmp_k_stack(this, 0, label_continue[0] - j, j, s); j += nfct_bsf_find_attr_nest(this, type, j); - j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s); + j += nfct_bsf_cmp_k_stack(this, 0, label_continue[0] - j, j, s); j += nfct_bsf_x_equal_a(this, j); for (i = 0; i < f->l3proto_elems_ipv6[dir]; i++) { @@ -621,7 +624,8 @@ bsf_add_addr_ipv6_filter(const struct nfct_filter *f, j); if (k < 3) { j += nfct_bsf_cmp_k_stack_jf(this, ip, - jf - j, j, s); + jf - j - label_continue[1], + j, s); } else { /* last word: jump if true */ j += nfct_bsf_cmp_k_stack(this, ip, jf - j, |