Skip to content

Commit 87563a0

Browse files
stonezdmkuba-moo
authored andcommitted
ax25: fix reference count leaks of ax25_dev
The previous commit d01ffb9 ("ax25: add refcount in ax25_dev to avoid UAF bugs") introduces refcount into ax25_dev, but there are reference leak paths in ax25_ctl_ioctl(), ax25_fwd_ioctl(), ax25_rt_add(), ax25_rt_del() and ax25_rt_opt(). This patch uses ax25_dev_put() and adjusts the position of ax25_addr_ax25dev() to fix reference cout leaks of ax25_dev. Fixes: d01ffb9 ("ax25: add refcount in ax25_dev to avoid UAF bugs") Signed-off-by: Duoming Zhou <[email protected]> Reviewed-by: Dan Carpenter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 80d4609 commit 87563a0

File tree

4 files changed

+41
-19
lines changed

4 files changed

+41
-19
lines changed

include/net/ax25.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,12 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25)
294294
}
295295
}
296296

297-
#define ax25_dev_hold(__ax25_dev) \
298-
refcount_inc(&((__ax25_dev)->refcount))
297+
static inline void ax25_dev_hold(ax25_dev *ax25_dev)
298+
{
299+
refcount_inc(&ax25_dev->refcount);
300+
}
299301

300-
static __inline__ void ax25_dev_put(ax25_dev *ax25_dev)
302+
static inline void ax25_dev_put(ax25_dev *ax25_dev)
301303
{
302304
if (refcount_dec_and_test(&ax25_dev->refcount)) {
303305
kfree(ax25_dev);

net/ax25/af_ax25.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,21 +359,25 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
359359
if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
360360
return -EFAULT;
361361

362-
if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
363-
return -ENODEV;
364-
365362
if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
366363
return -EINVAL;
367364

368365
if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
369366
return -EINVAL;
370367

368+
ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
369+
if (!ax25_dev)
370+
return -ENODEV;
371+
371372
digi.ndigi = ax25_ctl.digi_count;
372373
for (k = 0; k < digi.ndigi; k++)
373374
digi.calls[k] = ax25_ctl.digi_addr[k];
374375

375-
if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL)
376+
ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
377+
if (!ax25) {
378+
ax25_dev_put(ax25_dev);
376379
return -ENOTCONN;
380+
}
377381

378382
switch (ax25_ctl.cmd) {
379383
case AX25_KILL:

net/ax25/ax25_dev.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ void ax25_dev_device_up(struct net_device *dev)
8585
spin_lock_bh(&ax25_dev_lock);
8686
ax25_dev->next = ax25_dev_list;
8787
ax25_dev_list = ax25_dev;
88-
ax25_dev_hold(ax25_dev);
8988
spin_unlock_bh(&ax25_dev_lock);
89+
ax25_dev_hold(ax25_dev);
9090

9191
ax25_register_dev_sysctl(ax25_dev);
9292
}
@@ -115,8 +115,8 @@ void ax25_dev_device_down(struct net_device *dev)
115115

116116
if ((s = ax25_dev_list) == ax25_dev) {
117117
ax25_dev_list = s->next;
118-
ax25_dev_put(ax25_dev);
119118
spin_unlock_bh(&ax25_dev_lock);
119+
ax25_dev_put(ax25_dev);
120120
dev->ax25_ptr = NULL;
121121
dev_put_track(dev, &ax25_dev->dev_tracker);
122122
ax25_dev_put(ax25_dev);
@@ -126,8 +126,8 @@ void ax25_dev_device_down(struct net_device *dev)
126126
while (s != NULL && s->next != NULL) {
127127
if (s->next == ax25_dev) {
128128
s->next = ax25_dev->next;
129-
ax25_dev_put(ax25_dev);
130129
spin_unlock_bh(&ax25_dev_lock);
130+
ax25_dev_put(ax25_dev);
131131
dev->ax25_ptr = NULL;
132132
dev_put_track(dev, &ax25_dev->dev_tracker);
133133
ax25_dev_put(ax25_dev);
@@ -150,25 +150,35 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
150150

151151
switch (cmd) {
152152
case SIOCAX25ADDFWD:
153-
if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
153+
fwd_dev = ax25_addr_ax25dev(&fwd->port_to);
154+
if (!fwd_dev) {
155+
ax25_dev_put(ax25_dev);
154156
return -EINVAL;
155-
if (ax25_dev->forward != NULL)
157+
}
158+
if (ax25_dev->forward) {
159+
ax25_dev_put(fwd_dev);
160+
ax25_dev_put(ax25_dev);
156161
return -EINVAL;
162+
}
157163
ax25_dev->forward = fwd_dev->dev;
158164
ax25_dev_put(fwd_dev);
165+
ax25_dev_put(ax25_dev);
159166
break;
160167

161168
case SIOCAX25DELFWD:
162-
if (ax25_dev->forward == NULL)
169+
if (!ax25_dev->forward) {
170+
ax25_dev_put(ax25_dev);
163171
return -EINVAL;
172+
}
164173
ax25_dev->forward = NULL;
174+
ax25_dev_put(ax25_dev);
165175
break;
166176

167177
default:
178+
ax25_dev_put(ax25_dev);
168179
return -EINVAL;
169180
}
170181

171-
ax25_dev_put(ax25_dev);
172182
return 0;
173183
}
174184

net/ax25/ax25_route.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
7575
ax25_dev *ax25_dev;
7676
int i;
7777

78-
if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
79-
return -EINVAL;
8078
if (route->digi_count > AX25_MAX_DIGIS)
8179
return -EINVAL;
8280

81+
ax25_dev = ax25_addr_ax25dev(&route->port_addr);
82+
if (!ax25_dev)
83+
return -EINVAL;
84+
8385
write_lock_bh(&ax25_route_lock);
8486

8587
ax25_rt = ax25_route_list;
@@ -91,6 +93,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
9193
if (route->digi_count != 0) {
9294
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
9395
write_unlock_bh(&ax25_route_lock);
96+
ax25_dev_put(ax25_dev);
9497
return -ENOMEM;
9598
}
9699
ax25_rt->digipeat->lastrepeat = -1;
@@ -101,13 +104,15 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
101104
}
102105
}
103106
write_unlock_bh(&ax25_route_lock);
107+
ax25_dev_put(ax25_dev);
104108
return 0;
105109
}
106110
ax25_rt = ax25_rt->next;
107111
}
108112

