Re: Limits broken in 2.4.x kernel.

Andrew Morton
2002-01-29T08:32:49Z

Trond Myklebust wrote:
>
> >>>>> " " == Andrew Morton <akpm@zip.com.au> writes:
>
> > reparent_to_init() needs to decrement current->user's processes
> > count, and increment root's. I'll do a patch.
>
> Please just convert 'set_user()' into a non-static routine. Calling
> set_user(0, 1) would do precisely what you want, and the same thing
> could then be used for kmod.
> There's no real reason for having several different local hacks that
> all do the same thing kicking around the place.
>

I bet you thought I'd forgotten.

- Make set_user() non-static

- Convert set_user() to use cached copy of `current'

- Fix world's tiniest SMP race in set_user() - we should
increment usage count on the old struct before decrementing the
count on the new one - they may be the same.

- change exec_usermodehelper() to use set_user()

- change reparent_to_init() to use set_user() - fixes possible
error in user process accounting.

It is all tested.

--- linux-2.4.18-pre7/include/linux/sched.h Fri Dec 21 11:19:23 2001
+++ linux-akpm/include/linux/sched.h Tue Jan 29 00:04:58 2002
@@ -150,6 +150,7 @@ extern void trap_init(void);
extern void update_process_times(int user);
extern void update_one_process(struct task_struct *p, unsigned long user,
unsigned long system, int cpu);
+extern int set_user(uid_t new_ruid, int dumpclear);

#define MAX_SCHEDULE_TIMEOUT LONG_MAX
extern signed long FASTCALL(schedule_timeout(signed long timeout));
--- linux-2.4.18-pre7/kernel/sys.c Wed Jan 23 15:11:35 2002
+++ linux-akpm/kernel/sys.c Tue Jan 29 00:07:02 2002
@@ -490,9 +490,10 @@ static inline void cap_emulate_setxuid(i
}
}

-static int set_user(uid_t new_ruid, int dumpclear)
+int set_user(uid_t new_ruid, int dumpclear)
{
struct user_struct *new_user, *old_user;
+ struct task_struct *this_task = current;

/* What if a process setreuid()'s and this brings the
* new uid over his NPROC rlimit? We can check this now
@@ -502,17 +503,16 @@ static int set_user(uid_t new_ruid, int
new_user = alloc_uid(new_ruid);
if (!new_user)
return -EAGAIN;
- old_user = current->user;
- atomic_dec(&old_user->processes);
+ old_user = this_task->user;
atomic_inc(&new_user->processes);
+ atomic_dec(&old_user->processes);

- if(dumpclear)
- {
- current->mm->dumpable = 0;
+ if (dumpclear && this_task->mm) {
+ this_task->mm->dumpable = 0;
wmb();
}
- current->uid = new_ruid;
- current->user = new_user;
+ this_task->uid = new_ruid;
+ this_task->user = new_user;
free_uid(old_user);
return 0;
}
--- linux-2.4.18-pre7/kernel/sched.c Fri Dec 21 11:19:23 2001
+++ linux-akpm/kernel/sched.c Tue Jan 29 00:04:58 2002
@@ -1259,7 +1259,8 @@ void reparent_to_init(void)
this_task->cap_permitted = CAP_FULL_SET;
this_task->keep_capabilities = 0;
memcpy(this_task->rlim, init_task.rlim, sizeof(*(this_task->rlim)));
- this_task->user = INIT_USER;
+ /* Become root */
+ set_user(0, 0);

spin_unlock(&runqueue_lock);
write_unlock_irq(&tasklist_lock);
--- linux-2.4.18-pre7/kernel/kmod.c Tue Jul 17 18:23:50 2001
+++ linux-akpm/kernel/kmod.c Tue Jan 29 00:04:58 2002
@@ -111,15 +111,8 @@ int exec_usermodehelper(char *program_pa
if (curtask->files->fd[i]) close(i);
}

- /* Drop the "current user" thing */
- {
- struct user_struct *user = curtask->user;
- curtask->user = INIT_USER;
- atomic_inc(&INIT_USER->__count);
- atomic_inc(&INIT_USER->processes);
- atomic_dec(&user->processes);
- free_uid(user);
- }
+ /* Become root */
+ set_user(0, 1);

/* Give kmod all effective privileges.. */
curtask->euid = curtask->fsuid = 0;