Package: release.debian.org
Severity: normal
Tags: bookworm
User: [email protected]
Usertags: pu
X-Debbugs-Cc: [email protected], [email protected], 
[email protected]
Control: affects -1 + src:lxc

[ Reason ]
The release of LXC 7.0 included a fix for the low severity CVE-2026-
39402. After discussion with the Security Team, this vulnerability
won't receive its own DSA, but will be addressed via the upcoming point
release.

[ Impact ]
LXC in bookworm is currently vulnerable to CVE-2026-39402.

[ Tests ]
Upstream did add a test in the 7.0 release, but I haven't included it
in the cherry-pick because the packaging of lxc in bookworm won't ever
actually run it.

[ Risks ]
Minor/none -- one targeted fix cherry-picked from the upstream git
repo.

[ Checklist ]
  [*] *all* changes are documented in the d/changelog
  [*] I reviewed all changes and I approve them
  [*] attach debdiff against the package in (old)stable
  [*] the issue is verified as fixed in unstable

[ Changes ]
One patch as outlined above.

[ Other info ]
The source debdiff is attached.
diff -Nru lxc-5.0.2/debian/changelog lxc-5.0.2/debian/changelog
--- lxc-5.0.2/debian/changelog	2025-01-03 00:53:50.000000000 +0000
+++ lxc-5.0.2/debian/changelog	2026-04-30 19:05:41.000000000 +0000
@@ -1,3 +1,9 @@
+lxc (1:5.0.2-1+deb12u4) bookworm; urgency=medium
+
+  * Cherry-pick upstream fix for CVE-2026-39402
+
+ -- Mathias Gibbens <[email protected]>  Thu, 30 Apr 2026 19:05:41 +0000
+
 lxc (1:5.0.2-1+deb12u3) bookworm; urgency=medium
 
   * Cherry-pick upstream fix for null pointer dereference when using a shared
