mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
net: rose: include node references in rose_neigh refcount
Current implementation maintains two separate reference counting
mechanisms: the 'count' field in struct rose_neigh tracks references from
rose_node structures, while the 'use' field (now refcount_t) tracks
references from rose_sock.
This patch merges these two reference counting systems using 'use' field
for proper reference management. Specifically, this patch adds incrementing
and decrementing of rose_neigh->use when rose_neigh->count is incremented
or decremented.
This patch also modifies rose_rt_free(), rose_rt_device_down() and
rose_clear_route() to properly release references to rose_neigh objects
before freeing a rose_node through rose_remove_node().
These changes ensure rose_neigh structures are properly freed only when
all references, including those from rose_node structures, are released.
As a result, this resolves a slab-use-after-free issue reported by Syzbot.
Fixes: 1da177e4c3
("Linux-2.6.12-rc2")
Reported-by: syzbot+942297eecf7d2d61d1f1@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=942297eecf7d2d61d1f1
Signed-off-by: Takamitsu Iwai <takamitz@amazon.co.jp>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250823085857.47674-4-takamitz@amazon.co.jp
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d860d1faa6
commit
da9c9c8775
@ -178,6 +178,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rose_neigh->count++;
|
rose_neigh->count++;
|
||||||
|
rose_neigh_hold(rose_neigh);
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -187,6 +188,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
|
|||||||
rose_node->neighbour[rose_node->count] = rose_neigh;
|
rose_node->neighbour[rose_node->count] = rose_neigh;
|
||||||
rose_node->count++;
|
rose_node->count++;
|
||||||
rose_neigh->count++;
|
rose_neigh->count++;
|
||||||
|
rose_neigh_hold(rose_neigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -322,6 +324,7 @@ static int rose_del_node(struct rose_route_struct *rose_route,
|
|||||||
for (i = 0; i < rose_node->count; i++) {
|
for (i = 0; i < rose_node->count; i++) {
|
||||||
if (rose_node->neighbour[i] == rose_neigh) {
|
if (rose_node->neighbour[i] == rose_neigh) {
|
||||||
rose_neigh->count--;
|
rose_neigh->count--;
|
||||||
|
rose_neigh_put(rose_neigh);
|
||||||
|
|
||||||
if (rose_neigh->count == 0) {
|
if (rose_neigh->count == 0) {
|
||||||
rose_remove_neigh(rose_neigh);
|
rose_remove_neigh(rose_neigh);
|
||||||
@ -430,6 +433,7 @@ int rose_add_loopback_node(const rose_address *address)
|
|||||||
rose_node_list = rose_node;
|
rose_node_list = rose_node;
|
||||||
|
|
||||||
rose_loopback_neigh->count++;
|
rose_loopback_neigh->count++;
|
||||||
|
rose_neigh_hold(rose_loopback_neigh);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock_bh(&rose_node_list_lock);
|
spin_unlock_bh(&rose_node_list_lock);
|
||||||
@ -461,6 +465,7 @@ void rose_del_loopback_node(const rose_address *address)
|
|||||||
rose_remove_node(rose_node);
|
rose_remove_node(rose_node);
|
||||||
|
|
||||||
rose_loopback_neigh->count--;
|
rose_loopback_neigh->count--;
|
||||||
|
rose_neigh_put(rose_loopback_neigh);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock_bh(&rose_node_list_lock);
|
spin_unlock_bh(&rose_node_list_lock);
|
||||||
@ -500,6 +505,7 @@ void rose_rt_device_down(struct net_device *dev)
|
|||||||
memmove(&t->neighbour[i], &t->neighbour[i + 1],
|
memmove(&t->neighbour[i], &t->neighbour[i + 1],
|
||||||
sizeof(t->neighbour[0]) *
|
sizeof(t->neighbour[0]) *
|
||||||
(t->count - i));
|
(t->count - i));
|
||||||
|
rose_neigh_put(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->count <= 0)
|
if (t->count <= 0)
|
||||||
@ -543,6 +549,7 @@ static int rose_clear_routes(void)
|
|||||||
{
|
{
|
||||||
struct rose_neigh *s, *rose_neigh;
|
struct rose_neigh *s, *rose_neigh;
|
||||||
struct rose_node *t, *rose_node;
|
struct rose_node *t, *rose_node;
|
||||||
|
int i;
|
||||||
|
|
||||||
spin_lock_bh(&rose_node_list_lock);
|
spin_lock_bh(&rose_node_list_lock);
|
||||||
spin_lock_bh(&rose_neigh_list_lock);
|
spin_lock_bh(&rose_neigh_list_lock);
|
||||||
@ -553,9 +560,13 @@ static int rose_clear_routes(void)
|
|||||||
while (rose_node != NULL) {
|
while (rose_node != NULL) {
|
||||||
t = rose_node;
|
t = rose_node;
|
||||||
rose_node = rose_node->next;
|
rose_node = rose_node->next;
|
||||||
if (!t->loopback)
|
|
||||||
|
if (!t->loopback) {
|
||||||
|
for (i = 0; i < rose_node->count; i++)
|
||||||
|
rose_neigh_put(t->neighbour[i]);
|
||||||
rose_remove_node(t);
|
rose_remove_node(t);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (rose_neigh != NULL) {
|
while (rose_neigh != NULL) {
|
||||||
s = rose_neigh;
|
s = rose_neigh;
|
||||||
@ -1189,7 +1200,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
|
|||||||
(rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign),
|
(rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign),
|
||||||
rose_neigh->dev ? rose_neigh->dev->name : "???",
|
rose_neigh->dev ? rose_neigh->dev->name : "???",
|
||||||
rose_neigh->count,
|
rose_neigh->count,
|
||||||
refcount_read(&rose_neigh->use) - 1,
|
refcount_read(&rose_neigh->use) - rose_neigh->count - 1,
|
||||||
(rose_neigh->dce_mode) ? "DCE" : "DTE",
|
(rose_neigh->dce_mode) ? "DCE" : "DTE",
|
||||||
(rose_neigh->restarted) ? "yes" : "no",
|
(rose_neigh->restarted) ? "yes" : "no",
|
||||||
ax25_display_timer(&rose_neigh->t0timer) / HZ,
|
ax25_display_timer(&rose_neigh->t0timer) / HZ,
|
||||||
@ -1294,6 +1305,7 @@ void __exit rose_rt_free(void)
|
|||||||
struct rose_neigh *s, *rose_neigh = rose_neigh_list;
|
struct rose_neigh *s, *rose_neigh = rose_neigh_list;
|
||||||
struct rose_node *t, *rose_node = rose_node_list;
|
struct rose_node *t, *rose_node = rose_node_list;
|
||||||
struct rose_route *u, *rose_route = rose_route_list;
|
struct rose_route *u, *rose_route = rose_route_list;
|
||||||
|
int i;
|
||||||
|
|
||||||
while (rose_neigh != NULL) {
|
while (rose_neigh != NULL) {
|
||||||
s = rose_neigh;
|
s = rose_neigh;
|
||||||
@ -1307,6 +1319,8 @@ void __exit rose_rt_free(void)
|
|||||||
t = rose_node;
|
t = rose_node;
|
||||||
rose_node = rose_node->next;
|
rose_node = rose_node->next;
|
||||||
|
|
||||||
|
for (i = 0; i < t->count; i++)
|
||||||
|
rose_neigh_put(t->neighbour[i]);
|
||||||
rose_remove_node(t);
|
rose_remove_node(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user