Skip to content

Commit ceb9515

Browse files
committed
Merge branch 'introduce-refcount_t-for-reference-counting-of-rose_neigh'
Takamitsu Iwai says: ==================== Introduce refcount_t for reference counting of rose_neigh The current implementation of rose_neigh uses 'use' and 'count' field of type unsigned short as a reference count. This approach lacks atomicity, leading to potential race conditions. As a result, syzbot has reported slab-use-after-free errors due to unintended removals. This series introduces refcount_t for reference counting to ensure atomicity and prevent race conditions. The patches are structured as follows: 1. Refactor rose_remove_neigh() to separate removal and freeing operations 2. Convert 'use' field to refcount_t for appropriate reference counting 3. Include references from rose_node to 'use' field These changes should resolve the reported slab-use-after-free issues and improve the overall stability of the ROSE network layer. v1: https://lore.kernel.org/20250820174707.83372-1-takamitz@amazon.co.jp ==================== Link: https://patch.msgid.link/20250823085857.47674-1-takamitz@amazon.co.jp Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 9448ccd + da9c9c8 commit ceb9515

File tree

5 files changed

+69
-38
lines changed

5 files changed

+69
-38
lines changed

include/net/rose.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#ifndef _ROSE_H
99
#define _ROSE_H
1010

11+
#include <linux/refcount.h>
1112
#include <linux/rose.h>
1213
#include <net/ax25.h>
1314
#include <net/sock.h>
@@ -96,7 +97,7 @@ struct rose_neigh {
9697
ax25_cb *ax25;
9798
struct net_device *dev;
9899
unsigned short count;
99-
unsigned short use;
100+
refcount_t use;
100101
unsigned int number;
101102
char restarted;
102103
char dce_mode;
@@ -151,6 +152,21 @@ struct rose_sock {
151152

152153
#define rose_sk(sk) ((struct rose_sock *)(sk))
153154

155+
static inline void rose_neigh_hold(struct rose_neigh *rose_neigh)
156+
{
157+
refcount_inc(&rose_neigh->use);
158+
}
159+
160+
static inline void rose_neigh_put(struct rose_neigh *rose_neigh)
161+
{
162+
if (refcount_dec_and_test(&rose_neigh->use)) {
163+
if (rose_neigh->ax25)
164+
ax25_cb_put(rose_neigh->ax25);
165+
kfree(rose_neigh->digipeat);
166+
kfree(rose_neigh);
167+
}
168+
}
169+
154170
/* af_rose.c */
155171
extern ax25_address rose_callsign;
156172
extern int sysctl_rose_restart_request_timeout;

net/rose/af_rose.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
170170

171171
if (rose->neighbour == neigh) {
172172
rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
173-
rose->neighbour->use--;
173+
rose_neigh_put(rose->neighbour);
174174
rose->neighbour = NULL;
175175
}
176176
}
@@ -212,7 +212,7 @@ static void rose_kill_by_device(struct net_device *dev)
212212
if (rose->device == dev) {
213213
rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
214214
if (rose->neighbour)
215-
rose->neighbour->use--;
215+
rose_neigh_put(rose->neighbour);
216216
netdev_put(rose->device, &rose->dev_tracker);
217217
rose->device = NULL;
218218
}
@@ -655,7 +655,7 @@ static int rose_release(struct socket *sock)
655655
break;
656656

657657
case ROSE_STATE_2:
658-
rose->neighbour->use--;
658+
rose_neigh_put(rose->neighbour);
659659
release_sock(sk);
660660
rose_disconnect(sk, 0, -1, -1);
661661
lock_sock(sk);
@@ -823,6 +823,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
823823
rose->lci = rose_new_lci(rose->neighbour);
824824
if (!rose->lci) {
825825
err = -ENETUNREACH;
826+
rose_neigh_put(rose->neighbour);
826827
goto out_release;
827828
}
828829

@@ -834,12 +835,14 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
834835
dev = rose_dev_first();
835836
if (!dev) {
836837
err = -ENETUNREACH;
838+
rose_neigh_put(rose->neighbour);
837839
goto out_release;
838840
}
839841

840842
user = ax25_findbyuid(current_euid());
841843
if (!user) {
842844
err = -EINVAL;
845+
rose_neigh_put(rose->neighbour);
843846
dev_put(dev);
844847
goto out_release;
845848
}
@@ -874,8 +877,6 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
874877

875878
rose->state = ROSE_STATE_1;
876879

877-
rose->neighbour->use++;
878-
879880
rose_write_internal(sk, ROSE_CALL_REQUEST);
880881
rose_start_heartbeat(sk);
881882
rose_start_t1timer(sk);
@@ -1077,7 +1078,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
10771078
GFP_ATOMIC);
10781079
make_rose->facilities = facilities;
10791080

1080-
make_rose->neighbour->use++;
1081+
rose_neigh_hold(make_rose->neighbour);
10811082

10821083
if (rose_sk(sk)->defer) {
10831084
make_rose->state = ROSE_STATE_5;

net/rose/rose_in.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
5656
case ROSE_CLEAR_REQUEST:
5757
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
5858
rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
59-
rose->neighbour->use--;
59+
rose_neigh_put(rose->neighbour);
6060
break;
6161

6262
default:
@@ -79,12 +79,12 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
7979
case ROSE_CLEAR_REQUEST:
8080
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
8181
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
82-
rose->neighbour->use--;
82+
rose_neigh_put(rose->neighbour);
8383
break;
8484

8585
case ROSE_CLEAR_CONFIRMATION:
8686
rose_disconnect(sk, 0, -1, -1);
87-
rose->neighbour->use--;
87+
rose_neigh_put(rose->neighbour);
8888
break;
8989

9090
default:
@@ -121,7 +121,7 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
121121
case ROSE_CLEAR_REQUEST:
122122
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
123123
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
124-
rose->neighbour->use--;
124+
rose_neigh_put(rose->neighbour);
125125
break;
126126

127127
case ROSE_RR:
@@ -234,7 +234,7 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
234234
case ROSE_CLEAR_REQUEST:
235235
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
236236
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
237-
rose->neighbour->use--;
237+
rose_neigh_put(rose->neighbour);
238238
break;
239239

240240
default:
@@ -254,7 +254,7 @@ static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int framety
254254
if (frametype == ROSE_CLEAR_REQUEST) {
255255
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
256256
rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
257-
rose_sk(sk)->neighbour->use--;
257+
rose_neigh_put(rose_sk(sk)->neighbour);
258258
}
259259

260260
return 0;

0 commit comments

Comments
 (0)