mirror of
https://github.com/torvalds/linux.git
synced 2026-10-04 18:29:02 +02:00
net/sched: act_ife: validate metadata length before decoding
skbmark_decode(), skbprio_decode() and skbtcindex_decode() read fixed-size values from the TLV payload without validating its length. A malformed IFE frame can declare a shorter payload, causing the decoders to consume bytes beyond the declared metadata value: [TLV type=IFE_META_SKBMARK len=4] -> dlen == 0, but decode reads 4 bytes The decoder may therefore set skb metadata from unintended input. Validate the payload length before decoding and return -EINVAL for invalid lengths. Read the values with get_unaligned_be32() and get_unaligned_be16(), as TLV payloads are not guaranteed to be aligned. Teach tcf_ife_decode() to log a decoder error separately from an unknown metaid; both are counted as overlimits and decoding continues with the remaining metadata. The metadata length issue was found by an automated audit of the IFE decode path at v6.18-rc7 and reproduced with a userspace sanitizer model of the decode path. Compile-tested on x86_64 with defconfig and NET_ACT_IFE=y: act_ife.o and the three act_meta_*.o build warning-free. Fixes:084e2f6566("Support to encoding decoding skb mark on IFE action") Fixes:200e10f469("Support to encoding decoding skb prio on IFE action") Fixes:408fbc22ef("net sched ife action: Introduce skb tcindex metadata encap decap") Assisted-by: Hawkeye:GLM-5.3-flash Assisted-by: Qoder:Qwen3.8-Max Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com> Link: https://patch.msgid.link/20260921125441.81459-1-fangxy@xiaopeng.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
c2de369c5c
commit
d6ec384c87
|
|
@ -737,6 +737,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
|
|||
u8 *curr_data;
|
||||
u16 mtype;
|
||||
u16 dlen;
|
||||
int ret;
|
||||
|
||||
curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype,
|
||||
&dlen, NULL);
|
||||
|
|
@ -745,13 +746,19 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
|
|||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
||||
if (find_decode_metaid(skb, p, mtype, dlen, curr_data)) {
|
||||
/* abuse overlimits to count when we receive metadata
|
||||
* but dont have an ops for it
|
||||
ret = find_decode_metaid(skb, p, mtype, dlen, curr_data);
|
||||
if (ret < 0) {
|
||||
/* abuse overlimits to count metadata we cannot
|
||||
* decode: no ops for it, or the decoder rejected it
|
||||
*/
|
||||
pr_info_ratelimited("Unknown metaid %d dlen %d\n",
|
||||
mtype, dlen);
|
||||
qstats_cpu_overlimit_inc(ife->common.cpu_qstats);
|
||||
|
||||
if (ret == -ENOENT)
|
||||
pr_info_ratelimited("Unknown metaid %d dlen %d\n",
|
||||
mtype, dlen);
|
||||
else
|
||||
pr_info_ratelimited("Failed to decode metaid %d dlen %d err %d\n",
|
||||
mtype, dlen, ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -28,9 +29,10 @@ static int skbmark_encode(struct sk_buff *skb, void *skbdata,
|
|||
|
||||
static int skbmark_decode(struct sk_buff *skb, void *data, u16 len)
|
||||
{
|
||||
u32 ifemark = *(u32 *)data;
|
||||
if (len != sizeof(u32))
|
||||
return -EINVAL;
|
||||
|
||||
skb->mark = ntohl(ifemark);
|
||||
skb->mark = get_unaligned_be32(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -33,9 +34,10 @@ static int skbprio_encode(struct sk_buff *skb, void *skbdata,
|
|||
|
||||
static int skbprio_decode(struct sk_buff *skb, void *data, u16 len)
|
||||
{
|
||||
u32 ifeprio = *(u32 *)data;
|
||||
if (len != sizeof(u32))
|
||||
return -EINVAL;
|
||||
|
||||
skb->priority = ntohl(ifeprio);
|
||||
skb->priority = get_unaligned_be32(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -28,9 +29,10 @@ static int skbtcindex_encode(struct sk_buff *skb, void *skbdata,
|
|||
|
||||
static int skbtcindex_decode(struct sk_buff *skb, void *data, u16 len)
|
||||
{
|
||||
u16 ifetc_index = *(u16 *)data;
|
||||
if (len != sizeof(u16))
|
||||
return -EINVAL;
|
||||
|
||||
skb->tc_index = ntohs(ifetc_index);
|
||||
skb->tc_index = get_unaligned_be16(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user