public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks
@ 2026-03-27  6:12 Xiang Mei
  2026-03-27  6:12 ` [PATCH net 2/3] net/sched: cls_flow: " Xiang Mei
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Xiang Mei @ 2026-03-27  6:12 UTC (permalink / raw)
  To: netdev; +Cc: jhs, jiri, davem, edumazet, kuba, horms, shuah, bestswngs,
	Xiang Mei

The old-method path in fw_classify() calls tcf_block_q() and
dereferences q->handle. Shared blocks leave block->q NULL, causing a
NULL deref when an empty cls_fw filter is attached to a shared block
and a packet with a nonzero major skb mark is classified.

Check tcf_block_shared() before accessing block->q and return -1 (no
match) for shared blocks, consistent with cls_u32's tc_u_common_ptr().

The fixed null-ptr-deref calling stack:
 KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
 RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
 Call Trace:
  tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
  tc_run (net/core/dev.c:4401)
  __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)

Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
Reported-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Xiang Mei <xmei5@asu.edu>
---
 net/sched/cls_fw.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index be81c108179d..caf17ab3be87 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -74,9 +74,14 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb,
 			}
 		}
 	} else {
-		struct Qdisc *q = tcf_block_q(tp->chain->block);
+		struct tcf_block *block = tp->chain->block;
+		struct Qdisc *q;
+
+		if (tcf_block_shared(block))
+			return -1;
 
 		/* Old method: classify the packet using its skb mark. */
+		q = tcf_block_q(block);
 		if (id && (TC_H_MAJ(id) == 0 ||
 			   !(TC_H_MAJ(id ^ q->handle)))) {
 			res->classid = id;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net 2/3] net/sched: cls_flow: fix NULL pointer dereference on shared blocks
  2026-03-27  6:12 [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks Xiang Mei
@ 2026-03-27  6:12 ` Xiang Mei
  2026-03-27  6:13 ` [PATCH net 3/3] selftests/tc-testing: add tests for cls_fw and cls_flow " Xiang Mei
  2026-03-27 14:11 ` [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference " Jamal Hadi Salim
  2 siblings, 0 replies; 11+ messages in thread
From: Xiang Mei @ 2026-03-27  6:12 UTC (permalink / raw)
  To: netdev; +Cc: jhs, jiri, davem, edumazet, kuba, horms, shuah, bestswngs,
	Xiang Mei

flow_change() calls tcf_block_q() and dereferences q->handle to derive
a default baseclass. Shared blocks leave block->q NULL, causing a NULL
deref when a flow filter without a fully qualified baseclass is created
on a shared block.

Check tcf_block_shared() before accessing block->q and return -EINVAL
for shared blocks. This avoids the null-deref shown below:

=======================================================================
KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
RIP: 0010:flow_change (net/sched/cls_flow.c:508)
Call Trace:
 tc_new_tfilter (net/sched/cls_api.c:2432)
 rtnetlink_rcv_msg (net/core/rtnetlink.c:6980)
 [...]
=======================================================================

Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
Reported-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Xiang Mei <xmei5@asu.edu>
---
 net/sched/cls_flow.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 339c664beff6..26077681c9b6 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -503,8 +503,13 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
 		}
 
 		if (TC_H_MAJ(baseclass) == 0) {
-			struct Qdisc *q = tcf_block_q(tp->chain->block);
+			struct tcf_block *block = tp->chain->block;
+			struct Qdisc *q;
 
+			if (tcf_block_shared(block))
+				goto err2;
+
+			q = tcf_block_q(block);
 			baseclass = TC_H_MAKE(q->handle, baseclass);
 		}
 		if (TC_H_MIN(baseclass) == 0)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net 3/3] selftests/tc-testing: add tests for cls_fw and cls_flow on shared blocks
  2026-03-27  6:12 [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks Xiang Mei
  2026-03-27  6:12 ` [PATCH net 2/3] net/sched: cls_flow: " Xiang Mei
@ 2026-03-27  6:13 ` Xiang Mei
  2026-03-27 14:11 ` [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference " Jamal Hadi Salim
  2 siblings, 0 replies; 11+ messages in thread
From: Xiang Mei @ 2026-03-27  6:13 UTC (permalink / raw)
  To: netdev; +Cc: jhs, jiri, davem, edumazet, kuba, horms, shuah, bestswngs,
	Xiang Mei

Regression tests for the shared-block NULL derefs fixed in the previous
two patches:
  - fw: attach an empty fw filter to a shared block and send traffic.
  - flow: create a flow filter on a shared block without a baseclass.

Signed-off-by: Xiang Mei <xmei5@asu.edu>
---
 .../tc-testing/tc-tests/infra/filter.json     | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
index 8d10042b489b..b749087d1691 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json
@@ -22,5 +22,50 @@
         "teardown": [
             "$TC qdisc del dev $DUMMY root handle 1: htb default 1"
         ]
+    },
+    {
+        "id": "b7e3",
+        "name": "Empty fw filter on shared block - no NULL deref in fw_classify",
+        "category": [
+            "filter",
+            "fw"
+        ],
+        "plugins": {
+            "requires": "nsPlugin"
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 ingress_block 1 clsact",
+            "$TC filter add block 1 protocol ip prio 1 fw"
+        ],
+        "cmdUnderTest": "$IP addr add 10.10.10.1/24 dev $DEV1 && ping -I$DEV1 -c1 -W1 10.10.10.1 || true",
+        "expExitCode": "0",
+        "verifyCmd": "$TC qdisc show dev $DEV1",
+        "matchPattern": "clsact",
+        "matchCount": "1",
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact"
+        ]
+    },
+    {
+        "id": "c8f4",
+        "name": "Flow filter on shared block without baseclass - no NULL deref in flow_change",
+        "category": [
+            "filter",
+            "flow"
+        ],
+        "plugins": {
+            "requires": "nsPlugin"
+        },
+        "setup": [
+            "$TC qdisc add dev $DEV1 ingress_block 1 clsact"
+        ],
+        "cmdUnderTest": "$TC filter add block 1 protocol ip prio 1 handle 1 flow map key dst",
+        "expExitCode": "2",
+        "verifyCmd": "$TC filter show block 1",
+        "matchPattern": "flow",
+        "matchCount": "0",
+        "teardown": [
+            "$TC qdisc del dev $DEV1 clsact"
+        ]
     }
 ]
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks
  2026-03-27  6:12 [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks Xiang Mei
  2026-03-27  6:12 ` [PATCH net 2/3] net/sched: cls_flow: " Xiang Mei
  2026-03-27  6:13 ` [PATCH net 3/3] selftests/tc-testing: add tests for cls_fw and cls_flow " Xiang Mei
@ 2026-03-27 14:11 ` Jamal Hadi Salim
  2026-03-29 12:15   ` Jamal Hadi Salim
  2 siblings, 1 reply; 11+ messages in thread
From: Jamal Hadi Salim @ 2026-03-27 14:11 UTC (permalink / raw)
  To: Xiang Mei; +Cc: netdev, jiri, davem, edumazet, kuba, horms, shuah, bestswngs

On Fri, Mar 27, 2026 at 2:13 AM Xiang Mei <xmei5@asu.edu> wrote:
>
> The old-method path in fw_classify() calls tcf_block_q() and
> dereferences q->handle. Shared blocks leave block->q NULL, causing a
> NULL deref when an empty cls_fw filter is attached to a shared block
> and a packet with a nonzero major skb mark is classified.
>
> Check tcf_block_shared() before accessing block->q and return -1 (no
> match) for shared blocks, consistent with cls_u32's tc_u_common_ptr().
>
> The fixed null-ptr-deref calling stack:
>  KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
>  RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
>  Call Trace:
>   tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
>   tc_run (net/core/dev.c:4401)
>   __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
>
> Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
> Reported-by: Weiming Shi <bestswngs@gmail.com>
> Signed-off-by: Xiang Mei <xmei5@asu.edu>

Thanks for also providing the tdc tests. Looks like a bizarre bug—and
in my mind the question is does fw or flow even factor into tc blocks?
Please give me time to review if the approach makes sense - perhaps
this weekend.

cheers,
jamal

> ---
>  net/sched/cls_fw.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
> index be81c108179d..caf17ab3be87 100644
> --- a/net/sched/cls_fw.c
> +++ b/net/sched/cls_fw.c
> @@ -74,9 +74,14 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb,
>                         }
>                 }
>         } else {
> -               struct Qdisc *q = tcf_block_q(tp->chain->block);
> +               struct tcf_block *block = tp->chain->block;
> +               struct Qdisc *q;
> +
> +               if (tcf_block_shared(block))
> +                       return -1;
>
>                 /* Old method: classify the packet using its skb mark. */
> +               q = tcf_block_q(block);
>                 if (id && (TC_H_MAJ(id) == 0 ||
>                            !(TC_H_MAJ(id ^ q->handle)))) {
>                         res->classid = id;
> --
> 2.43.0
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks
  2026-03-27 14:11 ` [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference " Jamal Hadi Salim
@ 2026-03-29 12:15   ` Jamal Hadi Salim
  2026-03-29 18:52     ` Xiang Mei
  2026-03-30 13:40     ` [PATCH] net/sched: skip reverse bind walk after failed class delete Qi Tang
  0 siblings, 2 replies; 11+ messages in thread
From: Jamal Hadi Salim @ 2026-03-29 12:15 UTC (permalink / raw)
  To: Xiang Mei; +Cc: netdev, jiri, davem, edumazet, kuba, horms, shuah, bestswngs

On Fri, Mar 27, 2026 at 10:11 AM Jamal Hadi Salim <jhs@mojatatu.com> wrote:
>
> On Fri, Mar 27, 2026 at 2:13 AM Xiang Mei <xmei5@asu.edu> wrote:
> >
> > The old-method path in fw_classify() calls tcf_block_q() and
> > dereferences q->handle. Shared blocks leave block->q NULL, causing a
> > NULL deref when an empty cls_fw filter is attached to a shared block
> > and a packet with a nonzero major skb mark is classified.
> >
> > Check tcf_block_shared() before accessing block->q and return -1 (no
> > match) for shared blocks, consistent with cls_u32's tc_u_common_ptr().
> >
> > The fixed null-ptr-deref calling stack:
> >  KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
> >  RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
> >  Call Trace:
> >   tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
> >   tc_run (net/core/dev.c:4401)
> >   __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
> >
> > Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
> > Reported-by: Weiming Shi <bestswngs@gmail.com>
> > Signed-off-by: Xiang Mei <xmei5@asu.edu>
>
> Thanks for also providing the tdc tests. Looks like a bizarre bug—and
> in my mind the question is does fw or flow even factor into tc blocks?
> Please give me time to review if the approach makes sense - perhaps
> this weekend.
>
Since the fix is exactly as what u32 does - why not move
tc_u_common_ptr() to a header file (pkt_cls.h)? then reuse it in u32,
fw, and flow.

I am still questioning the value of using blocks with these two
classifiers and unfortunately the commit message of  1abf272022cf was
not helpful.
The testcases look good. Please add a letter head, perhaps quote the
comment in tc_u_common_ptr() since it gives a good description of this
whole dance.

cheers,
jamal

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] net/sched: skip reverse bind walk after failed class delete
@ 2026-03-29 16:53 Qi Tang
  2026-03-29 18:21 ` Jamal Hadi Salim
  0 siblings, 1 reply; 11+ messages in thread
From: Qi Tang @ 2026-03-29 16:53 UTC (permalink / raw)
  To: Jamal Hadi Salim, Jiri Pirko
  Cc: Cong Wang, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, Qi Tang

__tc_ctl_tclass() unconditionally calls tc_bind_tclass() after
RTM_DELTCLASS even when tclass_del_notify() fails.  On
ingress/clsact qdiscs with shared blocks, the delete always fails
with -EOPNOTSUPP, but the subsequent bind walk still runs.
tc_bind_tclass() reaches tcf_node_bind() which calls tcf_block_q()
on the shared block and dereferences the NULL qdisc pointer.

Only perform the reverse bind walk when the class delete succeeds.

Triggered by issuing RTM_DELTCLASS on an ingress/clsact pseudo-class
that carries a shared block with a classifier using bind_class:

  $ tc qdisc add dev veth0 egress_block 22 clsact
  $ tc filter add block 22 pref 1 protocol ip handle 0x1 \
      fw classid ffff:fff3 action drop
  $ tc class del dev veth0 classid ffff:fff3
  RTNETLINK answers: Operation not supported
  Kernel panic - not syncing: Attempted to kill init!
  exitcode=0x00000700

The NULL dereference occurs in tcf_node_bind() when sch_tree_lock()
is called with the NULL return from tcf_block_q() on a shared block.

Fixes: 07d79fc7d94e ("net_sched: add reverse binding for tc class")
Signed-off-by: Qi Tang <tpluszz77@gmail.com>
---
 net/sched/sch_api.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index cc43e3f7574f..50d311ff1f2d 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -2251,7 +2251,8 @@ static int __tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n,
 		case RTM_DELTCLASS:
 			err = tclass_del_notify(net, cops, skb, n, q, cl, extack);
 			/* Unbind the class with flilters with 0 */
-			tc_bind_tclass(q, portid, clid, 0);
+			if (!err)
+				tc_bind_tclass(q, portid, clid, 0);
 			goto out;
 		case RTM_GETTCLASS:
 			err = tclass_get_notify(net, skb, n, q, cl, extack);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] net/sched: skip reverse bind walk after failed class delete
  2026-03-29 16:53 Qi Tang
@ 2026-03-29 18:21 ` Jamal Hadi Salim
  0 siblings, 0 replies; 11+ messages in thread
From: Jamal Hadi Salim @ 2026-03-29 18:21 UTC (permalink / raw)
  To: Qi Tang
  Cc: Jiri Pirko, Cong Wang, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, netdev

On Sun, Mar 29, 2026 at 12:53 PM Qi Tang <tpluszz77@gmail.com> wrote:
>
> __tc_ctl_tclass() unconditionally calls tc_bind_tclass() after
> RTM_DELTCLASS even when tclass_del_notify() fails.  On
> ingress/clsact qdiscs with shared blocks, the delete always fails
> with -EOPNOTSUPP, but the subsequent bind walk still runs.
> tc_bind_tclass() reaches tcf_node_bind() which calls tcf_block_q()
> on the shared block and dereferences the NULL qdisc pointer.
>
> Only perform the reverse bind walk when the class delete succeeds.
>
> Triggered by issuing RTM_DELTCLASS on an ingress/clsact pseudo-class
> that carries a shared block with a classifier using bind_class:
>
>   $ tc qdisc add dev veth0 egress_block 22 clsact
>   $ tc filter add block 22 pref 1 protocol ip handle 0x1 \
>       fw classid ffff:fff3 action drop
>   $ tc class del dev veth0 classid ffff:fff3
>   RTNETLINK answers: Operation not supported
>   Kernel panic - not syncing: Attempted to kill init!
>   exitcode=0x00000700
>
> The NULL dereference occurs in tcf_node_bind() when sch_tree_lock()
> is called with the NULL return from tcf_block_q() on a shared block.
>

Try these patches:
https://lore.kernel.org/netdev/CAM0EoMmVey4ayJBZgogMO4S3Z-_n5oDfasdZyiVryEqCNqu6bw@mail.gmail.com/T/#t

Same for your other issue.

cheers,
jamal

> Fixes: 07d79fc7d94e ("net_sched: add reverse binding for tc class")
> Signed-off-by: Qi Tang <tpluszz77@gmail.com>
> ---
>  net/sched/sch_api.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
> index cc43e3f7574f..50d311ff1f2d 100644
> --- a/net/sched/sch_api.c
> +++ b/net/sched/sch_api.c
> @@ -2251,7 +2251,8 @@ static int __tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n,
>                 case RTM_DELTCLASS:
>                         err = tclass_del_notify(net, cops, skb, n, q, cl, extack);
>                         /* Unbind the class with flilters with 0 */
> -                       tc_bind_tclass(q, portid, clid, 0);
> +                       if (!err)
> +                               tc_bind_tclass(q, portid, clid, 0);
>                         goto out;
>                 case RTM_GETTCLASS:
>                         err = tclass_get_notify(net, skb, n, q, cl, extack);
> --
> 2.43.0
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks
  2026-03-29 12:15   ` Jamal Hadi Salim
@ 2026-03-29 18:52     ` Xiang Mei
  2026-03-30 16:45       ` Jamal Hadi Salim
  2026-03-30 13:40     ` [PATCH] net/sched: skip reverse bind walk after failed class delete Qi Tang
  1 sibling, 1 reply; 11+ messages in thread
From: Xiang Mei @ 2026-03-29 18:52 UTC (permalink / raw)
  To: Jamal Hadi Salim
  Cc: netdev, jiri, davem, edumazet, kuba, horms, shuah, bestswngs

On Sun, Mar 29, 2026 at 08:15:17AM -0400, Jamal Hadi Salim wrote:
> On Fri, Mar 27, 2026 at 10:11 AM Jamal Hadi Salim <jhs@mojatatu.com> wrote:
> >
> > On Fri, Mar 27, 2026 at 2:13 AM Xiang Mei <xmei5@asu.edu> wrote:
> > >
> > > The old-method path in fw_classify() calls tcf_block_q() and
> > > dereferences q->handle. Shared blocks leave block->q NULL, causing a
> > > NULL deref when an empty cls_fw filter is attached to a shared block
> > > and a packet with a nonzero major skb mark is classified.
> > >
> > > Check tcf_block_shared() before accessing block->q and return -1 (no
> > > match) for shared blocks, consistent with cls_u32's tc_u_common_ptr().
> > >
> > > The fixed null-ptr-deref calling stack:
> > >  KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
> > >  RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
> > >  Call Trace:
> > >   tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
> > >   tc_run (net/core/dev.c:4401)
> > >   __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
> > >
> > > Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
> > > Reported-by: Weiming Shi <bestswngs@gmail.com>
> > > Signed-off-by: Xiang Mei <xmei5@asu.edu>
> >
> > Thanks for also providing the tdc tests. Looks like a bizarre bug—and
> > in my mind the question is does fw or flow even factor into tc blocks?
> > Please give me time to review if the approach makes sense - perhaps
> > this weekend.
> >
> Since the fix is exactly as what u32 does - why not move
> tc_u_common_ptr() to a header file (pkt_cls.h)? then reuse it in u32,
> fw, and flow.

Thank you for the suggestion, I appreciate the review.

I spent some time exploring how to reuse tc_u_common_ptr() in cls_fw and
cls_flow, but I'm not sure I see a clean way to make it work across all 
three classifiers. The core issue is that they need different things 
when the block is shared:

 - cls_u32 needs a pointer value (block or block->q) as a hash key for 
   tc_u_common lookup
 - cls_fw and cls_flow need to bail out and return -1 (no match)

If we keep tc_u_common_ptr() as-is (returning void *), the usage in 
fw/flow would be tc_u_common_ptr(tp) == block to detect shared blocks,
which is less clear than tcf_block_shared(block) and doesn't save any 
code.

If we rework it to return struct Qdisc * (NULL for shared), it would
break cls_u32's current usage where it needs the block pointer itself
as a hash key for the shared case.

I may be misunderstanding your suggestion though — could you share 
what you had in mind? 

Thank you again for your time,
Xiang
> 
> I am still questioning the value of using blocks with these two
> classifiers and unfortunately the commit message of  1abf272022cf was
> not helpful.
> The testcases look good. Please add a letter head, perhaps quote the
> comment in tc_u_common_ptr() since it gives a good description of this
> whole dance.
> 
> cheers,
> jamal

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] net/sched: skip reverse bind walk after failed class delete
  2026-03-29 12:15   ` Jamal Hadi Salim
  2026-03-29 18:52     ` Xiang Mei
@ 2026-03-30 13:40     ` Qi Tang
  1 sibling, 0 replies; 11+ messages in thread
From: Qi Tang @ 2026-03-30 13:40 UTC (permalink / raw)
  To: Jamal Hadi Salim; +Cc: Jiri Pirko, netdev, Qi Tang

On Mon, Mar 30, 2026, Jamal Hadi Salim wrote:
> Try these patches:
> https://lore.kernel.org/netdev/CAM0EoMmVey4ayJBZgogMO4S3Z-_n5oDfasdZyiVryEqCNqu6bw@mail.gmail.com/T/#t
>
> Same for your other issue.

Thanks for the pointer, Jamal. Please disregard my two net/sched
patches.

Qi Tang

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks
  2026-03-29 18:52     ` Xiang Mei
@ 2026-03-30 16:45       ` Jamal Hadi Salim
  2026-03-31  5:04         ` Xiang Mei
  0 siblings, 1 reply; 11+ messages in thread
From: Jamal Hadi Salim @ 2026-03-30 16:45 UTC (permalink / raw)
  To: Xiang Mei; +Cc: netdev, jiri, davem, edumazet, kuba, horms, shuah, bestswngs

On Sun, Mar 29, 2026 at 2:52 PM Xiang Mei <xmei5@asu.edu> wrote:
>
> On Sun, Mar 29, 2026 at 08:15:17AM -0400, Jamal Hadi Salim wrote:
> > On Fri, Mar 27, 2026 at 10:11 AM Jamal Hadi Salim <jhs@mojatatu.com> wrote:
> > >
> > > On Fri, Mar 27, 2026 at 2:13 AM Xiang Mei <xmei5@asu.edu> wrote:
> > > >
> > > > The old-method path in fw_classify() calls tcf_block_q() and
> > > > dereferences q->handle. Shared blocks leave block->q NULL, causing a
> > > > NULL deref when an empty cls_fw filter is attached to a shared block
> > > > and a packet with a nonzero major skb mark is classified.
> > > >
> > > > Check tcf_block_shared() before accessing block->q and return -1 (no
> > > > match) for shared blocks, consistent with cls_u32's tc_u_common_ptr().
> > > >
> > > > The fixed null-ptr-deref calling stack:
> > > >  KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
> > > >  RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
> > > >  Call Trace:
> > > >   tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
> > > >   tc_run (net/core/dev.c:4401)
> > > >   __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
> > > >
> > > > Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
> > > > Reported-by: Weiming Shi <bestswngs@gmail.com>
> > > > Signed-off-by: Xiang Mei <xmei5@asu.edu>
> > >
> > > Thanks for also providing the tdc tests. Looks like a bizarre bug—and
> > > in my mind the question is does fw or flow even factor into tc blocks?
> > > Please give me time to review if the approach makes sense - perhaps
> > > this weekend.
> > >
> > Since the fix is exactly as what u32 does - why not move
> > tc_u_common_ptr() to a header file (pkt_cls.h)? then reuse it in u32,
> > fw, and flow.
>
> Thank you for the suggestion, I appreciate the review.
>

Actually on second thought - why dont you fix the fw one so it catches
things at control time? Something like:

--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -247,8 +247,18 @@ static int fw_change(struct net *net, struct
sk_buff *in_skb,
        struct nlattr *tb[TCA_FW_MAX + 1];
        int err;

-       if (!opt)
-               return handle ? -EINVAL : 0; /* Succeed if it is old method. */
+       if (!opt) {
+               if (handle)
+                       return -EINVAL;
+
+               if (tcf_block_shared(tp->chain->block)) {
+                       NL_SET_ERR_MSG(extack,
+                                      "Must specify mark when
attaching fw filter to block");
+                       return -EINVAL;
+               }
+
+               return 0; /* Succeed if it is old method. */
+       }

        err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
                                          NULL);

Also for the flow one, can you add an extack like above.
Note: This will change the nature of your tdc test, you dont need to
send an skb marked packet anymore since your config will be reject the
setup..

cheers,
jamal

> I spent some time exploring how to reuse tc_u_common_ptr() in cls_fw and
> cls_flow, but I'm not sure I see a clean way to make it work across all
> three classifiers. The core issue is that they need different things
> when the block is shared:
>
>  - cls_u32 needs a pointer value (block or block->q) as a hash key for
>    tc_u_common lookup
>  - cls_fw and cls_flow need to bail out and return -1 (no match)
>
> If we keep tc_u_common_ptr() as-is (returning void *), the usage in
> fw/flow would be tc_u_common_ptr(tp) == block to detect shared blocks,
> which is less clear than tcf_block_shared(block) and doesn't save any
> code.
>
> If we rework it to return struct Qdisc * (NULL for shared), it would
> break cls_u32's current usage where it needs the block pointer itself
> as a hash key for the shared case.
>
> I may be misunderstanding your suggestion though — could you share
> what you had in mind?
>
> Thank you again for your time,
> Xiang
> >
> > I am still questioning the value of using blocks with these two
> > classifiers and unfortunately the commit message of  1abf272022cf was
> > not helpful.
> > The testcases look good. Please add a letter head, perhaps quote the
> > comment in tc_u_common_ptr() since it gives a good description of this
> > whole dance.
> >
> > cheers,
> > jamal

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks
  2026-03-30 16:45       ` Jamal Hadi Salim
@ 2026-03-31  5:04         ` Xiang Mei
  0 siblings, 0 replies; 11+ messages in thread
From: Xiang Mei @ 2026-03-31  5:04 UTC (permalink / raw)
  To: Jamal Hadi Salim
  Cc: netdev, jiri, davem, edumazet, kuba, horms, shuah, bestswngs

Thanks for the review and advice. It's a better patch. I have sent the v3:
- for cls_fw and cls_flow, we check in fw/flow_change
- Adjust the tests

Thanks,
Xiang

On Mon, Mar 30, 2026 at 9:46 AM Jamal Hadi Salim <jhs@mojatatu.com> wrote:
>
> On Sun, Mar 29, 2026 at 2:52 PM Xiang Mei <xmei5@asu.edu> wrote:
> >
> > On Sun, Mar 29, 2026 at 08:15:17AM -0400, Jamal Hadi Salim wrote:
> > > On Fri, Mar 27, 2026 at 10:11 AM Jamal Hadi Salim <jhs@mojatatu.com> wrote:
> > > >
> > > > On Fri, Mar 27, 2026 at 2:13 AM Xiang Mei <xmei5@asu.edu> wrote:
> > > > >
> > > > > The old-method path in fw_classify() calls tcf_block_q() and
> > > > > dereferences q->handle. Shared blocks leave block->q NULL, causing a
> > > > > NULL deref when an empty cls_fw filter is attached to a shared block
> > > > > and a packet with a nonzero major skb mark is classified.
> > > > >
> > > > > Check tcf_block_shared() before accessing block->q and return -1 (no
> > > > > match) for shared blocks, consistent with cls_u32's tc_u_common_ptr().
> > > > >
> > > > > The fixed null-ptr-deref calling stack:
> > > > >  KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
> > > > >  RIP: 0010:fw_classify (net/sched/cls_fw.c:81)
> > > > >  Call Trace:
> > > > >   tcf_classify (./include/net/tc_wrapper.h:197 net/sched/cls_api.c:1764 net/sched/cls_api.c:1860)
> > > > >   tc_run (net/core/dev.c:4401)
> > > > >   __dev_queue_xmit (net/core/dev.c:4535 net/core/dev.c:4790)
> > > > >
> > > > > Fixes: 1abf272022cf ("net: sched: tcindex, fw, flow: use tcf_block_q helper to get struct Qdisc")
> > > > > Reported-by: Weiming Shi <bestswngs@gmail.com>
> > > > > Signed-off-by: Xiang Mei <xmei5@asu.edu>
> > > >
> > > > Thanks for also providing the tdc tests. Looks like a bizarre bug—and
> > > > in my mind the question is does fw or flow even factor into tc blocks?
> > > > Please give me time to review if the approach makes sense - perhaps
> > > > this weekend.
> > > >
> > > Since the fix is exactly as what u32 does - why not move
> > > tc_u_common_ptr() to a header file (pkt_cls.h)? then reuse it in u32,
> > > fw, and flow.
> >
> > Thank you for the suggestion, I appreciate the review.
> >
>
> Actually on second thought - why dont you fix the fw one so it catches
> things at control time? Something like:
>
> --- a/net/sched/cls_fw.c
> +++ b/net/sched/cls_fw.c
> @@ -247,8 +247,18 @@ static int fw_change(struct net *net, struct
> sk_buff *in_skb,
>         struct nlattr *tb[TCA_FW_MAX + 1];
>         int err;
>
> -       if (!opt)
> -               return handle ? -EINVAL : 0; /* Succeed if it is old method. */
> +       if (!opt) {
> +               if (handle)
> +                       return -EINVAL;
> +
> +               if (tcf_block_shared(tp->chain->block)) {
> +                       NL_SET_ERR_MSG(extack,
> +                                      "Must specify mark when
> attaching fw filter to block");
> +                       return -EINVAL;
> +               }
> +
> +               return 0; /* Succeed if it is old method. */
> +       }
>
>         err = nla_parse_nested_deprecated(tb, TCA_FW_MAX, opt, fw_policy,
>                                           NULL);
>
> Also for the flow one, can you add an extack like above.
> Note: This will change the nature of your tdc test, you dont need to
> send an skb marked packet anymore since your config will be reject the
> setup..
>
> cheers,
> jamal
>
> > I spent some time exploring how to reuse tc_u_common_ptr() in cls_fw and
> > cls_flow, but I'm not sure I see a clean way to make it work across all
> > three classifiers. The core issue is that they need different things
> > when the block is shared:
> >
> >  - cls_u32 needs a pointer value (block or block->q) as a hash key for
> >    tc_u_common lookup
> >  - cls_fw and cls_flow need to bail out and return -1 (no match)
> >
> > If we keep tc_u_common_ptr() as-is (returning void *), the usage in
> > fw/flow would be tc_u_common_ptr(tp) == block to detect shared blocks,
> > which is less clear than tcf_block_shared(block) and doesn't save any
> > code.
> >
> > If we rework it to return struct Qdisc * (NULL for shared), it would
> > break cls_u32's current usage where it needs the block pointer itself
> > as a hash key for the shared case.
> >
> > I may be misunderstanding your suggestion though — could you share
> > what you had in mind?
> >
> > Thank you again for your time,
> > Xiang
> > >
> > > I am still questioning the value of using blocks with these two
> > > classifiers and unfortunately the commit message of  1abf272022cf was
> > > not helpful.
> > > The testcases look good. Please add a letter head, perhaps quote the
> > > comment in tc_u_common_ptr() since it gives a good description of this
> > > whole dance.
> > >
> > > cheers,
> > > jamal

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-03-31  5:04 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-27  6:12 [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference on shared blocks Xiang Mei
2026-03-27  6:12 ` [PATCH net 2/3] net/sched: cls_flow: " Xiang Mei
2026-03-27  6:13 ` [PATCH net 3/3] selftests/tc-testing: add tests for cls_fw and cls_flow " Xiang Mei
2026-03-27 14:11 ` [PATCH net 1/3] net/sched: cls_fw: fix NULL pointer dereference " Jamal Hadi Salim
2026-03-29 12:15   ` Jamal Hadi Salim
2026-03-29 18:52     ` Xiang Mei
2026-03-30 16:45       ` Jamal Hadi Salim
2026-03-31  5:04         ` Xiang Mei
2026-03-30 13:40     ` [PATCH] net/sched: skip reverse bind walk after failed class delete Qi Tang
  -- strict thread matches above, loose matches on Subject: below --
2026-03-29 16:53 Qi Tang
2026-03-29 18:21 ` Jamal Hadi Salim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox