26c4caea "don't allow duplicate entries in listener mode" fix
cover 26c4caea "don't allow duplicate entries in listener mode" fix
Hello.
I noticed 26c4caea by accident. Afaics it deserves a couple of minor fixes/cleanups.
COMPILE TESTED ONLY. Needs review and acks ;)
Can't we kill listener->valid? It seems we can set ->pid = 0 to mark it invalid.
Oleg.
PATCH 1/2 taskstats: add_del_listener() shouldn't use the wrong node
1. 26c4caea "don't allow duplicate entries in listener mode" changed add_del_listener(REGISTER) so that "next_cpu:" can reuse the listener allocated for the previous cpu, this doesn't look exactly right even if minor.
Change the code to kfree() in the already-registered case, this case is unlikely anyway so the extra kmalloc_node() shouldn't hurt but looke more correct and clean.
2. use the plain list_for_each_entry() instead of _safe() to scan listeners->list.
3. Remove the unneeded INIT_LIST_HEAD(&s->list), we are going to list_add(&s->list).
---
kernel/taskstats.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
kernel/taskstats.c renamed from kernel/taskstats.c~1_cleanup +7 -9
@@ -291,30 +291,28 @@ static int add_del_listener(pid_t pid, cif (!cpumask_subset (mask, cpu_possible_mask))return -EINVAL ; - s =NULL ;if (isadd ==REGISTER ) {for_each_cpu (cpu, mask) { -if (!s) - s =kmalloc_node (sizeof (struct listener ), -GFP_KERNEL ,cpu_to_node (cpu)); + s =kmalloc_node (sizeof (struct listener ), +GFP_KERNEL ,cpu_to_node (cpu));if (!s) goto cleanup; + s->pid = pid; -INIT_LIST_HEAD (&s->list); s->valid =1 ; listeners = &per_cpu (listener_array, cpu);down_write (&listeners->sem); -list_for_each_entry_safe (s2, tmp, &listeners->list, list) { +list_for_each_entry (s2, &listeners->list, list) {if (s2->pid == pid) - goto next_cpu; + goto exists; }list_add (&s->list, &listeners->list); s =NULL ; -next_cpu: +exists:up_write (&listeners->sem); +kfree (s);/* nop if NULL */ } -kfree (s);return 0 ; }
Re: [PATCH 1/2] taskstats: add_del_listener() shouldn't use the wrong node
Quoted 9 lines · Oleg Nesterov
1.
26c4caea"don't allow duplicate entries in listener mode" changedadd_del_listener(REGISTER)so that "next_cpu:" can reuse the listener allocated for the previous cpu, this doesn't look exactly right even if minor.Change the code to
kfree()in the already-registered case, this case is unlikely anyway so the extrakmalloc_node()shouldn't hurt but looke more correct and clean.
Quoted 5 lines
2. use the plain
list_for_each_entry()instead of_safe()to scanlisteners->list.3. Remove the unneeded
INIT_LIST_HEAD(&s->list), we are going tolist_add(&s->list).
I don't know whether (1) is needed, looks very minor to me. Other than that:
Quoted 1 line
Signed-off-by Oleg Nesterov <[email protected]>
Quoted 46 lines
---
kernel/taskstats.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)kernel/taskstats.c renamed from kernel/taskstats.c~1_cleanup +7
-9@@ -291,30 +291,28 @@ static int add_del_listener(pid_t pid, cif (!cpumask_subset (mask, cpu_possible_mask))return -EINVAL ; - s =NULL ;if (isadd ==REGISTER ) {for_each_cpu (cpu, mask) { -if (!s) - s =kmalloc_node (sizeof (struct listener ), -GFP_KERNEL ,cpu_to_node (cpu)); + s =kmalloc_node (sizeof (struct listener ), +GFP_KERNEL ,cpu_to_node (cpu));if (!s) goto cleanup; + s->pid = pid; -INIT_LIST_HEAD (&s->list); s->valid =1 ; listeners = &per_cpu (listener_array, cpu);down_write (&listeners->sem); -list_for_each_entry_safe (s2, tmp, &listeners->list, list) { +list_for_each_entry (s2, &listeners->list, list) {if (s2->pid == pid) - goto next_cpu; + goto exists; }list_add (&s->list, &listeners->list); s =NULL ; -next_cpu: +exists:up_write (&listeners->sem); +kfree (s);/* nop if NULL */ } -kfree (s);return 0 ; }
Signature · 2 lines
Vasiliy Kulikov http://www.openwall.com - bringing security into open computing environments
Re: [PATCH 1/2] taskstats: add_del_listener() shouldn't use the wrong node
In reply to Oleg NesterovQuoted 4 lines · Oleg Nesterov
1.
26c4caea"don't allow duplicate entries in listener mode" changedadd_del_listener(REGISTER)so that "next_cpu:" can reuse the listener allocated for the previous cpu, this doesn't look exactly right even if minor.
That construction is somewhat unusual. I agree that this code looks cleaner and probably reduces the risk that someone in the future misunderstand the code.
Quoted 5 lines
Change the code to
kfree()in the already-registered case, this case is unlikely anyway so the extrakmalloc_node()shouldn't hurt but looke more correct and clean.
Quoted 7 lines
2. use the plain
list_for_each_entry()instead of_safe()to scanlisteners->list.3. Remove the unneeded
INIT_LIST_HEAD(&s->list), we are going tolist_add(&s->list).Signed-off-by Oleg Nesterov <[email protected]>
Quoted 46 lines
---
kernel/taskstats.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)kernel/taskstats.c renamed from kernel/taskstats.c~1_cleanup +7
-9@@ -291,30 +291,28 @@ static int add_del_listener(pid_t pid, cif (!cpumask_subset (mask, cpu_possible_mask))return -EINVAL ; - s =NULL ;if (isadd ==REGISTER ) {for_each_cpu (cpu, mask) { -if (!s) - s =kmalloc_node (sizeof (struct listener ), -GFP_KERNEL ,cpu_to_node (cpu)); + s =kmalloc_node (sizeof (struct listener ), +GFP_KERNEL ,cpu_to_node (cpu));if (!s) goto cleanup; + s->pid = pid; -INIT_LIST_HEAD (&s->list); s->valid =1 ; listeners = &per_cpu (listener_array, cpu);down_write (&listeners->sem); -list_for_each_entry_safe (s2, tmp, &listeners->list, list) { +list_for_each_entry (s2, &listeners->list, list) {if (s2->pid == pid) - goto next_cpu; + goto exists; }list_add (&s->list, &listeners->list); s =NULL ; -next_cpu: +exists:up_write (&listeners->sem); +kfree (s);/* nop if NULL */ } -kfree (s);return 0 ; }
PATCH 2/2 taskstats: add_del_listener() should ignore !valid listener's
In reply to Oleg NesterovWhen send_cpu_listeners() finds the orphaned listener it marks it as !valid and drops listeners->sem. Before it takes this sem for wrinting, s->pid can be reused and add_del_listener() can wrongly try to re-use this entry.
Change add_del_listener() to check ->valid = T.
---
kernel/taskstats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/taskstats.c renamed from kernel/taskstats.c~2_ck_valid +1 -1
@@ -304,7 +304,7 @@ static int add_del_listener(pid_t pid, c listeners = &per_cpu (listener_array, cpu);down_write (&listeners->sem);list_for_each_entry (s2, &listeners->list, list) { -if (s2->pid == pid) +if (s2->pid == pid && s2->valid) goto exists; }list_add (&s->list, &listeners->list);
Re: [PATCH 2/2] taskstats: add_del_listener() should ignore !valid listener's
Quoted 6 lines · Oleg Nesterov
When
send_cpu_listeners()finds the orphaned listener it marks it as !valid and dropslisteners->sem. Before it takes this sem for wrinting,s->pidcan be reused andadd_del_listener()can wrongly try to re-use this entry.Change
add_del_listener()to check ->valid = T.
I think the current logic is wrong. If s was claimed is invalid, it then points to a dead task, it is unknown when it died. As the same pid can be reused by a new process BEFORE add_del_listener(), it is unknown whether ->pid points to the actual owner task.
Rather than optimizing the wrong algorithm it's better to change the processes keeping way.
Thanks,
Signature · 2 lines
Vasiliy Kulikov http://www.openwall.com - bringing security into open computing environments
Re: [PATCH 2/2] taskstats: add_del_listener() should ignore !valid listener's
Quoted 10 lines · Vasiliy Kulikov
Quoted 6 lines · Oleg Nesterov
When
send_cpu_listeners()finds the orphaned listener it marks it as !valid and dropslisteners->sem. Before it takes this sem for wrinting,s->pidcan be reused andadd_del_listener()can wrongly try to re-use this entry.Change
add_del_listener()to check ->valid = T.I think the current logic is wrong.
me too ;)
still I think this patch makes sense anyway.
Quoted 2 lines
If s was claimed is invalid, it
then points to a dead task,
I forgot everything I knew about netlink. But, it seems, netlink_bind() can use nl_pid != current->pid. But even if this is not true,
Quoted 3 lines
it is unknown when it died. As the same pid
can be reused by a new process BEFOREadd_del_listener(), it is unknown whether ->pid points to the actual owner task.
And? Why should we try to reuse the !valid entries? struct listener is just the "addr" we should send the message to. If someone calls add_listener() it should works regardless of dead entries with the same ->pid.
Quoted 2 lines
Rather than optimizing the wrong algorithm it's better to change the processes keeping way.
Not sure I understand... This is not optimizing, the patch tries to fix the unlikely (in fact mostly theoretical) and minor problem. Still this is the problem, no?
Thanks,
Oleg.
Vasiliy Kulikov
Reviewed-byRe: [PATCH 2/2] taskstats: add_del_listener() should ignore !valid listener's
Quoted 8 lines · Oleg Nesterov
Quoted 3 lines
it is unknown when it died. As the same pid
can be reused by a new process BEFOREadd_del_listener(), it is unknown whether ->pid points to the actual owner task.And? Why should we try to reuse the !valid entries? struct listener is just the "addr" we should send the message to. If someone calls
add_listener()it should works regardless of dead entries with the same ->pid.
True.
Quoted 5 lines
Quoted 2 lines
Rather than optimizing the wrong algorithm it's better to change the processes keeping way.
Not sure I understand... This is not optimizing, the patch tries to fix the unlikely (in fact mostly theoretical) and minor problem.
Ah, I see the problem here. Yes, then it surely makes sense.
Thanks,
Signature · 2 lines
Vasiliy Kulikov http://www.openwall.com - bringing security into open computing environments
Re: [PATCH 2/2] taskstats: add_del_listener() should ignore !valid listener's
Quoted 7 lines · Vasiliy Kulikov
Quoted 3 lines · Oleg Nesterov
Not sure I understand... This is not optimizing, the patch tries to fix the unlikely (in fact mostly theoretical) and minor problem.
Ah, I see the problem here. Yes, then it surely makes sense.
Yes, agreed.
Just in case... please note that "s->pid can be reused" doesn't necessarily mean this pid was reused by kernel. For example, a task can close the socket without DEREGISTER, then create another one and do REGISTER which can race with send_cpu_listeners(). Afaics.
All this register/deregister logic doesn't look very right, imho.
Quoted 1 line
Reviewed-by Vasiliy Kulikov <[email protected]>
Thanks,
Oleg.
Re: [PATCH 2/2] taskstats: add_del_listener() should ignore !valid listener's
In reply to Oleg NesterovQuoted 8 lines · Oleg Nesterov
When
send_cpu_listeners()finds the orphaned listener it marks it as !valid and dropslisteners->sem. Before it takes this sem for wrinting,s->pidcan be reused andadd_del_listener()can wrongly try to re-use this entry.Change
add_del_listener()to check ->valid = T.Signed-off-by Oleg Nesterov <[email protected]>
BTW, some namespace changes are pending from my side. I need to get it, its on my TODO list
Balbir Singh