Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH -mm 0/3] proc: task->signal can't be NULL

6 views
Skip to first unread message

Oleg Nesterov

unread,
Mar 22, 2010, 2:50:02 PM3/22/10
to
With the recent changes in -mm it is always safe to dereference
task->signal. It can't be NULL and it is pinned to task_struct.

fs/proc becomes the only valid user of signal->count which should
either die or become "int nr_threads".


Alexey, Eric.

Can't we kill this counter? Afaics, get_nr_threads() doesn't need to
be "precise", we probably can estimate the number of threads using
signal->live (yes sure, we can't use ->live as nr_threads).

Except: first_tid() uses get_nr_threads() for optimization. Is this
optimization really important? Afaics, it only helps in the unlikely
case, probably in that case the extra lockless while_each_thread()
doesn't hurt.

IOW, how about

--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3071,11 +3071,6 @@ static struct task_struct *first_tid(str
goto found;
}

- /* If nr exceeds the number of threads there is nothing todo */
- pos = NULL;
- if (nr && nr >= get_nr_threads(leader))
- goto out;
-
/* If we haven't found our starting place yet start
* with the leader and walk nr threads forward.
*/

?

Not that I think it is terribly important to kill this counter, and
probably signal->nr_threads can make sense anyway, so far I am just
curious.

Oleg.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Eric W. Biederman

unread,
Mar 22, 2010, 10:20:02 PM3/22/10
to
Oleg Nesterov <ol...@redhat.com> writes:

I think that was just a sanity check since it was easy. I want to say
it prevents a DOS attack with user space passing unreasonably large
file position but that DOS attack is handled by ensuring we don't walk
through the list if threads more than once.

However:
proc_task_getattr uses get_nr_threads to get it's nlink count correct.

Not walking the thread list to get the number of threads seems like an
important cpu time saving measure.

Eric

Oleg Nesterov

unread,
Mar 23, 2010, 2:40:01 PM3/23/10
to
On 03/22, Eric W. Biederman wrote:

If a bad user passes the large f_pos > nr_threads then this check
eliminates the unneeded while_each_thread() loop, yes. But it can use
f_pos == nr_threads and provoke the same loop?

Or. just do rewinddir() + readdir(big_count). Now we walk through the
list and call proc_task_fill_cache() for each entry.

IOW, I don't understand how this check can help from the DOS pov.

> However:
> proc_task_getattr uses get_nr_threads to get it's nlink count correct.

Yes. But we don't need the exactly precise number here if we are
racing with fork/exit ?

> Not walking the thread list to get the number of threads seems like an
> important cpu time saving measure.

Not sure I understand... Also, first_tid() could use sig->sigcnt (the
reference counter) instead of sig->count. This is not the same, but I
think in practice this is fine.


OK. Let's keep this counter as "int nr_thread".

Besides, when I tried to re-implement get_nr_threads() using signal->live
I got the really ugly result ;)

Thanks.

Oleg.

Eric W. Biederman

unread,
Mar 23, 2010, 5:00:02 PM3/23/10
to
Oleg Nesterov <ol...@redhat.com> writes:

> On 03/22, Eric W. Biederman wrote:
>>
>> Oleg Nesterov <ol...@redhat.com> writes:
>
> If a bad user passes the large f_pos > nr_threads then this check
> eliminates the unneeded while_each_thread() loop, yes. But it can use
> f_pos == nr_threads and provoke the same loop?
>
> Or. just do rewinddir() + readdir(big_count). Now we walk through the
> list and call proc_task_fill_cache() for each entry.
>
> IOW, I don't understand how this check can help from the DOS pov.

It can't. I just want it to be able to ;)

>> However:
>> proc_task_getattr uses get_nr_threads to get it's nlink count correct.
>
> Yes. But we don't need the exactly precise number here if we are
> racing with fork/exit ?
>
>> Not walking the thread list to get the number of threads seems like an
>> important cpu time saving measure.
>
> Not sure I understand... Also, first_tid() could use sig->sigcnt (the
> reference counter) instead of sig->count. This is not the same, but I
> think in practice this is fine.

We need a value that can be computed in constant time, and is not correct
except when the number of threads is actively changing.

> OK. Let's keep this counter as "int nr_thread".
>
> Besides, when I tried to re-implement get_nr_threads() using signal->live
> I got the really ugly result ;)

Sounds good.

Eric

Oleg Nesterov

unread,
Mar 24, 2010, 2:00:02 PM3/24/10
to
On 03/23, Eric W. Biederman wrote:
>
> We need a value that can be computed in constant time, and is not correct
> except when the number of threads is actively changing.

Sure. I was thinking of something like

int get_nr_threads(struct task_struct *tsk)
{
int nr = atomic_read(&task->signal->live);
int reasonable_min = 1;

rcu_read_lock();
if (!thread_group_leader(tsk) && pid_alive(tsk) &&
tsk->group_leader->exit_state)
reasonable_min = 2;
rcu_read_unlock();

return max(nr, reasonable_min);
}

but as I said this doesn't look nice at all.

> > OK. Let's keep this counter as "int nr_thread".
> >
> > Besides, when I tried to re-implement get_nr_threads() using signal->live
> > I got the really ugly result ;)
>
> Sounds good.

OK, please see the "final" patch I am going to send...

Oleg.

0 new messages