Skip to content

[ciqlts8_6] mpls: add seqcount to protect the platform_label{,s} pair - #1613

Draft
ciq-kernel-automation[bot] wants to merge 1 commit into
ciqlts8_6from
{bmastbergen_nebusec}_ciqlts8_6
Draft

ciq-kernel-automation[bot] wants to merge 1 commit into
ciqlts8_6from
{bmastbergen_nebusec}_ciqlts8_6

Conversation

@ciq-kernel-automation

Copy link
Copy Markdown

Summary

This PR has been automatically created after successful completion of all CI stages.

Commit Message(s)

mpls: add seqcount to protect the platform_label{,s} pair

jira VULN-183754
cve CVE-2026-43042
commit-author Sabrina Dubroca <sd@queasysnail.net>
commit 629ec78ef8608d955ce217880cdc3e1873af3a15
upstream-diff Upstream adds seqcount_mutex_t to struct netns_mpls,
  which breaks kABI by changing the struct size. This backport uses
  a file-scope global seqcount_t in af_mpls.c instead, avoiding any
  struct layout change. This is safe because resize_platform_label_table()
  is already RTNL-serialized, so only one writer runs at a time.
  The seqcount is statically initialized, so no mpls_net_init() change
  is needed. The read/write seqcount logic is identical to upstream.

Test Results

✅ Build Stage

Architecture Build Time Total Time
x86_64 22m 36s 23m 30s
aarch64 9m 36s 10m 16s

✅ Boot Verification

✅ Kernel Selftests

Architecture Passed Failed Compared Against Status
x86_64 108 31 ciqlts8_6 ✅ No regressions
aarch64 67 20 ciqlts8_6 ✅ No regressions

✅ LTP Results

Architecture Passed Failed Compared Against Status
x86_64 1434 13 ciqlts8_6 ✅ No regressions
aarch64 1425 14 ciqlts8_6 ✅ No regressions

🤖 This PR was automatically generated by GitHub Actions
Run ID: 35021403299

@ciq-kernel-automation ciq-kernel-automation Bot added the created-by-kernelci Tag PRs that were automatically created when a user branch was pushed to the repo (kernelCI) label Sep 16, 2026
@github-actions

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/35041765251

@github-actions

Copy link
Copy Markdown

🔍 Interdiff Analysis

  • ⚠️ PR commit b7f8cfcf77e5 (mpls: add seqcount to protect the platform_label{,s} pair) → upstream 629ec78ef860
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -36,8 +36,6 @@
 
 #define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
 
-static seqcount_t mpls_platform_label_seq = SEQCNT_ZERO(mpls_platform_label_seq);
-
 static int label_limit = (1 << 20) - 1;
 static int ttl_max = 255;
 
@@ -75,32 +73,16 @@
 		       struct nlmsghdr *nlh, struct net *net, u32 portid,
 		       unsigned int nlm_flags);
 
-static struct mpls_route __rcu **mpls_platform_label_rcu(struct net *net,
-							size_t *platform_labels)
-{
-	struct mpls_route __rcu **platform_label;
-	unsigned int sequence;
-
-	do {
-		sequence = read_seqcount_begin(&mpls_platform_label_seq);
-		platform_label = rcu_dereference(net->mpls.platform_label);
-		*platform_labels = net->mpls.platform_labels;
-	} while (read_seqcount_retry(&mpls_platform_label_seq, sequence));
-
-	return platform_label;
-}
-
 static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
 {
-	struct mpls_route __rcu **platform_label;
-	size_t platform_labels;
-
-	platform_label = mpls_platform_label_rcu(net, &platform_labels);
+	struct mpls_route *rt = NULL;
 
-	if (index < platform_labels)
-		return rcu_dereference(platform_label[index]);
-
-	return NULL;
+	if (index < net->mpls.platform_labels) {
+		struct mpls_route __rcu **platform_label =
+			rcu_dereference(net->mpls.platform_label);
+		rt = rcu_dereference(platform_label[index]);
+	}
+	return rt;
 }
 
 bool mpls_output_possible(const struct net_device *dev)