diff -Nru lxc-5.0.2/debian/patches/0103-cherry-pick-CVE-2026-39402.patch lxc-5.0.2/debian/patches/0103-cherry-pick-CVE-2026-39402.patch
--- lxc-5.0.2/debian/patches/0103-cherry-pick-CVE-2026-39402.patch	1970-01-01 00:00:00.000000000 +0000
+++ lxc-5.0.2/debian/patches/0103-cherry-pick-CVE-2026-39402.patch	2026-04-30 19:05:09.000000000 +0000
@@ -0,0 +1,168 @@
+From db25752fe8a03c8264a21ca99f49b2db93c56910 Mon Sep 17 00:00:00 2001
+From: "Serge E. Hallyn" <[email protected]>
+Date: Mon, 20 Apr 2026 23:07:47 -0500
+Subject: [PATCH] lxc-user-nic: clarify and fix
+
+Some variable names were a bit confusing in find_line and cull_entries.
+Rename and document, and fix the flows using these.
+
+It's possible that a more maintainable approach, long term, would be
+to break these up differently: have one function create a neat
+in memory data structure representing the files, and have the paths
+currently using find_line and cull_entries peek into the data structures.
+But i think this is pretty clear.
+
+This fixes CVE-2026-39402
+
+Signed-off-by: Serge E. Hallyn <[email protected]>
+Reviewed-by: Alexander Mikhalitsyn <[email protected]>
+---
+ src/lxc/cmd/lxc_user_nic.c | 75 +++++++++++++++++++++++++++++---------
+ 1 file changed, 57 insertions(+), 18 deletions(-)
+
+diff --git a/src/lxc/cmd/lxc_user_nic.c b/src/lxc/cmd/lxc_user_nic.c
+index d1b392199a..7f5a0b6fdf 100644
+--- a/src/lxc/cmd/lxc_user_nic.c
++++ b/src/lxc/cmd/lxc_user_nic.c
+@@ -371,19 +371,58 @@ static char *get_eow(char *s, char *e)
+ 	return s;
+ }
+ 
++static bool same_word(const char *start, const char *end, const char *word)
++{
++	size_t wordlen = strlen(word);
++	size_t buflen = end - start;
++
++	if (wordlen != buflen)
++		return false;
++	if (strncmp(start, word, wordlen) == 0)
++		return true;
++	return false;
++}
++
++/*
++ * in:
++ * @buf_start and @buf_end point to the buffer to be read.
++ *
++ * @owner_name is the name of the user who should own the link.
++ *
++ * @net_type is type of connection, e.g. veth
++ *
++ * @net_link is the name of the bridge, e.g. lxcbr0, on which the
++ * device should live.
++ *
++ * @net_dev is the name of the device itself in the host netns.
++ *
++ * out:
++ * @is_owner is set to true if the current line is owned by @name.
++
++ * @nic_found is set to true if the line is specifically for the passed-in
++ * @net_dev, and it is on the right @net_link and of the right @net_type.
++ *
++ * @exists is set to false if the nic in this line no longer exists.  This is
++ * used by cull_entries(): if we set it to false, then this line will be
++ * removed from the LXC_USERNIC_DB (e.g. /var/run/lxc/nics).
++ */
+ static char *find_line(char *buf_start, char *buf_end, char *name,
+ 		       char *net_type, char *net_link, char *net_dev,
+-		       bool *owner, bool *found, bool *keep)
++		       bool *is_owner, bool *nic_found, bool *exists)
+ {
+ 	char *end_of_line, *end_of_word, *line;
++	bool right_net_type, right_bridge, right_link_name;;
+ 
+ 	while (buf_start < buf_end) {
+ 		size_t len;
+ 		char netdev_name[IFNAMSIZ];
+ 
+-		*found = false;
+-		*keep = true;
+-		*owner = false;
++		*nic_found = false;
++		*exists = true;
++		*is_owner = false;
++		right_net_type  = false;
++		right_bridge    = false;
++		right_link_name = false;
+ 
+ 		end_of_line = get_eol(buf_start, buf_end);
+ 		if (end_of_line >= buf_end)
+@@ -402,11 +441,8 @@ static char *find_line(char *buf_start, char *buf_end, char *name,
+ 		if (!end_of_word)
+ 			return NULL;
+ 
+-		if (strncmp(buf_start, name, strlen(name)))
+-			*found = false;
+-		else
+-			if (strlen(name) == (size_t)(end_of_word - buf_start))
+-				*owner = true;
++		if (same_word(buf_start, end_of_word, name))
++			*is_owner = true;
+ 
+ 		buf_start = end_of_word + 1;
+ 		while ((buf_start < buf_end) && isblank(*buf_start))
+@@ -418,8 +454,8 @@ static char *find_line(char *buf_start, char *buf_end, char *name,
+ 		if (!end_of_word)
+ 			return NULL;
+ 
+-		if (strncmp(buf_start, net_type, strlen(net_type)))
+-			*found = false;
++		if (same_word(buf_start, end_of_word, net_type))
++			right_net_type = true;
+ 
+ 		buf_start = end_of_word + 1;
+ 		while ((buf_start < buf_end) && isblank(*buf_start))
+@@ -431,8 +467,8 @@ static char *find_line(char *buf_start, char *buf_end, char *name,
+ 		if (!end_of_word)
+ 			return NULL;
+ 
+-		if (strncmp(buf_start, net_link, strlen(net_link)))
+-			*found = false;
++		if (same_word(buf_start, end_of_word, net_link))
++			right_bridge = true;
+ 
+ 		buf_start = end_of_word + 1;
+ 		while ((buf_start < buf_end) && isblank(*buf_start))
+@@ -451,10 +487,13 @@ static char *find_line(char *buf_start, char *buf_end, char *name,
+ 
+ 		memcpy(netdev_name, buf_start, len);
+ 		netdev_name[len] = '\0';
+-		*keep = lxc_nic_exists(netdev_name);
++		*exists = lxc_nic_exists(netdev_name);
+ 
+ 		if (net_dev && !strcmp(netdev_name, net_dev))
+-			*found = true;
++			right_link_name = true;
++
++		if (right_net_type && right_bridge && right_link_name)
++			*nic_found = true;
+ 
+ 		return line;
+ 
+@@ -584,7 +623,7 @@ static bool cull_entries(int fd, char *name, char *net_type, char *net_link,
+ 	size_t length = 0;
+ 	int ret;
+ 	char *buf_end, *buf_start;
+-	bool found, keep;
++	bool nic_found, is_owner, keep;
+ 
+ 	ret = fd_to_buf(fd, &buf, &length);
+ 	if (ret < 0) {
+@@ -600,7 +639,7 @@ static bool cull_entries(int fd, char *name, char *net_type, char *net_link,
+ 	buf_start = buf;
+ 	buf_end = buf + length;
+ 	while ((buf_start = find_line(buf_start, buf_end, name, net_type,
+-				      net_link, net_dev, &(bool){true}, &found,
++				      net_link, net_dev, &is_owner, &nic_found,
+ 				      &keep))) {
+ 		struct entry_line *newe;
+ 
+@@ -608,7 +647,7 @@ static bool cull_entries(int fd, char *name, char *net_type, char *net_link,
+ 		if (!newe)
+ 			return false;
+ 
+-		if (found)
++		if (nic_found && is_owner)
+ 			*found_nicname = true;
+ 
+ 		entry_lines = newe;
diff -Nru lxc-5.0.2/debian/patches/series lxc-5.0.2/debian/patches/series
--- lxc-5.0.2/debian/patches/series	2025-01-03 00:53:50.000000000 +0000
+++ lxc-5.0.2/debian/patches/series	2026-04-30 19:05:30.000000000 +0000
@@ -4,3 +4,4 @@
 0100-fix-nftables-ipv6.patch
 0101-cherry-pick-fix-ephemeral-copies.patch
 0102-cherry-pick-fix-null-pointer-dereference.patch
+0103-cherry-pick-CVE-2026-39402.patch

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to