From: Guy Harris Date: Wed, 24 Oct 2018 03:29:05 +0000 (-0700) Subject: Report an error for MPLS labels that don't fit in 20 bits. X-Git-Tag: libpcap-1.10-bp~756 X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/71abe040fa49dfcb8ba3e08e5f21896b0c7cc6e8 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). --- diff --git a/gencode.c b/gencode.c index 95a3ef95..09f72d43 100644 --- a/gencode.c +++ b/gencode.c @@ -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 */ diff --git a/gencode.h b/gencode.h index a8199002..287e9b9a 100644 --- a/gencode.h +++ b/gencode.h @@ -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); diff --git a/grammar.y b/grammar.y index e3883b53..dfaa6d86 100644 --- a/grammar.y +++ b/grammar.y @@ -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); }