Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: sched: ife: handle malformed tlv length

There is currently no handling to check on a invalid tlv length. This
patch adds such handling to avoid killing the kernel with a malformed
ife packet.

Signed-off-by: Alexander Aring <aring@mojatatu.com>
Reviewed-by: Yotam Gigi <yotam.gi@gmail.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Alexander Aring and committed by
David S. Miller
cc74eddd f6cd1453

+41 -4
+2 -1
include/net/ife.h
··· 12 12 void *ife_encode(struct sk_buff *skb, u16 metalen); 13 13 void *ife_decode(struct sk_buff *skb, u16 *metalen); 14 14 15 - void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen); 15 + void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype, 16 + u16 *dlen, u16 *totlen); 16 17 int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen, 17 18 const void *dval); 18 19
+33 -2
net/ife/ife.c
··· 92 92 __be16 len; 93 93 }; 94 94 95 + static bool __ife_tlv_meta_valid(const unsigned char *skbdata, 96 + const unsigned char *ifehdr_end) 97 + { 98 + const struct meta_tlvhdr *tlv; 99 + u16 tlvlen; 100 + 101 + if (unlikely(skbdata + sizeof(*tlv) > ifehdr_end)) 102 + return false; 103 + 104 + tlv = (const struct meta_tlvhdr *)skbdata; 105 + tlvlen = ntohs(tlv->len); 106 + 107 + /* tlv length field is inc header, check on minimum */ 108 + if (tlvlen < NLA_HDRLEN) 109 + return false; 110 + 111 + /* overflow by NLA_ALIGN check */ 112 + if (NLA_ALIGN(tlvlen) < tlvlen) 113 + return false; 114 + 115 + if (unlikely(skbdata + NLA_ALIGN(tlvlen) > ifehdr_end)) 116 + return false; 117 + 118 + return true; 119 + } 120 + 95 121 /* Caller takes care of presenting data in network order 96 122 */ 97 - void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen) 123 + void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype, 124 + u16 *dlen, u16 *totlen) 98 125 { 99 - struct meta_tlvhdr *tlv = (struct meta_tlvhdr *) skbdata; 126 + struct meta_tlvhdr *tlv; 100 127 128 + if (!__ife_tlv_meta_valid(skbdata, ifehdr_end)) 129 + return NULL; 130 + 131 + tlv = (struct meta_tlvhdr *)skbdata; 101 132 *dlen = ntohs(tlv->len) - NLA_HDRLEN; 102 133 *attrtype = ntohs(tlv->type); 103 134
+6 -1
net/sched/act_ife.c
··· 682 682 u16 mtype; 683 683 u16 dlen; 684 684 685 - curr_data = ife_tlv_meta_decode(tlv_data, &mtype, &dlen, NULL); 685 + curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype, 686 + &dlen, NULL); 687 + if (!curr_data) { 688 + qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); 689 + return TC_ACT_SHOT; 690 + } 686 691 687 692 if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) { 688 693 /* abuse overlimits to count when we receive metadata