aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Aring <aring@mojatatu.com>2018-04-20 15:15:04 -0400
committerDavid S. Miller <davem@davemloft.net>2018-04-22 21:12:00 -0400
commitcc74eddd0ff325d57373cea99f642b787d7f76f5 (patch)
treefc8048a8254e5d249763543e20355a0bba0324f1
parentf6cd14537ff9919081be19b9c53b9b19c0d3ea97 (diff)
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>
-rw-r--r--include/net/ife.h3
-rw-r--r--net/ife/ife.c35
-rw-r--r--net/sched/act_ife.c7
3 files changed, 41 insertions, 4 deletions
diff --git a/include/net/ife.h b/include/net/ife.h
index 44b9c00f7223..e117617e3c34 100644
--- a/include/net/ife.h
+++ b/include/net/ife.h
@@ -12,7 +12,8 @@
12void *ife_encode(struct sk_buff *skb, u16 metalen); 12void *ife_encode(struct sk_buff *skb, u16 metalen);
13void *ife_decode(struct sk_buff *skb, u16 *metalen); 13void *ife_decode(struct sk_buff *skb, u16 *metalen);
14 14
15void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen); 15void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype,
16 u16 *dlen, u16 *totlen);
16int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen, 17int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen,
17 const void *dval); 18 const void *dval);
18 19
diff --git a/net/ife/ife.c b/net/ife/ife.c
index 7d1ec76e7f43..7fbe70a0af4b 100644
--- a/net/ife/ife.c
+++ b/net/ife/ife.c
@@ -92,12 +92,43 @@ struct meta_tlvhdr {
92 __be16 len; 92 __be16 len;
93}; 93};
94 94
95static 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/* Caller takes care of presenting data in network order 121/* Caller takes care of presenting data in network order
96 */ 122 */
97void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen) 123void *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;
127
128 if (!__ife_tlv_meta_valid(skbdata, ifehdr_end))
129 return NULL;
100 130
131 tlv = (struct meta_tlvhdr *)skbdata;
101 *dlen = ntohs(tlv->len) - NLA_HDRLEN; 132 *dlen = ntohs(tlv->len) - NLA_HDRLEN;
102 *attrtype = ntohs(tlv->type); 133 *attrtype = ntohs(tlv->type);
103 134
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 49b8ab551fbe..8527cfdc446d 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -682,7 +682,12 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
682 u16 mtype; 682 u16 mtype;
683 u16 dlen; 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 if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) { 692 if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) {
688 /* abuse overlimits to count when we receive metadata 693 /* abuse overlimits to count when we receive metadata