Thread (11 messages) flat view 11 messages, 4 authors, 1d ago

Re: [PATCH net 4/4] drop_monitor: fix out-of-bounds write in reset_per_cpu_data()

From: Eric Dumazet <edumazet@google.com>
Date: 2026-09-12 14:46:36

On Fri, Sep 11, 2026 at 2:08 PM [off-list ref] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 · Low: 0

- [Medium] Commit message overstates the impact: the pre-patch memset()
  in reset_per_cpu_data() (net/core/drop_monitor.c:165) is NOT an out-…

--

drop_monitor: fix out-of-bounds write in reset_per_cpu_data()

The patch stops adding sizeof(struct nlattr) to al in
reset_per_cpu_data(), and instead allocates the skb with
genlmsg_new(nla_total_size(al), GFP_KERNEL) so that al describes only the
attribute payload that is later zeroed via memset(msg, 0, al).
quoted
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index 795c15dd1771a..edc660778408e 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -141,9 +141,8 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)

      al = sizeof(struct net_dm_alert_msg);
      al += dm_hit_limit * sizeof(struct net_dm_drop_point);
-     al += sizeof(struct nlattr);

-     skb = genlmsg_new(al, GFP_KERNEL);
+     skb = genlmsg_new(nla_total_size(al), GFP_KERNEL);
[Severity: Medium]
Is the impact described in the changelog accurate?  The subject says "fix
out-of-bounds write", and the body says the memset() is

    exceeding the allocated buffer by sizeof(struct nlattr) (4 bytes) and
    corrupting skb_shared_info.

With the in-tree constants, dm_hit_limit is a fixed "static int
dm_hit_limit = 64" with no module_param and no way for userspace to change
it, sizeof(struct net_dm_alert_msg) is 4 and sizeof(struct
net_dm_drop_point) is 12, so the old al was 4 + 768 + 4 = 776.

That gives genlmsg_new(776) -> nlmsg_new(780) -> alloc_skb(796), and with
nlmsghdr [0,16), genlmsghdr [16,20) and the nlattr header [20,24), msg sits
at offset 24 and memset(msg, 0, 776) writes up to offset 800, i.e. 4 bytes
past the 796 bytes that were requested.

But the head buffer that gets allocated is larger than the request, and
skb_shared_info is placed at the end of the rounded-up zone:

net/core/skbuff.c:kmalloc_reserve() {
        ...
        obj_size = SKB_HEAD_ALIGN(*size);
        ...
        obj_size = kmalloc_size_roundup(obj_size);
        *size = (unsigned int)obj_size;
}

net/core/skbuff.c:__alloc_skb() {
        ...
        /* kmalloc_size_roundup() might give us more room than requested.
         * Put skb_shared_info exactly at the end of allocated zone,
         * to allow max possible filling before reallocation.
         */
        __finalize_skb_around(skb, data, size);
}

For a 796-byte request SKB_HEAD_ALIGN(796) is 832 + 320 = 1152, which
kmalloc_size_roundup() rounds to 2048, so skb->end lands near offset 1728
and the 4 extra zeroed bytes fall in unused tailroom.  KASAN would also not
report anything, since kmalloc is called with the already-rounded size.  The
small-head-cache path gives *size = SKB_SMALL_HEAD_CACHE_SIZE, which is also
comfortably above 800.

Also, nla_total_size(772) is 776, exactly the previous genlmsg_new()
argument, so the allocation size is unchanged by this patch; only the memset
length shrinks from 776 to 772, which matches the usable payload (796 - 24 =
772 = 4 + 64 * 12) and the fill limit enforced in trace_drop_common().

The code change itself looks correct, but with the Fixes: 683703a26e46 tag
this will be picked up for stable and CVE triage as an out-of-bounds write.
Could the changelog be reworded to describe it as a size-accounting cleanup,
and to drop the claim about corrupting skb_shared_info?
This feedback is quite shocking and annoying.

Do I need to double check everything and make precise computations?

No, I do not.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help