@@ -2197,7 +2179,8 @@
 	if (index < MPLS_LABEL_FIRST_UNRESERVED)
 		index = MPLS_LABEL_FIRST_UNRESERVED;
 
-	platform_label = mpls_platform_label_rcu(net, &platform_labels);
+	platform_label = rtnl_dereference(net->mpls.platform_label);
+	platform_labels = net->mpls.platform_labels;
 
 	if (filter.filter_set)
 		flags |= NLM_F_DUMP_FILTERED;
@@ -2584,10 +2567,10 @@
 
 	/* Update the global pointers */
 	local_bh_disable();
-	write_seqcount_begin(&mpls_platform_label_seq);
+	write_seqcount_begin(&net->mpls.platform_label_seq);
 	net->mpls.platform_labels = limit;
 	rcu_assign_pointer(net->mpls.platform_label, labels);
-	write_seqcount_end(&mpls_platform_label_seq);
+	write_seqcount_end(&net->mpls.platform_label_seq);
 	local_bh_enable();
 
 	rtnl_unlock();

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -83,6 +83,20 @@
 	return mpls_dereference(net, platform_label[index]);
 }
 
+static struct mpls_route __rcu **mpls_platform_label_rcu(struct net *net, size_t *platform_labels)
+{
+	struct mpls_route __rcu **platform_label;
+	unsigned int sequence;
+
+	do {
+		sequence = read_seqcount_begin(&net->mpls.platform_label_seq);
+		platform_label = rcu_dereference(net->mpls.platform_label);
+		*platform_labels = net->mpls.platform_labels;
+	} while (read_seqcount_retry(&net->mpls.platform_label_seq, sequence));
+
+	return platform_label;
+}
+
 static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
 {
 	struct mpls_route __rcu **platform_label;
@@ -86,6 +100,9 @@
 static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
 {
 	struct mpls_route __rcu **platform_label;
+	size_t platform_labels;
+
+	platform_label = mpls_platform_label_rcu(net, &platform_labels);
 
 	if (index >= net->mpls.platform_labels)
 		return NULL;
@@ -87,7 +104,7 @@
 {
 	struct mpls_route __rcu **platform_label;
 
-	if (index >= net->mpls.platform_labels)
+	if (index >= platform_labels)
 		return NULL;
 
 	platform_label = rcu_dereference(net->mpls.platform_label);
@@ -90,7 +107,6 @@
 	if (index >= net->mpls.platform_labels)
 		return NULL;
 
-	platform_label = rcu_dereference(net->mpls.platform_label);
 	return rcu_dereference(platform_label[index]);
 }
 
@@ -2240,8 +2256,7 @@
 	if (index < MPLS_LABEL_FIRST_UNRESERVED)
 		index = MPLS_LABEL_FIRST_UNRESERVED;
 
-	platform_label = rcu_dereference(net->mpls.platform_label);
-	platform_labels = net->mpls.platform_labels;
+	platform_label = mpls_platform_label_rcu(net, &platform_labels);
 
 	if (filter.filter_set)
 		flags |= NLM_F_DUMP_FILTERED;
@@ -2732,6 +2751,8 @@
 	int i;
 
 	mutex_init(&net->mpls.platform_mutex);
+	seqcount_mutex_init(&net->mpls.platform_label_seq, &net->mpls.platform_mutex);
+
 	net->mpls.platform_labels = 0;
 	net->mpls.platform_label = NULL;
 	net->mpls.ip_ttl_propagate = 1;

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -70,13 +66,12 @@
 
-static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
+static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
 {
-	struct mpls_route *rt = NULL;
+	struct mpls_route __rcu **platform_label;
 
-	if (index < net->mpls.platform_labels) {
-		struct mpls_route __rcu **platform_label =
-			rcu_dereference(net->mpls.platform_label);
-		rt = rcu_dereference(platform_label[index]);
-	}
-	return rt;
+	if (index >= net->mpls.platform_labels)
+		return NULL;
+
+	platform_label = rcu_dereference(net->mpls.platform_label);
+	return rcu_dereference(platform_label[index]);
 }
 
@@ -2179,7 +2240,7 @@
 	if (index < MPLS_LABEL_FIRST_UNRESERVED)
 		index = MPLS_LABEL_FIRST_UNRESERVED;
 
-	platform_label = rtnl_dereference(net->mpls.platform_label);
+	platform_label = rcu_dereference(net->mpls.platform_label);
 	platform_labels = net->mpls.platform_labels;
 
 	if (filter.filter_set)
@@ -2563,7 +2624,8 @@
 	}
 
 	/* Update the global pointers */
 	net->mpls.platform_labels = limit;
 	rcu_assign_pointer(net->mpls.platform_label, labels);
 
-	rtnl_unlock();
+	mutex_unlock(&net->mpls.platform_mutex);
+

================================================================================
*    ONLY IN PATCH2 - files not modified by patch1                             *
================================================================================

--- a/include/net/netns/mpls.h
+++ b/include/net/netns/mpls.h
@@ -17,6 +17,7 @@ struct netns_mpls {
 	size_t platform_labels;
 	struct mpls_route __rcu * __rcu *platform_label;
 	struct mutex platform_mutex;
+	seqcount_mutex_t platform_label_seq;
 
 	struct ctl_table_header *ctl;
 };

This is an automated interdiff check for backported commits.

@github-actions

Copy link
Copy Markdown

JIRA PR Check Results

1 commit(s) with issues found:

Commit b7f8cfcf77e5

Summary: mpls: add seqcount to protect the platform_label{,s} pair

❌ Errors:

  • VULN-183754: Status is 'To Do', expected 'In Progress'

⚠️ Warnings:

  • VULN-183754: No time logged - please log time manually

Summary: Checked 1 commit(s) total.

@github-actions

Copy link
Copy Markdown

Validation checks completed with issues View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/35041765251

@bmastbergen
bmastbergen marked this pull request as draft September 16, 2026 14:59
jira VULN-183754
cve CVE-2026-43042
commit-author Sabrina Dubroca <sd@queasysnail.net>
commit 629ec78
upstream-diff Upstream adds seqcount_mutex_t to struct netns_mpls,
  which breaks kABI by changing the struct size. This backport uses
  a file-scope seqcount_spinlock_t with a static spinlock in af_mpls.c
  instead, avoiding any struct layout change. This is safe because
  resize_platform_label_table() is already RTNL-serialized, so only
  one writer runs at a time. The seqcount_spinlock_t is RT-safe
  (readers sleep on the lock instead of spinning when the writer is
  preempted). The seqcount is statically initialized, so no
  mpls_net_init() change is needed. On this tree mpls_dump_routes()
  still runs under RTNL, so only mpls_route_input_rcu() (reached
  from mpls_forward()) is a true lockless reader; the dump change
  is extra hardening. The read/write seqcount logic is identical
  to upstream.

The RCU-protected codepaths (mpls_forward, mpls_dump_routes) can have
an inconsistent view of platform_labels vs platform_label in case of a
concurrent resize (resize_platform_label_table, under
platform_mutex). This can lead to OOB accesses.

This patch adds a seqcount, so that we get a consistent snapshot.

Note that mpls_label_ok is also susceptible to this, so the check
against RTA_DST in rtm_to_route_config, done outside platform_mutex,
is not sufficient. This value gets passed to mpls_label_ok once more
in both mpls_route_add and mpls_route_del, so there is no issue, but
that additional check must not be removed.

	Reported-by: Yuan Tan <tanyuan98@outlook.com>
	Reported-by: Yifan Wu <yifanwucs@gmail.com>
	Reported-by: Juefei Pu <tomapufckgml@gmail.com>
	Reported-by: Xin Liu <bird@lzu.edu.cn>
Fixes: 7720c01 ("mpls: Add a sysctl to control the size of the mpls label table")
Fixes: dde1b38 ("mpls: Convert mpls_dump_routes() to RCU.")
	Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Link: https://patch.msgid.link/cd8fca15e3eb7e212b094064cd83652e20fd9d31.1774284088.git.sd@queasysnail.net
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 629ec78)
	Signed-off-by: Brett Mastbergen <bmastbergen@ciq.com>
