Add interim mitigations for CVE-2026-98432 #691

Merged
greg merged 2 commits from chore/mptcp into master 2026-10-31 10:49:14 +00:00
4 changed files with 86 additions and 1 deletions

No files matched your search

+1 -1
Submodule nodes updated: ee04075fbc...5378c7ffc0.
@@ -0,0 +1,78 @@
#
# Cookbook:: kosmos-base
# Recipe:: cve_2026_98432
#
# Interim mitigations for CVE-2026-98432: a use-after-free in the Linux IPv4
# TCP option handling (inet_opt/ireq_opt are freed with a plain kfree()) that
# is reachable by sending a TCP SYN carrying IP options. No fixed kernel has
# been released for Ubuntu yet, so until every host runs a patched kernel we:
#
# 1. drop inbound IPv4 TCP segments that carry IP options (no legitimate
# traffic uses them), and
# 2. disable Multipath TCP where the running kernel supports it, so that Go
# programs built with Go >= 1.24 (e.g. node_exporter) stop opening MPTCP
# listeners - the precondition of the published exploit.
#
# This recipe (and the matching change in kosmos_prometheus::node_exporter) can
# be removed once all hosts run a kernel containing the fix.
#
# --- 1. Drop inbound IPv4 TCP segments that carry IP options ----------------
#
# ufw rebuilds its ruleset from /etc/ufw/before.rules on every start/reload, so
# the restriction has to live in that file to survive. The u32 expression
# `0&0x0F000000=0x05000000` matches a segment whose IP header length (IHL) is
# 5, i.e. one *without* IP options; negating it drops any segment that carries
# them. Drops are logged (rate limited) so probing is visible.
before_rules = "/etc/ufw/before.rules"
cve_marker = "CVE-2026-98432"
ipopts_match = '-p tcp -m u32 ! --u32 "0&0x0F000000=0x05000000"'
ruby_block "ufw: drop IPv4 TCP segments with IP options (#{cve_marker})" do
block do
editor = Chef::Util::FileEdit.new(before_rules)
editor.search_file_delete_line(/#{cve_marker}/)
editor.insert_line_after_match(
/^# End required lines$/,
"# #{cve_marker}: drop IPv4 TCP segments carrying IP options\n" \
"-A ufw-before-input -m comment --comment \"#{cve_marker}\" #{ipopts_match} " \
"-m limit --limit 5/min -j LOG --log-prefix \"[#{cve_marker}] ipopts \" --log-level 4\n" \
"-A ufw-before-input -m comment --comment \"#{cve_marker}\" #{ipopts_match} -j DROP"
)
editor.write_file
raise "#{cve_marker}: failed to add the ip-options drop rule to #{before_rules}" \
unless ::File.read(before_rules).include?(cve_marker)
end
not_if { ::File.exist?(before_rules) && ::File.read(before_rules).include?(cve_marker) }
notifies :run, "execute[reload ufw]"
end
execute "reload ufw" do
command "ufw reload"
action :nothing
end
# --- 2. Disable Multipath TCP where the kernel supports it ------------------
#
# MPTCP is in-tree since Linux 5.6; the /proc entry only exists when it is
# available, so the compile-time guard keeps older (5.4) hosts from writing a
# sysctl for a key their kernel does not know. Nothing in our stack needs MPTCP.
#
# Not using the core `sysctl` resource here: its reload runs `sysctl -p`, which
# reads /etc/sysctl.conf - a file that does not exist on Ubuntu 26.04, making
# the resource fail. Writing the drop-in and applying the value explicitly works
# on every release we run.
if ::File.exist?("/proc/sys/net/mptcp/enabled")
file "/etc/sysctl.d/99-chef-net.mptcp.enabled.conf" do
content "net.mptcp.enabled = 0\n"
owner "root"
group "root"
mode "0644"
end
execute "disable multipath TCP (net.mptcp.enabled=0)" do
command "sysctl -w net.mptcp.enabled=0"
not_if { ::File.read("/proc/sys/net/mptcp/enabled").strip == "0" }
end
end
@@ -77,6 +77,8 @@ unless node.chef_environment == "development"
include_recipe "kosmos-base::firewall"
include_recipe "kosmos-base::cve_2026_98432"
include_recipe "kosmos-base::tmux"
include_recipe "kosmos-postfix"
@@ -59,6 +59,10 @@ systemd_unit "node_exporter.service" do
User: "node_exporter",
Group: "node_exporter",
ExecStart: "/usr/local/bin/node_exporter --web.listen-address=:#{node_exporter_port} --collector.textfile.directory=/var/lib/node_exporter/textfile",
# node_exporter 1.11.1 is built with Go >= 1.24, which opens MPTCP
# listeners by default on Linux since 5.6. That is the precondition of
# the CVE-2026-98432 exploit, and we do not need MPTCP, so opt out.
Environment: "GODEBUG=multipathtcp=0",
Restart: "on-failure",
RestartSec: "5",
NoNewPrivileges: "yes",
@@ -70,6 +74,7 @@ systemd_unit "node_exporter.service" do
},
})
triggers_reload true
notifies :restart, "service[node_exporter]", :delayed
action :create
end