diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-03-31 05:31:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-31 15:18:59 -0500 |
commit | 390e2ff07712468ce6600a43aa91e897b056ce12 (patch) | |
tree | fb92d3c2218fa3e41078d1b5e103892ac7e95117 /kernel/sys.c | |
parent | 9741ef964dc8bfeb6520825df9fed8f538c3336e (diff) |
[PATCH] Make setsid() more robust
The core problem: setsid fails if it is called by init. The effect in 2.6.16
and the earlier kernels that have this problem is that if you do a "ps -j 1 or
ps -ej 1" you will see that init and several of it's children have process
group and session == 0. Instead of process group == session == 1. Despite
init calling setsid.
The reason it fails is that daemonize calls set_special_pids(1,1) on kernel
threads that are launched before /sbin/init is called.
The only remaining effect in that current->signal->leader == 0 for init
instead of 1. And the setsid call fails. No one has noticed because
/sbin/init does not check the return value of setsid.
In 2.4 where we don't have the pidhash table, and daemonize doesn't exist
setsid actually works for init.
I care a lot about pid == 1 not being a special case that we leave broken,
because of the container/jail work that I am doing.
- Carefully allow init (pid == 1) to call setsid despite the kernel using
its session.
- Use find_task_by_pid instead of find_pid because find_pid taking a
pidtype is going away.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 7ef7f6054c28..0b6ec0e7936f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1372,18 +1372,29 @@ asmlinkage long sys_getsid(pid_t pid) | |||
1372 | asmlinkage long sys_setsid(void) | 1372 | asmlinkage long sys_setsid(void) |
1373 | { | 1373 | { |
1374 | struct task_struct *group_leader = current->group_leader; | 1374 | struct task_struct *group_leader = current->group_leader; |
1375 | struct pid *pid; | 1375 | pid_t session; |
1376 | int err = -EPERM; | 1376 | int err = -EPERM; |
1377 | 1377 | ||
1378 | mutex_lock(&tty_mutex); | 1378 | mutex_lock(&tty_mutex); |
1379 | write_lock_irq(&tasklist_lock); | 1379 | write_lock_irq(&tasklist_lock); |
1380 | 1380 | ||
1381 | pid = find_pid(PIDTYPE_PGID, group_leader->pid); | 1381 | /* Fail if I am already a session leader */ |
1382 | if (pid) | 1382 | if (group_leader->signal->leader) |
1383 | goto out; | ||
1384 | |||
1385 | session = group_leader->pid; | ||
1386 | /* Fail if a process group id already exists that equals the | ||
1387 | * proposed session id. | ||
1388 | * | ||
1389 | * Don't check if session id == 1 because kernel threads use this | ||
1390 | * session id and so the check will always fail and make it so | ||
1391 | * init cannot successfully call setsid. | ||
1392 | */ | ||
1393 | if (session > 1 && find_task_by_pid_type(PIDTYPE_PGID, session)) | ||
1383 | goto out; | 1394 | goto out; |
1384 | 1395 | ||
1385 | group_leader->signal->leader = 1; | 1396 | group_leader->signal->leader = 1; |
1386 | __set_special_pids(group_leader->pid, group_leader->pid); | 1397 | __set_special_pids(session, session); |
1387 | group_leader->signal->tty = NULL; | 1398 | group_leader->signal->tty = NULL; |
1388 | group_leader->signal->tty_old_pgrp = 0; | 1399 | group_leader->signal->tty_old_pgrp = 0; |
1389 | err = process_group(group_leader); | 1400 | err = process_group(group_leader); |