From: Tomas Olsson sys_getgroups16 (or rather groups16_to_user()) returns large gids truncated. Needs to be fixed, one way or another. Don't know why the other similar casts are still there. Signed-off-by: Andrew Morton --- 25-akpm/include/linux/sched.h | 10 +++++++++- 25-akpm/kernel/uid16.c | 12 ++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff -puN kernel/uid16.c~getgroups16-fix kernel/uid16.c --- 25/kernel/uid16.c~getgroups16-fix Mon Jun 7 14:48:03 2004 +++ 25-akpm/kernel/uid16.c Mon Jun 7 14:48:03 2004 @@ -39,7 +39,7 @@ asmlinkage long sys_setregid16(old_gid_t asmlinkage long sys_setgid16(old_gid_t gid) { - return sys_setgid((gid_t)gid); + return sys_setgid(low2highgid(gid)); } asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid) @@ -49,7 +49,7 @@ asmlinkage long sys_setreuid16(old_uid_t asmlinkage long sys_setuid16(old_uid_t uid) { - return sys_setuid((uid_t)uid); + return sys_setuid(low2highuid(uid)); } asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid) @@ -88,12 +88,12 @@ asmlinkage long sys_getresgid16(old_gid_ asmlinkage long sys_setfsuid16(old_uid_t uid) { - return sys_setfsuid((uid_t)uid); + return sys_setfsuid(low2highuid(uid)); } asmlinkage long sys_setfsgid16(old_gid_t gid) { - return sys_setfsgid((gid_t)gid); + return sys_setfsgid(low2highgid(gid)); } static int groups16_to_user(old_gid_t __user *grouplist, @@ -103,7 +103,7 @@ static int groups16_to_user(old_gid_t __ old_gid_t group; for (i = 0; i < group_info->ngroups; i++) { - group = (old_gid_t)GROUP_AT(group_info, i); + group = high2lowgid(GROUP_AT(group_info, i)); if (put_user(group, grouplist+i)) return -EFAULT; } @@ -120,7 +120,7 @@ static int groups16_from_user(struct gro for (i = 0; i < group_info->ngroups; i++) { if (get_user(group, grouplist+i)) return -EFAULT; - GROUP_AT(group_info, i) = (gid_t)group; + GROUP_AT(group_info, i) = low2highgid(group); } return 0; diff -puN include/linux/sched.h~getgroups16-fix include/linux/sched.h --- 25/include/linux/sched.h~getgroups16-fix Mon Jun 7 14:48:03 2004 +++ 25-akpm/include/linux/sched.h Mon Jun 7 14:48:03 2004 @@ -371,6 +371,12 @@ struct group_info { gid_t *blocks[0]; }; +/* + * get_group_info() must be called with the owning task locked (via task_lock()) + * when task != current. The reason being that the vast majority of callers are + * looking at current->group_info, which can not be changed except by the + * current task. Changing current->group_info requires the task lock, too. + */ #define get_group_info(group_info) do { \ atomic_inc(&(group_info)->usage); \ } while (0) @@ -966,7 +972,9 @@ static inline int thread_group_empty(tas extern void unhash_process(struct task_struct *p); /* - * Protects ->fs, ->files, ->mm, ->ptrace and synchronises with wait4(). + * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info and synchronises with + * wait4(). + * * Nests both inside and outside of read_lock(&tasklist_lock). * It must not be nested with write_lock_irq(&tasklist_lock), * neither inside nor outside. _