@bmastbergen
bmastbergen force-pushed the {bmastbergen_nebusec}_ciqlts8_6 branch from b7f8cfc to 0a86ca1 Compare September 16, 2026 15:50
@github-actions

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/35119021094

@github-actions

Copy link
Copy Markdown

🔍 Interdiff Analysis

  • ⚠️ PR commit 0a86ca17a055 (mpls: add seqcount to protect the platform_label{,s} pair) → upstream 629ec78ef860
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -36,10 +36,6 @@
 
 #define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
 
-static DEFINE_SPINLOCK(mpls_platform_label_lock);
-static seqcount_spinlock_t mpls_platform_label_seq =
-	SEQCNT_SPINLOCK_ZERO(mpls_platform_label_seq, &mpls_platform_label_lock);
-
 static int label_limit = (1 << 20) - 1;
 static int ttl_max = 255;
 
@@ -77,32 +73,16 @@
 		       struct nlmsghdr *nlh, struct net *net, u32 portid,
 		       unsigned int nlm_flags);
 
-static struct mpls_route __rcu **mpls_platform_label_rcu(struct net *net,
-							size_t *platform_labels)
-{
-	struct mpls_route __rcu **platform_label;
-	unsigned int sequence;
-
-	do {
-		sequence = read_seqcount_begin(&mpls_platform_label_seq);
-		platform_label = rcu_dereference(net->mpls.platform_label);
-		*platform_labels = net->mpls.platform_labels;
-	} while (read_seqcount_retry(&mpls_platform_label_seq, sequence));
-
-	return platform_label;
-}
-
 static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
 {
-	struct mpls_route __rcu **platform_label;
-	size_t platform_labels;
-
-	platform_label = mpls_platform_label_rcu(net, &platform_labels);
+	struct mpls_route *rt = NULL;
 
-	if (index < platform_labels)
-		return rcu_dereference(platform_label[index]);
-
-	return NULL;
+	if (index < net->mpls.platform_labels) {
+		struct mpls_route __rcu **platform_label =
+			rcu_dereference(net->mpls.platform_label);
+		rt = rcu_dereference(platform_label[index]);
+	}
+	return rt;
 }
 
 bool mpls_output_possible(const struct net_device *dev)
