Skip to contentSkip to conversation

for 2.6.18, revert "Drop tasklist lock in do_sched_setscheduler"

PATCH In review Oleg Nesterov 1 participant 2 messages Aug 19, 2006

lore
Share & tools
lore
#0 lore raw

PATCH 1/4 for 2.6.18, revert "Drop tasklist lock in do_sched_setscheduler"

sched_setscheduler() looks at ->signal->rlim[]. It is unsafe do dereference ->signal unless tasklist_lock or ->siglock is held (or p == current). We pin the task structure, but this can't prevent from release_task()->__exit_signal() which sets ->signal = NULL.

Restore tasklist_lock across the setscheduler call.

kernel/sched.c renamed from kernel/sched.c~1_revert +1 -3
@@ -4162,10 +4162,8 @@ do_sched_setscheduler(pid_t pid, int pol
 		read_unlock_irq(&tasklist_lock);
 		return -ESRCH;
 	}
-	get_task_struct(p);
-	read_unlock_irq(&tasklist_lock);
 	retval = sched_setscheduler(p, policy, &lparam);
-	put_task_struct(p);
+	read_unlock_irq(&tasklist_lock);
 
 	return retval;
 }
#1 lore raw
Quoted 5 lines · Oleg Nesterov

sched_setscheduler() looks at ->signal->rlim[]. It is unsafe do dereference ->signal unless tasklist_lock or ->siglock is held (or p == current). We pin the task structure, but this can't prevent from release_task()->__exit_signal() which sets ->signal = NULL.

See the testcase below, 2.6.18-rc4 oopses. The stable tree is ok, the problem was introduced during 2.6.18 development.

Oleg.

#!/usr/bin/perl

pipe R, W;

if (fork) {
	while (sysread R, $_, 4) {
		do {
			syscall 156, unpack('i', $_), 1, pack('i', 1);
		} while $! == 1; # EPERM
	}
} else {
	wait while fork;
	syswrite W, pack 'i', $$;
}