Re: Question about to KMSAN: uninit-value in can_receive
From: Oliver Hartkopp
Date: Sat Nov 29 2025 - 12:04:29 EST
Hello Prithvi,
thanks for picking up this topic!
I had your mail in my open tabs and I was reading some code several times without having a really good idea how to continue.
On 17.11.25 18:30, Prithvi Tambewagh wrote:
The call trace suggests that the bug appears to be due to effect of change
in headroom by pskb_header_expand(). The new headroom remains uninitialized
and when can_receive tries accessing can_skb_prv(skb)->skbcnt, indirectly
skb->head is accessed which causes KMSAN uninitialized value read bug.
Yes.
If you take a look at the KMSAN message:
https://lore.kernel.org/linux-can/68bae75b.050a0220.192772.0190.GAE@xxxxxxxxxx/T/#m0372e223746b9da19cbf39348ab1cda52a5cfadc
I wonder why anybody is obviously fiddling with the with the skb->head here.
When initially creating skb for the CAN subsystem we use can_skb_reserve() which does a
skb_reserve(skb, sizeof(struct can_skb_priv));
so that we get some headroom for struct can_skb_priv.
Then we access this struct by referencing skb->head:
static inline struct can_skb_priv *can_skb_prv(struct sk_buff *skb)
{
return (struct can_skb_priv *)(skb->head);
}
If anybody is now extending the headroom skb->head will likely not pointing to struct can_skb_priv anymore, right?
To fix this bug, I think we can call can_dropped_invalid_skb() in can_rcv()
just before calling can_receive(). Further, we can add a condition for these
sk_buff with uninitialized headroom to initialize the skb, the way it had
been done in the patch for an earlier packet injection case in a similar
KMSAN bug:
https://lore.kernel.org/linux-can/20191207183418.28868-1-socketcan@xxxxxxxxxxxx/
No. This is definitely a wrong approach. You can not wildly poke values behind skb->head, when the correctly initialized struct can_skb_priv just sits somewhere else.
In opposite to the case in your referenced patch we do not get a skb from PF_PACKET but we handle a skb that has been properly created in isotp_sendmsg(). Including can_skb_reserve() and an initialized struct can_skb_priv.
However, I am not getting on what basis can I filter the sk_buff so that
only those with an uninitialized headroom will be initialized via this path.
Is this the correct approach?
No.
When we are creating CAN skbs with [can_]skb_reserve(), the struct can_skb_priv is located directly "before" the struct can_frame which is at skb->data.
I'm therefore currently thinking in the direction of using skb->data instead of skb->head as reference to struct can_skb_priv:
diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
index 1abc25a8d144..8822d7d2e3df 100644
--- a/include/linux/can/skb.h
+++ b/include/linux/can/skb.h
@@ -60,11 +60,11 @@ struct can_skb_priv {
struct can_frame cf[];
};
static inline struct can_skb_priv *can_skb_prv(struct sk_buff *skb)
{
- return (struct can_skb_priv *)(skb->head);
+ return (struct can_skb_priv *)(skb->data - sizeof(struct can_skb_priv));
}
static inline void can_skb_reserve(struct sk_buff *skb)
{
skb_reserve(skb, sizeof(struct can_skb_priv));
I have not checked what effect this might have to this patch
https://lore.kernel.org/linux-can/20191207183418.28868-1-socketcan@xxxxxxxxxxxx/
when we initialize struct can_skb_priv inside skbs we did not create in the CAN subsystem. The difference would be that we access struct can_skb_priv via skb->data and not via skb->head. The effect to the system should be similar.
What do you think about such approach?
Best regards,
Oliver