From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qk1-f180.google.com (mail-qk1-f180.google.com [209.85.222.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F08443C4555 for ; Tue, 12 May 2026 20:51:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.180 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778619083; cv=none; b=VHOan9JOgTKLTU4twRsEXsiC54yvLUc5NO9fC8EVRJ6PmY91+lk1WRE4Z9afh2FPmBfgazAXGcoZaCXW2dNNOg9GNL+eKlWcFfdghBvFXQotIkksqJ6KKrO281SxOmeraFtfF1DJvTrZcxQQcbrrqbLRPRtthC8kNo3/b2CuFb8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778619083; c=relaxed/simple; bh=DaExS6jVhCbFdfpu1jp+ptHK+FugGZYNQVrAif7iSd8=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=melEBYOhLrMJY9RuwDZGwrOHCKdDd8ajfNgPIcmlJaHTa8nnBNEPOcc1lSHLXdjPt8QtZhrC6fX7l8BM6WnTbs4xdZs49V2EmHYAGizRw+MfCr4X+xd37YuaPImjd8Nm+2eV4XJDJz/D/TartWmnQiXV5f5GWKBx0ZtQY4iK6yU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=q67Ia9mM; arc=none smtp.client-ip=209.85.222.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="q67Ia9mM" Received: by mail-qk1-f180.google.com with SMTP id af79cd13be357-8ea8563c693so646548485a.2 for ; Tue, 12 May 2026 13:51:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778619080; x=1779223880; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=XUMHU/SEZPYFwgbrY/+Ks3cr/YWBTknXiaWwRLGqhxk=; b=q67Ia9mMETYGr8O2ZyTVYha1e1u1W6iKNLtotcCxUeBF3OzAV/HYSRsXg50aw/ydCD 9RgOzehLJUIZqHDciV+zgf1Z+T9L0rBwVYnpjlwbFSIwUr5yE9pQ0tCipcgGDpUBVeIQ g4wAQSoVTSQd+Blz8eM4JDvPUdKVZ44eprrXnI+tzUcWsEn7IHV1niuUUYGU0jMDPVlo rN3ClC4UQhBAHDHKLLnGef6DGveSEDCy/lFThOWhZjW8kZk6d/QELHWANuPXX1AVEf+5 FmNaeMWbwNFp7+TjNLkF4QOuXFcVz8geOBF/WgnnzBIzLsTZNCPUC5T4AFOXPXTqzjQH DXHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778619080; x=1779223880; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=XUMHU/SEZPYFwgbrY/+Ks3cr/YWBTknXiaWwRLGqhxk=; b=owLPhLg36ZgmO9LgjwK+clDFnphiVynz5TfgigeDLYRjb0y95V42iTsglP90cnI8cR PdnU55k+QXCG3xFE3ExaHnYXhAyDV3VgbTYIjBFHCiHgmpHLIJqMD4cW2ET4QRSzdkrS QuyCE4+g9a+/4Dup0bM5Q7v6U0nD58yQ4TS0sA2waMFNkBHK4lQPcwyRL19FODxVlEKF HvSBziXdPCnRb1R1CUNUOHbO9x5zruZgsywWaQu3gNsffMGA0NOsFRtNBdi1sI/d4Lpb aG3wbdwnT/Eo28Knu0O4KVUtUZ9A8KmEEBZ3d6phVxmRsx/ICD/8E/XFfq9IxjR6QhKF TF7Q== X-Forwarded-Encrypted: i=1; AFNElJ8HnkSWtdTCgyJLyRh0HDmSqn+O6IxNZYyeBV9g04UcrhnOVy2E6ZWiYsyO3GKhasz79tnPfJY=@vger.kernel.org X-Gm-Message-State: AOJu0YyE+fUFg+7q9R2QSCus97MSaq7xRQdT8SEQ0pgIMUiEXjTYnDZm Br8WXSDtn0Q8kDy+VN2ovnHBlz7ptws7nXB8LJM94e7hlDWtK5eIqJSY X-Gm-Gg: Acq92OHDbX7QUglHo0xcFdRzXpkT0z0SWCKNwxTSMEKsFTFnH0DyGtXmGsGGLpx3xEy FpKkTOuYwnAFENd6O7y5P32rDf17KWjsc/T3Z48D8+u8HsYG/Slrh6vzt5ZdsfnPmOH/VFH1Phz GrpRoTLf0rdKMPVJ/uSerJb5RxWHOAVRVew9qS7HID4jmDwQBLFX32N1sohs6FyYgHdy4ObCgMJ yk0Zi8jIg+sYVklMBnl0zv4hvsnH5DmqUEZFXLw6nKEHdeu4ilRfm1rkZRb3gUMKkK0jJQPFVei 9z/vRSn43CHdQUUcXZ8HaAeqsU0keRYTB+bUZ1ndvI6J9ci93DVP/q2dCXP50KC+mGnHAocPery ZxtSi6B0zHF4RkrTOnEkxmVpoLeZepflIy5BikXSXmEuPbmaTqqcydLPAk9LEP4rDvZkop5gIhq xcu5eZKQFjtSt9YBKjbcULqFJXxL8UmgXYOCQPk6PfoS3EgoqaxLeggKp/GUmiApLeU33wvT7KR YANxvY9UDuMJqssxJ8YfKj3OrAfsH33KTdHK9kO9p0= X-Received: by 2002:a05:620a:7014:b0:8d9:3cb9:9905 with SMTP id af79cd13be357-90fade53b89mr6198085a.54.1778619079364; Tue, 12 May 2026 13:51:19 -0700 (PDT) Received: from server0.tail6e7dd.ts.net (c-68-48-65-54.hsd1.mi.comcast.net. [68.48.65.54]) by smtp.gmail.com with ESMTPSA id af79cd13be357-907b8d9eed0sm1490734285a.19.2026.05.12.13.51.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 May 2026 13:51:18 -0700 (PDT) From: Michael Bommarito To: Steffen Klassert , Herbert Xu , Eric Dumazet , netdev@vger.kernel.org Cc: "David S . Miller" , Jakub Kicinski , Paolo Abeni , Kuniyuki Iwashima , Maciej Zenczykowski , Kees Cook , Jeff Layton , "Gustavo A . R . Silva" , Pablo Neira Ayuso , Florian Westphal , netfilter-devel@vger.kernel.org, coreteam@netfilter.org, linux-kernel@vger.kernel.org Subject: [PATCH net 0/2] ipv4: harden against ihl < 5 IP_HDRINCL packets Date: Tue, 12 May 2026 16:51:13 -0400 Message-ID: X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit This series fixes a size_t underflow in net/ipv4/ah4.c:ah_output() reachable when a raw IP_HDRINCL socket sends a packet with ihl < 5 through an xfrm AH policy. Originally triaged on security@kernel.org; moving to netdev at Herbert's suggestion so nftables / netfilter maintainers can weigh in on a related question (see "Open question" below). Herbert also asked for the malformed packet to be rejected upstream of AH rather than guarded at the AH consumer; that is patch 1/2. v1's AH-side guard is kept here as 2/2 defense-in-depth. Bug --- In net/ipv4/ah4.c, ah_output_done() and ah_output() copy the IPv4 options area with if (top_iph->ihl != 5) { memcpy(dst, src, top_iph->ihl * 4 - sizeof(struct iphdr)); } The "!= 5" guard correctly excludes the no-options case but does NOT exclude ihl < 5. For ihl in [0, 4], top_iph->ihl * 4 is less than sizeof(struct iphdr) (20); the subtraction is computed as int and becomes negative, then is implicitly converted to size_t at the memcpy() call. The resulting length is close to SIZE_MAX and memcpy walks off the slab allocation backing the skb's network header. The malformed packet arrives via raw_send_hdrinc() in net/ipv4/raw.c. raw_send_hdrinc() validates "iphlen > length" but does not reject "iphlen < sizeof(struct iphdr)". An IP_HDRINCL caller with CAP_NET_RAW (acquirable in an unprivileged user+net namespace on a distro kernel with CONFIG_USER_NS=y) can therefore craft an ihl < 5 packet; if a matching xfrm AH policy is installed on the outgoing route, ah_output() runs on the crafted packet and panics the host kernel. The guard has been in place since 1da177e4c3f4 ("Linux-2.6.12-rc2", 2005). No prior fix on lore (3-year window) and no CVE on the file. Reproduction ------------ x86 + KASAN (QEMU KVM, net-next 7.1.0-rc2): BUG: KASAN: out-of-bounds in ah_output+0x696/0x19e0 Read of size 18446744073709551596 at addr ffff88800bae9824 \ by task trigger_ah4_ihl/97 Call Trace: __asan_memcpy+0x23/0x60 ah_output+0x696/0x19e0 xfrm_output_resume+0xdc8/0x6280 xfrm4_output+0xfe/0x4c0 raw_sendmsg+0x2531/0x26f0 __sys_sendto+0x32b/0x390 __x64_sys_sendto+0xdf/0x1f0 do_syscall_64+0xf3/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f The buggy address belongs to the object at ffff88800bae9800 which belongs to the cache kmalloc-1k of size 1024 The buggy address is located 36 bytes inside of 1024-byte region [ffff88800bae9800, ffff88800bae9c00) The read size 0xFFFFFFFFFFFFFFEC (SIZE_MAX - 19) is the underflowed result of (top_iph->ihl * 4 - sizeof(struct iphdr)) for ihl = 0. Trigger: veth pair (loopback bypasses xfrm_output), xfrm AH transport-mode policy, IP_HDRINCL sendto() of a 128-byte packet with iph->ihl in [0, 4]. A container-only variant (CAP_NET_ADMIN container, no --privileged, no host networking) panics the host kernel on a stock distro kernel with CONFIG_INET_AH=m + module autoload. Repro harness + container Dockerfile + console logs available privately on request; not attached to this public posting. Patches ------- 1/2 ipv4: raw: reject IP_HDRINCL packets with ihl < 5 Upstream-of-AH fix. An IPv4 header with ihl < 5 is malformed by definition (RFC 791) and must not be allowed to continue along the in-stack output path. This is the primary fix. 2/2 ipv4: ah: harden ah_output options-copy guard against ihl < 5 Defense-in-depth at the three memcpy sites in ah_output() and ah_output_done(). Changes "if (top_iph->ihl != 5)" to "if (top_iph->ihl > 5)" so a future path delivering an ihl < 5 packet cannot re-introduce the OOB access. With patch 1/2 in place an IP_HDRINCL-crafted ihl < 5 packet should no longer reach ah_output; this patch closes the OOB primitive specifically at the AH consumer. Open question for netfilter / netdev ------------------------------------ After patch 1/2 lands, a caller with CAP_NET_ADMIN can still deliver an ihl < 5 packet into the post-LOCAL_OUT in-stack path by attaching an nftables payload-set rule on NF_INET_LOCAL_OUT (or an NFQUEUE reinject on the same hook) that rewrites byte 0 of the IPv4 header after the raw_send_hdrinc / __ip_local_out validation has run. Construction: nft add table ip mangle nft add chain ip mangle output { type filter hook output \ priority -150 \; } nft add rule ip mangle output ip daddr \ @nh,0,8 set 0x40 I reproduced this separately with nftables payload-set delivering an ihl = 0 packet to xfrm4_output() and onward. Patch 2/2 covers the AH consumer; other consumers that read iph->ihl after the LOCAL_OUT hook may be similarly exposed and I have not enumerated them. Direction question rather than a fix proposal: does basic iphdr re-sanitization after a header-mangling hook belong in the netfilter machinery, in each in-stack consumer, or both? Michael Bommarito (2): ipv4: raw: reject IP_HDRINCL packets with ihl < 5 ipv4: ah: harden ah_output options-copy guard against ihl < 5 net/ipv4/ah4.c | 6 +++--- net/ipv4/raw.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) base-commit: 73d587ae684d176fac9db94173f77d78a794ea4f -- 2.53.0