* [PATCH V3] net: rose: Prevent the use of freed digipeat
@ 2025-10-24 9:39 Lizhi Xu
2025-10-24 11:49 ` Eric Dumazet
2025-10-25 2:18 ` Kuniyuki Iwashima
0 siblings, 2 replies; 11+ messages in thread
From: Lizhi Xu @ 2025-10-24 9:39 UTC (permalink / raw)
To: edumazet
Cc: davem, horms, jreuter, kuba, kuniyu, linux-hams, linux-kernel,
lizhi.xu, netdev, pabeni, syzbot+caa052a0958a9146870d,
syzkaller-bugs
There is no synchronization between the two timers, rose_t0timer_expiry
and rose_timer_expiry.
rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2.
However, rose_t0timer_expiry() does initiate a restart request on the
neighbor.
When rose_t0timer_expiry() accesses the released neighbor member digipeat,
a UAF is triggered.
To avoid this UAF, defer the put operation to rose_t0timer_expiry() and
stop restarting t0timer after putting the neighbor.
When putting the neighbor, set the neighbor to NULL. Setting neighbor to
NULL prevents rose_t0timer_expiry() from restarting t0timer.
syzbot reported a slab-use-after-free Read in ax25_find_cb.
BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237
Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200
Call Trace:
ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237
ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55
rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106
rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198
rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83
Freed by task 17183:
kfree+0x2b8/0x6d0 mm/slub.c:6826
rose_neigh_put include/net/rose.h:165 [inline]
rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183
Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t")
Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com
Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com>
---
V1 -> V2: Putting the neighbor stops t0timer from automatically starting
V2 -> V3: add rose_neigh_putex for set rose neigh to NULL
include/net/rose.h | 12 ++++++++++++
net/rose/rose_link.c | 5 +++++
2 files changed, 17 insertions(+)
diff --git a/include/net/rose.h b/include/net/rose.h
index 2b5491bbf39a..33de310ba778 100644
--- a/include/net/rose.h
+++ b/include/net/rose.h
@@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh)
}
}
+static inline void rose_neigh_putex(struct rose_neigh **roseneigh)
+{
+ struct rose_neigh *rose_neigh = *roseneigh;
+ if (refcount_dec_and_test(&rose_neigh->use)) {
+ if (rose_neigh->ax25)
+ ax25_cb_put(rose_neigh->ax25);
+ kfree(rose_neigh->digipeat);
+ kfree(rose_neigh);
+ *roseneigh = NULL;
+ }
+}
+
/* af_rose.c */
extern ax25_address rose_callsign;
extern int sysctl_rose_restart_request_timeout;
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index 7746229fdc8c..334c8cc0876d 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh)
static void rose_start_t0timer(struct rose_neigh *neigh)
{
+ if (!neigh)
+ return;
+
timer_delete(&neigh->t0timer);
neigh->t0timer.function = rose_t0timer_expiry;
@@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t)
{
struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer);
+ rose_neigh_hold(neigh);
rose_transmit_restart_request(neigh);
neigh->dce_mode = 0;
+ rose_neigh_putex(&neigh);
rose_start_t0timer(neigh);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-24 9:39 [PATCH V3] net: rose: Prevent the use of freed digipeat Lizhi Xu @ 2025-10-24 11:49 ` Eric Dumazet 2025-10-25 1:48 ` Lizhi Xu 2025-10-25 2:18 ` Kuniyuki Iwashima 1 sibling, 1 reply; 11+ messages in thread From: Eric Dumazet @ 2025-10-24 11:49 UTC (permalink / raw) To: Lizhi Xu Cc: davem, horms, jreuter, kuba, kuniyu, linux-hams, linux-kernel, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > There is no synchronization between the two timers, rose_t0timer_expiry > and rose_timer_expiry. > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > However, rose_t0timer_expiry() does initiate a restart request on the > neighbor. > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > a UAF is triggered. > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > stop restarting t0timer after putting the neighbor. > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > Call Trace: > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > Freed by task 17183: > kfree+0x2b8/0x6d0 mm/slub.c:6826 > rose_neigh_put include/net/rose.h:165 [inline] > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > --- > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > include/net/rose.h | 12 ++++++++++++ > net/rose/rose_link.c | 5 +++++ > 2 files changed, 17 insertions(+) > > diff --git a/include/net/rose.h b/include/net/rose.h > index 2b5491bbf39a..33de310ba778 100644 > --- a/include/net/rose.h > +++ b/include/net/rose.h > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > } > } > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > +{ > + struct rose_neigh *rose_neigh = *roseneigh; > + if (refcount_dec_and_test(&rose_neigh->use)) { > + if (rose_neigh->ax25) > + ax25_cb_put(rose_neigh->ax25); > + kfree(rose_neigh->digipeat); > + kfree(rose_neigh); > + *roseneigh = NULL; > + } > +} You have not even compiled this patch. Also please carefully read Documentation/process/maintainer-netdev.rst Resending after review ~~~~~~~~~~~~~~~~~~~~~~ Allow at least 24 hours to pass between postings. This will ensure reviewers from all geographical locations have a chance to chime in. Do not wait too long (weeks) between postings either as it will make it harder for reviewers to recall all the context. Make sure you address all the feedback in your new posting. Do not post a new version of the code if the discussion about the previous version is still ongoing, unless directly instructed by a reviewer. The new version of patches should be posted as a separate thread, not as a reply to the previous posting. Change log should include a link to the previous posting (see :ref:`Changes requested`). ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-24 11:49 ` Eric Dumazet @ 2025-10-25 1:48 ` Lizhi Xu 0 siblings, 0 replies; 11+ messages in thread From: Lizhi Xu @ 2025-10-25 1:48 UTC (permalink / raw) To: edumazet Cc: davem, horms, jreuter, kuba, kuniyu, linux-hams, linux-kernel, lizhi.xu, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset="y", Size: 2836 bytes --] On Fri, 24 Oct 2025 04:49:55 -0700, Eric Dumazet <edumazet@google.com> wrote: > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > and rose_timer_expiry. > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > However, rose_t0timer_expiry() does initiate a restart request on the > > neighbor. > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > a UAF is triggered. > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > stop restarting t0timer after putting the neighbor. > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > Call Trace: > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > Freed by task 17183: > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > rose_neigh_put include/net/rose.h:165 [inline] > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > --- > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > include/net/rose.h | 12 ++++++++++++ > > net/rose/rose_link.c | 5 +++++ > > 2 files changed, 17 insertions(+) > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > index 2b5491bbf39a..33de310ba778 100644 > > --- a/include/net/rose.h > > +++ b/include/net/rose.h > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > } > > } > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > +{ > > + struct rose_neigh *rose_neigh = *roseneigh; > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > + if (rose_neigh->ax25) > > + ax25_cb_put(rose_neigh->ax25); > > + kfree(rose_neigh->digipeat); > > + kfree(rose_neigh); > > + *roseneigh = NULL; > > + } > > +} > > You have not even compiled this patch. 580K -rw-r--r-- 1 lzx users 578K Oct 24 17:35 net/rose/rose_link.o ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-24 9:39 [PATCH V3] net: rose: Prevent the use of freed digipeat Lizhi Xu 2025-10-24 11:49 ` Eric Dumazet @ 2025-10-25 2:18 ` Kuniyuki Iwashima 2025-10-25 3:51 ` Lizhi Xu 1 sibling, 1 reply; 11+ messages in thread From: Kuniyuki Iwashima @ 2025-10-25 2:18 UTC (permalink / raw) To: Lizhi Xu Cc: edumazet, davem, horms, jreuter, kuba, linux-hams, linux-kernel, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > There is no synchronization between the two timers, rose_t0timer_expiry > and rose_timer_expiry. > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > However, rose_t0timer_expiry() does initiate a restart request on the > neighbor. > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > a UAF is triggered. > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > stop restarting t0timer after putting the neighbor. > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > Call Trace: > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > Freed by task 17183: > kfree+0x2b8/0x6d0 mm/slub.c:6826 > rose_neigh_put include/net/rose.h:165 [inline] > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > --- > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > include/net/rose.h | 12 ++++++++++++ > net/rose/rose_link.c | 5 +++++ > 2 files changed, 17 insertions(+) > > diff --git a/include/net/rose.h b/include/net/rose.h > index 2b5491bbf39a..33de310ba778 100644 > --- a/include/net/rose.h > +++ b/include/net/rose.h > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > } > } > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > +{ > + struct rose_neigh *rose_neigh = *roseneigh; > + if (refcount_dec_and_test(&rose_neigh->use)) { > + if (rose_neigh->ax25) > + ax25_cb_put(rose_neigh->ax25); > + kfree(rose_neigh->digipeat); > + kfree(rose_neigh); > + *roseneigh = NULL; > + } > +} > + > /* af_rose.c */ > extern ax25_address rose_callsign; > extern int sysctl_rose_restart_request_timeout; > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > index 7746229fdc8c..334c8cc0876d 100644 > --- a/net/rose/rose_link.c > +++ b/net/rose/rose_link.c > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > static void rose_start_t0timer(struct rose_neigh *neigh) > { > + if (!neigh) > + return; > + > timer_delete(&neigh->t0timer); > > neigh->t0timer.function = rose_t0timer_expiry; > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > { > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > What prevents rose_timer_expiry() from releasing the last refcnt here ? The t0timer could be triggered even after that happens. > + rose_neigh_hold(neigh); > rose_transmit_restart_request(neigh); > > neigh->dce_mode = 0; > > + rose_neigh_putex(&neigh); > rose_start_t0timer(neigh); > } > > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-25 2:18 ` Kuniyuki Iwashima @ 2025-10-25 3:51 ` Lizhi Xu 2025-10-25 4:25 ` Kuniyuki Iwashima 0 siblings, 1 reply; 11+ messages in thread From: Lizhi Xu @ 2025-10-25 3:51 UTC (permalink / raw) To: kuniyu Cc: davem, edumazet, horms, jreuter, kuba, linux-hams, linux-kernel, lizhi.xu, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset="y", Size: 4426 bytes --] On Fri, 24 Oct 2025 19:18:46 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > and rose_timer_expiry. > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > However, rose_t0timer_expiry() does initiate a restart request on the > > neighbor. > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > a UAF is triggered. > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > stop restarting t0timer after putting the neighbor. > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > Call Trace: > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > Freed by task 17183: > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > rose_neigh_put include/net/rose.h:165 [inline] > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > --- > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > include/net/rose.h | 12 ++++++++++++ > > net/rose/rose_link.c | 5 +++++ > > 2 files changed, 17 insertions(+) > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > index 2b5491bbf39a..33de310ba778 100644 > > --- a/include/net/rose.h > > +++ b/include/net/rose.h > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > } > > } > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > +{ > > + struct rose_neigh *rose_neigh = *roseneigh; > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > + if (rose_neigh->ax25) > > + ax25_cb_put(rose_neigh->ax25); > > + kfree(rose_neigh->digipeat); > > + kfree(rose_neigh); > > + *roseneigh = NULL; > > + } > > +} > > + > > /* af_rose.c */ > > extern ax25_address rose_callsign; > > extern int sysctl_rose_restart_request_timeout; > > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > > index 7746229fdc8c..334c8cc0876d 100644 > > --- a/net/rose/rose_link.c > > +++ b/net/rose/rose_link.c > > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > > > static void rose_start_t0timer(struct rose_neigh *neigh) > > { > > + if (!neigh) > > + return; > > + > > timer_delete(&neigh->t0timer); > > > > neigh->t0timer.function = rose_t0timer_expiry; > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > { > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > What prevents rose_timer_expiry() from releasing the > last refcnt here ? The issue reported by syzbot is that rose_t0timer_expiry() is triggered first, followed by rose_timer_expiry(). Therefore, in rose_t0timer_expiry(), the reference count of neigh is increased before entering rose_transmit_restart_request() to prevent neigh from being put in rose_timer_expiry(). Then, in rose_t0timer_expiry(), neigh is put before executing rose_start_t0timer() and the neigh value is set to NULL to prevent t0timer restarts. The case where rose_timer_expiry() is triggered before rose_t0timer_expiry() is not considered at this time. > > The t0timer could be triggered even after that happens. > > > > + rose_neigh_hold(neigh); > > rose_transmit_restart_request(neigh); > > > > neigh->dce_mode = 0; > > > > + rose_neigh_putex(&neigh); > > rose_start_t0timer(neigh); > > } > > > > -- > > 2.43.0 > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-25 3:51 ` Lizhi Xu @ 2025-10-25 4:25 ` Kuniyuki Iwashima 2025-10-25 6:46 ` Lizhi Xu 0 siblings, 1 reply; 11+ messages in thread From: Kuniyuki Iwashima @ 2025-10-25 4:25 UTC (permalink / raw) To: Lizhi Xu Cc: davem, edumazet, horms, jreuter, kuba, linux-hams, linux-kernel, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Fri, Oct 24, 2025 at 8:51 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > On Fri, 24 Oct 2025 19:18:46 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > > and rose_timer_expiry. > > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > > However, rose_t0timer_expiry() does initiate a restart request on the > > > neighbor. > > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > > a UAF is triggered. > > > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > > stop restarting t0timer after putting the neighbor. > > > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > > Call Trace: > > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > > > Freed by task 17183: > > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > > rose_neigh_put include/net/rose.h:165 [inline] > > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > > --- > > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > > > include/net/rose.h | 12 ++++++++++++ > > > net/rose/rose_link.c | 5 +++++ > > > 2 files changed, 17 insertions(+) > > > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > > index 2b5491bbf39a..33de310ba778 100644 > > > --- a/include/net/rose.h > > > +++ b/include/net/rose.h > > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > > } > > > } > > > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > > +{ > > > + struct rose_neigh *rose_neigh = *roseneigh; > > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > > + if (rose_neigh->ax25) > > > + ax25_cb_put(rose_neigh->ax25); > > > + kfree(rose_neigh->digipeat); > > > + kfree(rose_neigh); > > > + *roseneigh = NULL; > > > + } > > > +} > > > + > > > /* af_rose.c */ > > > extern ax25_address rose_callsign; > > > extern int sysctl_rose_restart_request_timeout; > > > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > > > index 7746229fdc8c..334c8cc0876d 100644 > > > --- a/net/rose/rose_link.c > > > +++ b/net/rose/rose_link.c > > > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > > > > > static void rose_start_t0timer(struct rose_neigh *neigh) > > > { > > > + if (!neigh) > > > + return; > > > + > > > timer_delete(&neigh->t0timer); > > > > > > neigh->t0timer.function = rose_t0timer_expiry; > > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > > { > > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > > > > What prevents rose_timer_expiry() from releasing the > > last refcnt here ? > The issue reported by syzbot is that rose_t0timer_expiry() is triggered > first, followed by rose_timer_expiry(). I don't see how you read that ordering from the report. https://syzkaller.appspot.com/bug?extid=caa052a0958a9146870d The only ordering I can find is that kfree() in rose_timer_expiry() happened before ax25_find_cb () in rose_t0timer_expiry(). > Therefore, in rose_t0timer_expiry(), the reference count of neigh is > increased before entering rose_transmit_restart_request() to prevent > neigh from being put in rose_timer_expiry(). Then, in rose_t0timer_expiry(), > neigh is put before executing rose_start_t0timer() and the neigh value is > set to NULL to prevent t0timer restarts. > > The case where rose_timer_expiry() is triggered before rose_t0timer_expiry() > is not considered at this time. So this change just papers over the root cause. > > > > The t0timer could be triggered even after that happens. > > > > > > > + rose_neigh_hold(neigh); > > > rose_transmit_restart_request(neigh); > > > > > > neigh->dce_mode = 0; > > > > > > + rose_neigh_putex(&neigh); > > > rose_start_t0timer(neigh); > > > } > > > > > > -- > > > 2.43.0 > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-25 4:25 ` Kuniyuki Iwashima @ 2025-10-25 6:46 ` Lizhi Xu 2025-10-25 7:15 ` Kuniyuki Iwashima 0 siblings, 1 reply; 11+ messages in thread From: Lizhi Xu @ 2025-10-25 6:46 UTC (permalink / raw) To: kuniyu Cc: davem, edumazet, horms, jreuter, kuba, linux-hams, linux-kernel, lizhi.xu, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Fri, 24 Oct 2025 21:25:20 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > On Fri, Oct 24, 2025 at 8:51 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > On Fri, 24 Oct 2025 19:18:46 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > > > and rose_timer_expiry. > > > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > > > However, rose_t0timer_expiry() does initiate a restart request on the > > > > neighbor. > > > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > > > a UAF is triggered. > > > > > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > > > stop restarting t0timer after putting the neighbor. > > > > > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > > > Call Trace: > > > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > > > > > Freed by task 17183: > > > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > > > rose_neigh_put include/net/rose.h:165 [inline] > > > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > > > --- > > > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > > > > > include/net/rose.h | 12 ++++++++++++ > > > > net/rose/rose_link.c | 5 +++++ > > > > 2 files changed, 17 insertions(+) > > > > > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > > > index 2b5491bbf39a..33de310ba778 100644 > > > > --- a/include/net/rose.h > > > > +++ b/include/net/rose.h > > > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > > > } > > > > } > > > > > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > > > +{ > > > > + struct rose_neigh *rose_neigh = *roseneigh; > > > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > > > + if (rose_neigh->ax25) > > > > + ax25_cb_put(rose_neigh->ax25); > > > > + kfree(rose_neigh->digipeat); > > > > + kfree(rose_neigh); > > > > + *roseneigh = NULL; > > > > + } > > > > +} > > > > + > > > > /* af_rose.c */ > > > > extern ax25_address rose_callsign; > > > > extern int sysctl_rose_restart_request_timeout; > > > > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > > > > index 7746229fdc8c..334c8cc0876d 100644 > > > > --- a/net/rose/rose_link.c > > > > +++ b/net/rose/rose_link.c > > > > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > > > > > > > static void rose_start_t0timer(struct rose_neigh *neigh) > > > > { > > > > + if (!neigh) > > > > + return; > > > > + > > > > timer_delete(&neigh->t0timer); > > > > > > > > neigh->t0timer.function = rose_t0timer_expiry; > > > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > > > { > > > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > > > > > > > What prevents rose_timer_expiry() from releasing the > > > last refcnt here ? > > The issue reported by syzbot is that rose_t0timer_expiry() is triggered > > first, followed by rose_timer_expiry(). > > I don't see how you read that ordering from the report. > https://syzkaller.appspot.com/bug?extid=caa052a0958a9146870d Here's my understanding: See the two calltraces below. [1] Line 111 occurs after rose_neigh_put(). Otherwise, accessing neigh->digipeat would result in a UAF. Therefore, rose_t0timer_expiry() must be triggered before rose_timer_expiry(). [2] syzbot reports that line 237 generates a UAF when accessing digi->ndigi. UAF Task1: rose_t0timer_expiry()-> rose_transmit_restart_request()-> rose_send_frame(.., neigh->digipeat, ..)-> // [1] line 111 ax25_find_cb()-> if (digi != NULL && digi->ndigi != 0) // [2] line 237 Freed neigh Task2: rose_timer_expiry()-> rose_neigh_put(neigh)-> kfree(neigh) > > The only ordering I can find is that kfree() in rose_timer_expiry() > happened before ax25_find_cb () in rose_t0timer_expiry(). > > > Therefore, in rose_t0timer_expiry(), the reference count of neigh is > > increased before entering rose_transmit_restart_request() to prevent > > neigh from being put in rose_timer_expiry(). Then, in rose_t0timer_expiry(), > > neigh is put before executing rose_start_t0timer() and the neigh value is > > set to NULL to prevent t0timer restarts. > > > > The case where rose_timer_expiry() is triggered before rose_t0timer_expiry() > > is not considered at this time. > > So this change just papers over the root cause. > > > > > > > > The t0timer could be triggered even after that happens. > > > > > > > > > > + rose_neigh_hold(neigh); > > > > rose_transmit_restart_request(neigh); > > > > > > > > neigh->dce_mode = 0; > > > > > > > > + rose_neigh_putex(&neigh); > > > > rose_start_t0timer(neigh); > > > > } > > > > > > > > -- > > > > 2.43.0 > > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-25 6:46 ` Lizhi Xu @ 2025-10-25 7:15 ` Kuniyuki Iwashima 2025-10-25 7:53 ` Lizhi Xu 0 siblings, 1 reply; 11+ messages in thread From: Kuniyuki Iwashima @ 2025-10-25 7:15 UTC (permalink / raw) To: Lizhi Xu Cc: davem, edumazet, horms, jreuter, kuba, linux-hams, linux-kernel, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Fri, Oct 24, 2025 at 11:46 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > On Fri, 24 Oct 2025 21:25:20 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > On Fri, Oct 24, 2025 at 8:51 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > On Fri, 24 Oct 2025 19:18:46 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > > > > and rose_timer_expiry. > > > > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > > > > However, rose_t0timer_expiry() does initiate a restart request on the > > > > > neighbor. > > > > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > > > > a UAF is triggered. > > > > > > > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > > > > stop restarting t0timer after putting the neighbor. > > > > > > > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > > > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > > > > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > > > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > > > > Call Trace: > > > > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > > > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > > > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > > > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > > > > > > > Freed by task 17183: > > > > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > > > > rose_neigh_put include/net/rose.h:165 [inline] > > > > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > > > > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > > > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > > > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > > > > --- > > > > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > > > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > > > > > > > include/net/rose.h | 12 ++++++++++++ > > > > > net/rose/rose_link.c | 5 +++++ > > > > > 2 files changed, 17 insertions(+) > > > > > > > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > > > > index 2b5491bbf39a..33de310ba778 100644 > > > > > --- a/include/net/rose.h > > > > > +++ b/include/net/rose.h > > > > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > > > > } > > > > > } > > > > > > > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > > > > +{ > > > > > + struct rose_neigh *rose_neigh = *roseneigh; > > > > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > > > > + if (rose_neigh->ax25) > > > > > + ax25_cb_put(rose_neigh->ax25); > > > > > + kfree(rose_neigh->digipeat); > > > > > + kfree(rose_neigh); > > > > > + *roseneigh = NULL; > > > > > + } > > > > > +} > > > > > + > > > > > /* af_rose.c */ > > > > > extern ax25_address rose_callsign; > > > > > extern int sysctl_rose_restart_request_timeout; > > > > > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > > > > > index 7746229fdc8c..334c8cc0876d 100644 > > > > > --- a/net/rose/rose_link.c > > > > > +++ b/net/rose/rose_link.c > > > > > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > > > > > > > > > static void rose_start_t0timer(struct rose_neigh *neigh) > > > > > { > > > > > + if (!neigh) > > > > > + return; > > > > > + > > > > > timer_delete(&neigh->t0timer); > > > > > > > > > > neigh->t0timer.function = rose_t0timer_expiry; > > > > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > > > > { > > > > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > > > > > > > > > > What prevents rose_timer_expiry() from releasing the > > > > last refcnt here ? > > > The issue reported by syzbot is that rose_t0timer_expiry() is triggered > > > first, followed by rose_timer_expiry(). > > > > I don't see how you read that ordering from the report. > > https://syzkaller.appspot.com/bug?extid=caa052a0958a9146870d > Here's my understanding: See the two calltraces below. The same question still applies. What prevents rose_timer_expiry() from releasing the last refcnt before [1] ? For example, why is accessing neigh->dev in rose_send_frame() safe then ? The commit message mentions that two timers are not synchronised, but the diff adds no such synchronisation. > [1] Line 111 occurs after rose_neigh_put(). Otherwise, accessing > neigh->digipeat would result in a UAF. Therefore, rose_t0timer_expiry() > must be triggered before rose_timer_expiry(). > > [2] syzbot reports that line 237 generates a UAF when accessing digi->ndigi. > > UAF Task1: > rose_t0timer_expiry()-> > rose_transmit_restart_request()-> > rose_send_frame(.., neigh->digipeat, ..)-> // [1] line 111 > ax25_find_cb()-> > if (digi != NULL && digi->ndigi != 0) // [2] line 237 > > Freed neigh Task2: > rose_timer_expiry()-> > rose_neigh_put(neigh)-> > kfree(neigh) > > > > The only ordering I can find is that kfree() in rose_timer_expiry() > > happened before ax25_find_cb () in rose_t0timer_expiry(). > > > > > Therefore, in rose_t0timer_expiry(), the reference count of neigh is > > > increased before entering rose_transmit_restart_request() to prevent > > > neigh from being put in rose_timer_expiry(). Then, in rose_t0timer_expiry(), > > > neigh is put before executing rose_start_t0timer() and the neigh value is > > > set to NULL to prevent t0timer restarts. > > > > > > The case where rose_timer_expiry() is triggered before rose_t0timer_expiry() > > > is not considered at this time. > > > > So this change just papers over the root cause. > > > > > > > > > > > > The t0timer could be triggered even after that happens. > > > > > > > > > > > > > + rose_neigh_hold(neigh); > > > > > rose_transmit_restart_request(neigh); > > > > > > > > > > neigh->dce_mode = 0; > > > > > > > > > > + rose_neigh_putex(&neigh); > > > > > rose_start_t0timer(neigh); > > > > > } > > > > > > > > > > -- > > > > > 2.43.0 > > > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-25 7:15 ` Kuniyuki Iwashima @ 2025-10-25 7:53 ` Lizhi Xu 2025-10-27 17:40 ` Kuniyuki Iwashima 0 siblings, 1 reply; 11+ messages in thread From: Lizhi Xu @ 2025-10-25 7:53 UTC (permalink / raw) To: kuniyu Cc: davem, edumazet, horms, jreuter, kuba, linux-hams, linux-kernel, lizhi.xu, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Sat, 25 Oct 2025 00:15:51 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > On Fri, Oct 24, 2025 at 11:46 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > On Fri, 24 Oct 2025 21:25:20 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > On Fri, Oct 24, 2025 at 8:51 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > On Fri, 24 Oct 2025 19:18:46 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > > > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > > > > > and rose_timer_expiry. > > > > > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > > > > > However, rose_t0timer_expiry() does initiate a restart request on the > > > > > > neighbor. > > > > > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > > > > > a UAF is triggered. > > > > > > > > > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > > > > > stop restarting t0timer after putting the neighbor. > > > > > > > > > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > > > > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > > > > > > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > > > > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > > > > > Call Trace: > > > > > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > > > > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > > > > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > > > > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > > > > > > > > > Freed by task 17183: > > > > > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > > > > > rose_neigh_put include/net/rose.h:165 [inline] > > > > > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > > > > > > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > > > > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > > > > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > > > > > --- > > > > > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > > > > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > > > > > > > > > include/net/rose.h | 12 ++++++++++++ > > > > > > net/rose/rose_link.c | 5 +++++ > > > > > > 2 files changed, 17 insertions(+) > > > > > > > > > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > > > > > index 2b5491bbf39a..33de310ba778 100644 > > > > > > --- a/include/net/rose.h > > > > > > +++ b/include/net/rose.h > > > > > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > > > > > } > > > > > > } > > > > > > > > > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > > > > > +{ > > > > > > + struct rose_neigh *rose_neigh = *roseneigh; > > > > > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > > > > > + if (rose_neigh->ax25) > > > > > > + ax25_cb_put(rose_neigh->ax25); > > > > > > + kfree(rose_neigh->digipeat); > > > > > > + kfree(rose_neigh); > > > > > > + *roseneigh = NULL; > > > > > > + } > > > > > > +} > > > > > > + > > > > > > /* af_rose.c */ > > > > > > extern ax25_address rose_callsign; > > > > > > extern int sysctl_rose_restart_request_timeout; > > > > > > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > > > > > > index 7746229fdc8c..334c8cc0876d 100644 > > > > > > --- a/net/rose/rose_link.c > > > > > > +++ b/net/rose/rose_link.c > > > > > > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > > > > > > > > > > > static void rose_start_t0timer(struct rose_neigh *neigh) > > > > > > { > > > > > > + if (!neigh) > > > > > > + return; > > > > > > + > > > > > > timer_delete(&neigh->t0timer); > > > > > > > > > > > > neigh->t0timer.function = rose_t0timer_expiry; > > > > > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > > > > > { > > > > > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > > > > > > > > > > > > > What prevents rose_timer_expiry() from releasing the > > > > > last refcnt here ? > > > > The issue reported by syzbot is that rose_t0timer_expiry() is triggered > > > > first, followed by rose_timer_expiry(). > > > > > > I don't see how you read that ordering from the report. > > > https://syzkaller.appspot.com/bug?extid=caa052a0958a9146870d > > Here's my understanding: See the two calltraces below. > > The same question still applies. > > What prevents rose_timer_expiry() from releasing the last > refcnt before [1] ? @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) { struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); + rose_neigh_hold(neigh); // [3] This prevents rose_timer_expiry() from putting neigh. rose_transmit_restart_request(neigh); neigh->dce_mode = 0; + rose_neigh_putex(&neigh); // [4] This prevents t0timer from restarting by setting neigh to NULL. rose_start_t0timer(neigh); } > > For example, why is accessing neigh->dev in rose_send_frame() > safe then ? > > The commit message mentions that two timers are not > synchronised, but the diff adds no such synchronisation. > > > > [1] Line 111 occurs after rose_neigh_put(). Otherwise, accessing > > neigh->digipeat would result in a UAF. Therefore, rose_t0timer_expiry() > > must be triggered before rose_timer_expiry(). > > > > [2] syzbot reports that line 237 generates a UAF when accessing digi->ndigi. > > > > UAF Task1: > > rose_t0timer_expiry()-> > > rose_transmit_restart_request()-> > > rose_send_frame(.., neigh->digipeat, ..)-> // [1] line 111 > > ax25_find_cb()-> > > if (digi != NULL && digi->ndigi != 0) // [2] line 237 > > > > Freed neigh Task2: > > rose_timer_expiry()-> > > rose_neigh_put(neigh)-> > > kfree(neigh) > > > > > > The only ordering I can find is that kfree() in rose_timer_expiry() > > > happened before ax25_find_cb () in rose_t0timer_expiry(). > > > > > > > Therefore, in rose_t0timer_expiry(), the reference count of neigh is > > > > increased before entering rose_transmit_restart_request() to prevent > > > > neigh from being put in rose_timer_expiry(). Then, in rose_t0timer_expiry(), > > > > neigh is put before executing rose_start_t0timer() and the neigh value is > > > > set to NULL to prevent t0timer restarts. > > > > > > > > The case where rose_timer_expiry() is triggered before rose_t0timer_expiry() > > > > is not considered at this time. > > > > > > So this change just papers over the root cause. > > > > > > > > > > > > > > > > The t0timer could be triggered even after that happens. > > > > > > > > > > > > > > > > + rose_neigh_hold(neigh); > > > > > > rose_transmit_restart_request(neigh); > > > > > > > > > > > > neigh->dce_mode = 0; > > > > > > > > > > > > + rose_neigh_putex(&neigh); > > > > > > rose_start_t0timer(neigh); > > > > > > } > > > > > > > > > > > > -- > > > > > > 2.43.0 > > > > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-25 7:53 ` Lizhi Xu @ 2025-10-27 17:40 ` Kuniyuki Iwashima 2025-10-28 2:05 ` Lizhi Xu 0 siblings, 1 reply; 11+ messages in thread From: Kuniyuki Iwashima @ 2025-10-27 17:40 UTC (permalink / raw) To: Lizhi Xu Cc: davem, edumazet, horms, jreuter, kuba, linux-hams, linux-kernel, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Sat, Oct 25, 2025 at 12:53 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > On Sat, 25 Oct 2025 00:15:51 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > On Fri, Oct 24, 2025 at 11:46 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > On Fri, 24 Oct 2025 21:25:20 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > > On Fri, Oct 24, 2025 at 8:51 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > > > On Fri, 24 Oct 2025 19:18:46 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > > > > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > > > > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > > > > > > and rose_timer_expiry. > > > > > > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > > > > > > However, rose_t0timer_expiry() does initiate a restart request on the > > > > > > > neighbor. > > > > > > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > > > > > > a UAF is triggered. > > > > > > > > > > > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > > > > > > stop restarting t0timer after putting the neighbor. > > > > > > > > > > > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > > > > > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > > > > > > > > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > > > > > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > > > > > > Call Trace: > > > > > > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > > > > > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > > > > > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > > > > > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > > > > > > > > > > > Freed by task 17183: > > > > > > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > > > > > > rose_neigh_put include/net/rose.h:165 [inline] > > > > > > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > > > > > > > > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > > > > > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > > > > > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > > > > > > --- > > > > > > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > > > > > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > > > > > > > > > > > include/net/rose.h | 12 ++++++++++++ > > > > > > > net/rose/rose_link.c | 5 +++++ > > > > > > > 2 files changed, 17 insertions(+) > > > > > > > > > > > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > > > > > > index 2b5491bbf39a..33de310ba778 100644 > > > > > > > --- a/include/net/rose.h > > > > > > > +++ b/include/net/rose.h > > > > > > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > > > > > > } > > > > > > > } > > > > > > > > > > > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > > > > > > +{ > > > > > > > + struct rose_neigh *rose_neigh = *roseneigh; > > > > > > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > > > > > > + if (rose_neigh->ax25) > > > > > > > + ax25_cb_put(rose_neigh->ax25); > > > > > > > + kfree(rose_neigh->digipeat); > > > > > > > + kfree(rose_neigh); > > > > > > > + *roseneigh = NULL; > > > > > > > + } > > > > > > > +} > > > > > > > + > > > > > > > /* af_rose.c */ > > > > > > > extern ax25_address rose_callsign; > > > > > > > extern int sysctl_rose_restart_request_timeout; > > > > > > > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > > > > > > > index 7746229fdc8c..334c8cc0876d 100644 > > > > > > > --- a/net/rose/rose_link.c > > > > > > > +++ b/net/rose/rose_link.c > > > > > > > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > > > > > > > > > > > > > static void rose_start_t0timer(struct rose_neigh *neigh) > > > > > > > { > > > > > > > + if (!neigh) > > > > > > > + return; > > > > > > > + > > > > > > > timer_delete(&neigh->t0timer); > > > > > > > > > > > > > > neigh->t0timer.function = rose_t0timer_expiry; > > > > > > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > > > > > > { > > > > > > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > > > > > > > > > > > > > > > > What prevents rose_timer_expiry() from releasing the > > > > > > last refcnt here ? > > > > > The issue reported by syzbot is that rose_t0timer_expiry() is triggered > > > > > first, followed by rose_timer_expiry(). > > > > > > > > I don't see how you read that ordering from the report. > > > > https://syzkaller.appspot.com/bug?extid=caa052a0958a9146870d > > > Here's my understanding: See the two calltraces below. > > > > The same question still applies. > > > > What prevents rose_timer_expiry() from releasing the last > > refcnt before [1] ? > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > { > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > + rose_neigh_hold(neigh); // [3] This prevents rose_timer_expiry() from putting neigh. If you ask yourself the same question once more here, you will notice the fix is broken. What prevents rose_timer_expiry() from releasing the last refcnt before rose_neigh_hold() ? Do you add another rose_neigh_hold() before rose_neigh_hold() ? ... and the same question applies as long as you are trying to fix the bug by adding changes in rose_t0timer_expiry(). > rose_transmit_restart_request(neigh); > > neigh->dce_mode = 0; > > + rose_neigh_putex(&neigh); // [4] This prevents t0timer from restarting by setting neigh to NULL. > rose_start_t0timer(neigh); > } > > > > For example, why is accessing neigh->dev in rose_send_frame() > > safe then ? > > > > The commit message mentions that two timers are not > > synchronised, but the diff adds no such synchronisation. > > > > > > > [1] Line 111 occurs after rose_neigh_put(). Otherwise, accessing > > > neigh->digipeat would result in a UAF. Therefore, rose_t0timer_expiry() > > > must be triggered before rose_timer_expiry(). > > > > > > [2] syzbot reports that line 237 generates a UAF when accessing digi->ndigi. > > > > > > UAF Task1: > > > rose_t0timer_expiry()-> > > > rose_transmit_restart_request()-> > > > rose_send_frame(.., neigh->digipeat, ..)-> // [1] line 111 > > > ax25_find_cb()-> > > > if (digi != NULL && digi->ndigi != 0) // [2] line 237 > > > > > > Freed neigh Task2: > > > rose_timer_expiry()-> > > > rose_neigh_put(neigh)-> > > > kfree(neigh) > > > > > > > > The only ordering I can find is that kfree() in rose_timer_expiry() > > > > happened before ax25_find_cb () in rose_t0timer_expiry(). > > > > > > > > > Therefore, in rose_t0timer_expiry(), the reference count of neigh is > > > > > increased before entering rose_transmit_restart_request() to prevent > > > > > neigh from being put in rose_timer_expiry(). Then, in rose_t0timer_expiry(), > > > > > neigh is put before executing rose_start_t0timer() and the neigh value is > > > > > set to NULL to prevent t0timer restarts. > > > > > > > > > > The case where rose_timer_expiry() is triggered before rose_t0timer_expiry() > > > > > is not considered at this time. > > > > > > > > So this change just papers over the root cause. > > > > > > > > > > > > > > > > > > > > The t0timer could be triggered even after that happens. > > > > > > > > > > > > > > > > > > > + rose_neigh_hold(neigh); > > > > > > > rose_transmit_restart_request(neigh); > > > > > > > > > > > > > > neigh->dce_mode = 0; > > > > > > > > > > > > > > + rose_neigh_putex(&neigh); > > > > > > > rose_start_t0timer(neigh); > > > > > > > } > > > > > > > > > > > > > > -- > > > > > > > 2.43.0 > > > > > > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH V3] net: rose: Prevent the use of freed digipeat 2025-10-27 17:40 ` Kuniyuki Iwashima @ 2025-10-28 2:05 ` Lizhi Xu 0 siblings, 0 replies; 11+ messages in thread From: Lizhi Xu @ 2025-10-28 2:05 UTC (permalink / raw) To: kuniyu Cc: davem, edumazet, horms, jreuter, kuba, linux-hams, linux-kernel, lizhi.xu, netdev, pabeni, syzbot+caa052a0958a9146870d, syzkaller-bugs On Mon, 27 Oct 2025 10:40:34 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > On Sat, Oct 25, 2025 at 12:53 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > On Sat, 25 Oct 2025 00:15:51 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > On Fri, Oct 24, 2025 at 11:46 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > On Fri, 24 Oct 2025 21:25:20 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > > > On Fri, Oct 24, 2025 at 8:51 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > > > > > On Fri, 24 Oct 2025 19:18:46 -0700, Kuniyuki Iwashima <kuniyu@google.com> wrote: > > > > > > > On Fri, Oct 24, 2025 at 2:39 AM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > > > > > > > > > > > > > > > There is no synchronization between the two timers, rose_t0timer_expiry > > > > > > > > and rose_timer_expiry. > > > > > > > > rose_timer_expiry() puts the neighbor when the rose state is ROSE_STATE_2. > > > > > > > > However, rose_t0timer_expiry() does initiate a restart request on the > > > > > > > > neighbor. > > > > > > > > When rose_t0timer_expiry() accesses the released neighbor member digipeat, > > > > > > > > a UAF is triggered. > > > > > > > > > > > > > > > > To avoid this UAF, defer the put operation to rose_t0timer_expiry() and > > > > > > > > stop restarting t0timer after putting the neighbor. > > > > > > > > > > > > > > > > When putting the neighbor, set the neighbor to NULL. Setting neighbor to > > > > > > > > NULL prevents rose_t0timer_expiry() from restarting t0timer. > > > > > > > > > > > > > > > > syzbot reported a slab-use-after-free Read in ax25_find_cb. > > > > > > > > BUG: KASAN: slab-use-after-free in ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > > > > Read of size 1 at addr ffff888059c704c0 by task syz.6.2733/17200 > > > > > > > > Call Trace: > > > > > > > > ax25_find_cb+0x3b8/0x3f0 net/ax25/af_ax25.c:237 > > > > > > > > ax25_send_frame+0x157/0xb60 net/ax25/ax25_out.c:55 > > > > > > > > rose_send_frame+0xcc/0x2c0 net/rose/rose_link.c:106 > > > > > > > > rose_transmit_restart_request+0x1b8/0x240 net/rose/rose_link.c:198 > > > > > > > > rose_t0timer_expiry+0x1d/0x150 net/rose/rose_link.c:83 > > > > > > > > > > > > > > > > Freed by task 17183: > > > > > > > > kfree+0x2b8/0x6d0 mm/slub.c:6826 > > > > > > > > rose_neigh_put include/net/rose.h:165 [inline] > > > > > > > > rose_timer_expiry+0x537/0x630 net/rose/rose_timer.c:183 > > > > > > > > > > > > > > > > Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") > > > > > > > > Reported-by: syzbot+caa052a0958a9146870d@syzkaller.appspotmail.com > > > > > > > > Signed-off-by: Lizhi Xu <lizhi.xu@windriver.com> > > > > > > > > --- > > > > > > > > V1 -> V2: Putting the neighbor stops t0timer from automatically starting > > > > > > > > V2 -> V3: add rose_neigh_putex for set rose neigh to NULL > > > > > > > > > > > > > > > > include/net/rose.h | 12 ++++++++++++ > > > > > > > > net/rose/rose_link.c | 5 +++++ > > > > > > > > 2 files changed, 17 insertions(+) > > > > > > > > > > > > > > > > diff --git a/include/net/rose.h b/include/net/rose.h > > > > > > > > index 2b5491bbf39a..33de310ba778 100644 > > > > > > > > --- a/include/net/rose.h > > > > > > > > +++ b/include/net/rose.h > > > > > > > > @@ -167,6 +167,18 @@ static inline void rose_neigh_put(struct rose_neigh *rose_neigh) > > > > > > > > } > > > > > > > > } > > > > > > > > > > > > > > > > +static inline void rose_neigh_putex(struct rose_neigh **roseneigh) > > > > > > > > +{ > > > > > > > > + struct rose_neigh *rose_neigh = *roseneigh; > > > > > > > > + if (refcount_dec_and_test(&rose_neigh->use)) { > > > > > > > > + if (rose_neigh->ax25) > > > > > > > > + ax25_cb_put(rose_neigh->ax25); > > > > > > > > + kfree(rose_neigh->digipeat); > > > > > > > > + kfree(rose_neigh); > > > > > > > > + *roseneigh = NULL; > > > > > > > > + } > > > > > > > > +} > > > > > > > > + > > > > > > > > /* af_rose.c */ > > > > > > > > extern ax25_address rose_callsign; > > > > > > > > extern int sysctl_rose_restart_request_timeout; > > > > > > > > diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c > > > > > > > > index 7746229fdc8c..334c8cc0876d 100644 > > > > > > > > --- a/net/rose/rose_link.c > > > > > > > > +++ b/net/rose/rose_link.c > > > > > > > > @@ -43,6 +43,9 @@ void rose_start_ftimer(struct rose_neigh *neigh) > > > > > > > > > > > > > > > > static void rose_start_t0timer(struct rose_neigh *neigh) > > > > > > > > { > > > > > > > > + if (!neigh) > > > > > > > > + return; > > > > > > > > + > > > > > > > > timer_delete(&neigh->t0timer); > > > > > > > > > > > > > > > > neigh->t0timer.function = rose_t0timer_expiry; > > > > > > > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > > > > > > > { > > > > > > > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > > > > > > > > > > > > > > > > > > > What prevents rose_timer_expiry() from releasing the > > > > > > > last refcnt here ? > > > > > > The issue reported by syzbot is that rose_t0timer_expiry() is triggered > > > > > > first, followed by rose_timer_expiry(). > > > > > > > > > > I don't see how you read that ordering from the report. > > > > > https://syzkaller.appspot.com/bug?extid=caa052a0958a9146870d > > > > Here's my understanding: See the two calltraces below. > > > > > > The same question still applies. > > > > > > What prevents rose_timer_expiry() from releasing the last > > > refcnt before [1] ? > > @@ -80,10 +83,12 @@ static void rose_t0timer_expiry(struct timer_list *t) > > { > > struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer); > > > > + rose_neigh_hold(neigh); // [3] This prevents rose_timer_expiry() from putting neigh. > > If you ask yourself the same question once more here, > you will notice the fix is broken. > > What prevents rose_timer_expiry() from releasing the > last refcnt before rose_neigh_hold() ? The UAF issue reported by syzbot is shown below: CPU0 CPU1 ==== ==== rose_t0timer_expiry() rose_transmit_restart_request() rose_send_frame() ax25_send_frame() rose_timer_expiry() rose_neigh_put() kfree(neigh) ax25_find_cb() My patch calls rose_neigh_hold() before executing rose_transmit_restart_request() in rose_t0timer_expiry(). It then calls rose_neigh_putex() to release and set neigh to NULL before executing rose_start_t0timer(). This also prevents timer0 from restarting. I think the only questionable part of the patch is the expiration time of rose_timer. I don't know the expiration time because I don't have a reproducer. If the value is very small, the result may be different. ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-10-28 2:06 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-10-24 9:39 [PATCH V3] net: rose: Prevent the use of freed digipeat Lizhi Xu 2025-10-24 11:49 ` Eric Dumazet 2025-10-25 1:48 ` Lizhi Xu 2025-10-25 2:18 ` Kuniyuki Iwashima 2025-10-25 3:51 ` Lizhi Xu 2025-10-25 4:25 ` Kuniyuki Iwashima 2025-10-25 6:46 ` Lizhi Xu 2025-10-25 7:15 ` Kuniyuki Iwashima 2025-10-25 7:53 ` Lizhi Xu 2025-10-27 17:40 ` Kuniyuki Iwashima 2025-10-28 2:05 ` Lizhi Xu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox