Fix potential memory leak in tipc_named_node_up()
Subsystems (2)
PATCH 1/1 Fix potential memory leak in tipc_named_node_up()
There seems to be a memory leak in net/tipc/name_distr.c::tipc_named_node_up()
The function, with comments, is this :
void tipc_named_node_up(unsigned long node)
{
struct publication *publ;
struct distr_item *item = NULL;
struct sk_buff *buf = NULL;
u32 left = 0;
u32 rest;
u32 max_item_buf;
read_lock_bh(&tipc_nametbl_lock);
max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
max_item_buf *= ITEM_SIZE;
rest = publ_cnt * ITEM_SIZE;
list_for_each_entry(publ, &publ_root, local_list) {
-----> If we stop processing here after doing 1, 2 & 3 below we end up at (4) (below).
if (!buf) {
left = (rest <= max_item_buf) ? rest : max_item_buf;
rest -= left;
buf = named_prepare_buf(PUBLICATION, left, node);-----> (1) here we allocate memory and store a pointer to it in 'buf'.
if (!buf) {
-----> (2) This test needs to fail, meaning we did allocate some memory.
warn("Bulk publication distribution failure\n");
goto exit;
}
item = (struct distr_item *)msg_data(buf_msg(buf));
}
publ_to_item(item, publ);
item++;
left -= ITEM_SIZE;
if (!left) {
-----> (3) If this test fails we loop and do nothing to 'buf'.
msg_set_link_selector(buf_msg(buf), node);
dbg("tipc_named_node_up: sending publish msg to "
"<%u.%u.%u>\n", tipc_zone(node),
tipc_cluster(node), tipc_node(node));
tipc_link_send(buf, node, node);
buf = NULL;
}
}
exit:
read_unlock_bh(&tipc_nametbl_lock);-----> (4) here we return without freeing 'buf' - memory leak. }
Luckily this is easy to fix, since we can only leave the function with 'buf' either set to NULL or (in the leak case) set to a valid address, and since kfree() handles being passed NULL gracefully we can simply kfree(buf) just before we leave the function.
The patch below frees 'buf' before leaving the function, thus avoiding the potential leak.
Fix a potential memory leak in tipc_named_node_up()
---
net/tipc/name_distr.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
net/tipc/name_distr.c +1 -0
@@ -204,6 +204,7 @@ void tipc_named_node_up(unsigned long node) } exit:read_unlock_bh (&tipc_nametbl_lock); +kfree (buf); }/**
Quoted 48 lines · Jesper Juhl
There seems to be a memory leak in net/tipc/name_distr.c::tipc_named_node_up()
The function, with comments, is this :
void
tipc_named_node_up(unsigned long node){ struct publication *publ; struct distr_item *item = NULL; struct sk_buff *buf = NULL; u32 left = 0; u32 rest; u32 max_item_buf; read_lock_bh(&tipc_nametbl_lock); max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE; max_item_buf *= ITEM_SIZE; rest = publ_cnt * ITEM_SIZE; list_for_each_entry(publ, &publ_root, local_list) { -----> If we stop processing here after doing 1, 2 & 3 below we end up at (4) (below). if (!buf) { left = (rest <= max_item_buf) ? rest : max_item_buf; rest -= left; buf = named_prepare_buf(PUBLICATION, left, node);-----> (1) here we allocate memory and store a pointer to it in 'buf'.
if (!buf) { -----> (2) This test needs to fail, meaning we did allocate some memory. warn("Bulk publication distribution failure\n"); goto exit; } item = (struct distr_item *)msg_data(buf_msg(buf)); } publ_to_item(item, publ); item++; left -= ITEM_SIZE; if (!left) { -----> (3) If this test fails we loop and do nothing to 'buf'. msg_set_link_selector(buf_msg(buf), node); dbg("tipc_named_node_up: sending publish msg to " "<%u.%u.%u>\n", tipc_zone(node), tipc_cluster(node), tipc_node(node)); tipc_link_send(buf, node, node); buf = NULL; } } exit: read_unlock_bh(&tipc_nametbl_lock);
Quoted 7 lines
-----> (4) here we return without freeing 'buf' - memory leak. }
Luckily this is easy to fix, since we can only leave the function with 'buf' either set to NULL or (in the leak case) set to a valid address, and since
kfree()handles being passed NULL gracefully we can simply kfree(buf) just before we leave the function.
Actually, I don't think that there's a leak.
publ_cnt: Number of items in the list
rest = publ_cnt * ITEM_SIZEmax_item_buf = n * ITEM_SIZE (Buffer can hold n elements at most)
1)
If publ_cnt <= n, "rest" becomes 0 and "left" becomes publ_cnt * ITEM_SIZE, so for the last iteration "left" becomes 0 and "buf" is freed.
2)
And if publ_cnt > n, "left" becomes 0 in the nth iteration. As "rest" already got decrement by n * ITEM_SIZE, you now got:
rest = (publ_cnt - n) * ITEM_SIZE
Then after 2*n iterations:
rest = (publ_cnt - 2*n) * ITEM_SIZE
and so on, until publ_cnt - m*n < n
At that point, "left" becomes (publ_cnt - m*n) * ITEM_SIZE, and there are also (publ_cnt - m*n) iterations left, so "left" again becomes 0 in the last iteration and "buf" is freed.
Besides that, is it valid to call kfree() on a buffer allocated by alloc_skb()?
Thanks,
Björn
Quoted 76 lines · Björn Steinbrink
Quoted 48 lines · Jesper Juhl
There seems to be a memory leak in net/tipc/name_distr.c::tipc_named_node_up()
The function, with comments, is this :
void
tipc_named_node_up(unsigned long node){ struct publication *publ; struct distr_item *item = NULL; struct sk_buff *buf = NULL; u32 left = 0; u32 rest; u32 max_item_buf; read_lock_bh(&tipc_nametbl_lock); max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE; max_item_buf *= ITEM_SIZE; rest = publ_cnt * ITEM_SIZE; list_for_each_entry(publ, &publ_root, local_list) { -----> If we stop processing here after doing 1, 2 & 3 below we end up at (4) (below). if (!buf) { left = (rest <= max_item_buf) ? rest : max_item_buf; rest -= left; buf = named_prepare_buf(PUBLICATION, left, node);-----> (1) here we allocate memory and store a pointer to it in 'buf'.
if (!buf) { -----> (2) This test needs to fail, meaning we did allocate some memory. warn("Bulk publication distribution failure\n"); goto exit; } item = (struct distr_item *)msg_data(buf_msg(buf)); } publ_to_item(item, publ); item++; left -= ITEM_SIZE; if (!left) { -----> (3) If this test fails we loop and do nothing to 'buf'. msg_set_link_selector(buf_msg(buf), node); dbg("tipc_named_node_up: sending publish msg to " "<%u.%u.%u>\n", tipc_zone(node), tipc_cluster(node), tipc_node(node)); tipc_link_send(buf, node, node); buf = NULL; } } exit: read_unlock_bh(&tipc_nametbl_lock);Quoted 7 lines
-----> (4) here we return without freeing 'buf' - memory leak. }
Luckily this is easy to fix, since we can only leave the function with 'buf' either set to NULL or (in the leak case) set to a valid address, and since
kfree()handles being passed NULL gracefully we can simply kfree(buf) just before we leave the function.Actually, I don't think that there's a leak.
publ_cnt: Number of items in the listrest =
publ_cnt*ITEM_SIZEmax_item_buf= n *ITEM_SIZE(Buffer can hold n elements at most)1)
Ifpubl_cnt<= n, "rest" becomes 0 and "left" becomespubl_cnt*ITEM_SIZE, so for the last iteration "left" becomes 0 and "buf" is freed.2)
And ifpubl_cnt> n, "left" becomes 0 in the nth iteration. As "rest" already got decrement by n *ITEM_SIZE, you now got:
rest = (publ_cnt- n) *ITEM_SIZE
Then after 2*n iterations:
rest = (publ_cnt- 2*n) *ITEM_SIZE
and so on, untilpubl_cnt- m*n < n
Quoted 4 lines
At that point, "left" becomes (
publ_cnt- m*n) *ITEM_SIZE, and there are also (publ_cnt- m*n) iterations left, so "left" again becomes 0 in the last iteration and "buf" is freed.
Ok, creating patches late in the evening after several cups of coffee is clearly a bad idea. I think you are right and there is really no leak. Thanks.
Quoted 4 lines
Besides that, is it valid to call
kfree()on a buffer allocated byalloc_skb()?
Arrgh, no of course not, seems I messed this one up real good :(
Signature · 3 lines
Jesper Juhl <[email protected]> Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html Plain text mails only, please http://www.expita.com/nomime.html