@@ -2199,7 +2179,8 @@
 	if (index < MPLS_LABEL_FIRST_UNRESERVED)
 		index = MPLS_LABEL_FIRST_UNRESERVED;
 
-	platform_label = mpls_platform_label_rcu(net, &platform_labels);
+	platform_label = rtnl_dereference(net->mpls.platform_label);
+	platform_labels = net->mpls.platform_labels;
 
 	if (filter.filter_set)
 		flags |= NLM_F_DUMP_FILTERED;
@@ -2585,12 +2566,12 @@
 	}
 
 	/* Update the global pointers */
-	spin_lock_bh(&mpls_platform_label_lock);
-	write_seqcount_begin(&mpls_platform_label_seq);
+	local_bh_disable();
+	write_seqcount_begin(&net->mpls.platform_label_seq);
 	net->mpls.platform_labels = limit;
 	rcu_assign_pointer(net->mpls.platform_label, labels);
-	write_seqcount_end(&mpls_platform_label_seq);
-	spin_unlock_bh(&mpls_platform_label_lock);
+	write_seqcount_end(&net->mpls.platform_label_seq);
+	local_bh_enable();
 
 	rtnl_unlock();
 

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -83,6 +83,20 @@
 	return mpls_dereference(net, platform_label[index]);
 }
 