109113
if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
110114
write_unlock_bh(&ax25_route_lock);
115+
ax25_dev_put(ax25_dev);
111116
return -ENOMEM;
112117
}
113118

@@ -116,11 +121,11 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
116121
ax25_rt->dev = ax25_dev->dev;
117122
ax25_rt->digipeat = NULL;
118123
ax25_rt->ip_mode = ' ';
119-
ax25_dev_put(ax25_dev);
120124
if (route->digi_count != 0) {
121125
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
122126
write_unlock_bh(&ax25_route_lock);
123127
kfree(ax25_rt);
128+
ax25_dev_put(ax25_dev);
124129
return -ENOMEM;
125130
}
126131
ax25_rt->digipeat->lastrepeat = -1;
@@ -133,6 +138,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
133138
ax25_rt->next = ax25_route_list;
134139
ax25_route_list = ax25_rt;
135140
write_unlock_bh(&ax25_route_lock);
141+
ax25_dev_put(ax25_dev);
136142

137143
return 0;
138144
}
@@ -173,8 +179,8 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
173179
}
174180
}
175181
}
176-
ax25_dev_put(ax25_dev);
177182
write_unlock_bh(&ax25_route_lock);
183+
ax25_dev_put(ax25_dev);
178184

179185
return 0;
180186
}
@@ -216,8 +222,8 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
216222
}
217223

218224
out:
219-
ax25_dev_put(ax25_dev);
220225
write_unlock_bh(&ax25_route_lock);
226+
ax25_dev_put(ax25_dev);
221227
return err;
222228
}
223229

0 commit comments

Comments
 (0)