diff options
author | Guy Harris <guy@alum.mit.edu> | 2018-10-23 20:29:05 -0700 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2018-10-23 20:29:05 -0700 |
commit | 71abe040fa49dfcb8ba3e08e5f21896b0c7cc6e8 (patch) | |
tree | 520fccb102947f787cb839515a3a6099add0f85e | |
parent | 2954b59a01a2e5f5a3305e900659e9f2807cc875 (diff) | |
download | libpcap-71abe040fa49dfcb8ba3e08e5f21896b0c7cc6e8.tar.gz |
Report an error for MPLS labels that don't fit in 20 bits.
Also, make the label an unsigned value, with a separate argument to
gen_mpls() to indicate whether we *have* a label value to test; this
prevents "mpls 0xFFFFFFFF" from being treated as equivalent to "mpls"
just because (on 2's complement machines; we make no effort to support
other types) 32-bit -1 and 32-bit 0xFFFFFFFF have the same bit pattern.
Credit to OSS-Fuzz for finding this issue (which showed up as an invalid
shift of a signed value, shifting into the sign bit; making the shift
value unsigned avoids that headache).
-rw-r--r-- | gencode.c | 8 | ||||
-rw-r--r-- | gencode.h | 2 | ||||
-rw-r--r-- | grammar.y | 4 |
3 files changed, 9 insertions, 5 deletions
@@ -8574,7 +8574,7 @@ gen_vlan(compiler_state_t *cstate, int vlan_num) * support for MPLS */ struct block * -gen_mpls(compiler_state_t *cstate, int label_num) +gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num, int has_label_num) { struct block *b0, *b1; @@ -8612,7 +8612,11 @@ gen_mpls(compiler_state_t *cstate, int label_num) } /* If a specific MPLS label is requested, check it */ - if (label_num >= 0) { + if (has_label_num) { + if (label_num > 0xFFFFF) { + bpf_error(cstate, "MPLS label %u greater than maximum %u", + label_num, 0xFFFFF); + } label_num = label_num << 12; /* label is shifted 12 bits on the wire */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */ @@ -325,7 +325,7 @@ struct block *gen_llc_s_subtype(compiler_state_t *, bpf_u_int32); struct block *gen_llc_u_subtype(compiler_state_t *, bpf_u_int32); struct block *gen_vlan(compiler_state_t *, int); -struct block *gen_mpls(compiler_state_t *, int); +struct block *gen_mpls(compiler_state_t *, bpf_u_int32, int); struct block *gen_pppoed(compiler_state_t *); struct block *gen_pppoes(compiler_state_t *, int); @@ -550,8 +550,8 @@ other: pqual TK_BROADCAST { $$ = gen_broadcast(cstate, $1); } | OUTBOUND { $$ = gen_inbound(cstate, 1); } | VLAN pnum { $$ = gen_vlan(cstate, $2); } | VLAN { $$ = gen_vlan(cstate, -1); } - | MPLS pnum { $$ = gen_mpls(cstate, $2); } - | MPLS { $$ = gen_mpls(cstate, -1); } + | MPLS pnum { $$ = gen_mpls(cstate, (bpf_u_int32)$2, 1); } + | MPLS { $$ = gen_mpls(cstate, 0, 0); } | PPPOED { $$ = gen_pppoed(cstate); } | PPPOES pnum { $$ = gen_pppoes(cstate, $2); } | PPPOES { $$ = gen_pppoes(cstate, -1); } |