+static struct mpls_route __rcu **mpls_platform_label_rcu(struct net *net, size_t *platform_labels)
+{
+	struct mpls_route __rcu **platform_label;
+	unsigned int sequence;
+
+	do {
+		sequence = read_seqcount_begin(&net->mpls.platform_label_seq);
+		platform_label = rcu_dereference(net->mpls.platform_label);
+		*platform_labels = net->mpls.platform_labels;
+	} while (read_seqcount_retry(&net->mpls.platform_label_seq, sequence));
+
+	return platform_label;
+}
+
 static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
 {
 	struct mpls_route __rcu **platform_label;
@@ -86,6 +100,9 @@
 static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
 {
 	struct mpls_route __rcu **platform_label;
+	size_t platform_labels;
+
+	platform_label = mpls_platform_label_rcu(net, &platform_labels);
 
 	if (index >= net->mpls.platform_labels)
 		return NULL;
@@ -87,7 +104,7 @@
 {
 	struct mpls_route __rcu **platform_label;
 
-	if (index >= net->mpls.platform_labels)
+	if (index >= platform_labels)
 		return NULL;
 
 	platform_label = rcu_dereference(net->mpls.platform_label);
@@ -90,7 +107,6 @@
 	if (index >= net->mpls.platform_labels)
 		return NULL;
 
-	platform_label = rcu_dereference(net->mpls.platform_label);
 	return rcu_dereference(platform_label[index]);
 }
 
@@ -2240,8 +2256,7 @@
 	if (index < MPLS_LABEL_FIRST_UNRESERVED)
 		index = MPLS_LABEL_FIRST_UNRESERVED;
 
-	platform_label = rcu_dereference(net->mpls.platform_label);
-	platform_labels = net->mpls.platform_labels;
+	platform_label = mpls_platform_label_rcu(net, &platform_labels);
 
 	if (filter.filter_set)
 		flags |= NLM_F_DUMP_FILTERED;
@@ -2732,6 +2751,8 @@
 	int i;
 
 	mutex_init(&net->mpls.platform_mutex);
+	seqcount_mutex_init(&net->mpls.platform_label_seq, &net->mpls.platform_mutex);
+
 	net->mpls.platform_labels = 0;
 	net->mpls.platform_label = NULL;
 	net->mpls.ip_ttl_propagate = 1;

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -70,13 +66,12 @@
 
-static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
+static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
 {
-	struct mpls_route *rt = NULL;
+	struct mpls_route __rcu **platform_label;
 
-	if (index < net->mpls.platform_labels) {
-		struct mpls_route __rcu **platform_label =
-			rcu_dereference(net->mpls.platform_label);
-		rt = rcu_dereference(platform_label[index]);
-	}
-	return rt;
+	if (index >= net->mpls.platform_labels)
+		return NULL;
+
+	platform_label = rcu_dereference(net->mpls.platform_label);
+	return rcu_dereference(platform_label[index]);
 }
 
@@ -2179,7 +2240,7 @@
 	if (index < MPLS_LABEL_FIRST_UNRESERVED)
 		index = MPLS_LABEL_FIRST_UNRESERVED;
 
-	platform_label = rtnl_dereference(net->mpls.platform_label);
+	platform_label = rcu_dereference(net->mpls.platform_label);
 	platform_labels = net->mpls.platform_labels;
 
 	if (filter.filter_set)
@@ -2563,7 +2624,8 @@
 	}
 
 	/* Update the global pointers */
 	net->mpls.platform_labels = limit;
 	rcu_assign_pointer(net->mpls.platform_label, labels);
 
-	rtnl_unlock();
+	mutex_unlock(&net->mpls.platform_mutex);
+

================================================================================
*    ONLY IN PATCH2 - files not modified by patch1                             *
================================================================================

--- a/include/net/netns/mpls.h
+++ b/include/net/netns/mpls.h
@@ -17,6 +17,7 @@ struct netns_mpls {
 	size_t platform_labels;
 	struct mpls_route __rcu * __rcu *platform_label;
 	struct mutex platform_mutex;
+	seqcount_mutex_t platform_label_seq;
 
 	struct ctl_table_header *ctl;
 };

This is an automated interdiff check for backported commits.

@github-actions

Copy link
Copy Markdown

JIRA PR Check Results

1 commit(s) with issues found:

Commit 0a86ca17a055

Summary: mpls: add seqcount to protect the platform_label{,s} pair

❌ Errors:

  • VULN-183754: Status is 'To Do', expected 'In Progress'

⚠️ Warnings:

  • VULN-183754: No time logged - please log time manually

Summary: Checked 1 commit(s) total.

@github-actions

Copy link
Copy Markdown

Validation checks completed with issues View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/35119021094

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by-kernelci Tag PRs that were automatically created when a user branch was pushed to the repo (kernelCI)

Development

Successfully merging this pull request may close these issues.

1 participant