Skip to content

Commit

Permalink
sys_personality: change sys_personality() to accept "unsigned int" in…
Browse files Browse the repository at this point in the history
…stead of u_long

task_struct->pesonality is "unsigned int", but sys_personality() paths use
"unsigned long pesonality".  This means that every assignment or
comparison is not right.  In particular, if this argument does not fit
into "unsigned int" __set_personality() changes the caller's personality
and then sys_personality() returns -EINVAL.

Turn this argument into "unsigned int" and avoid overflows.  Obviously,
this is the user-visible change, we just ignore the upper bits.  But this
can't break the sane application.

There is another thing which can confuse the poorly written applications.
User-space thinks that this syscall returns int, not long.  This means
that the returned value can be negative and look like the error code.  But
note that libc won't be confused and thus errno won't be set, and with
this patch the user-space can never get -1 unless sys_personality() really
fails.  And, most importantly, the negative RET != -1 is only possible if
that app previously called personality(RET).

Pointed-out-by: Wenming Zhang <wezhang@redhat.com>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Oleg Nesterov authored and Linus Torvalds committed Jun 4, 2010
1 parent d6d03f9 commit 485d527
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 11 deletions.
2 changes: 1 addition & 1 deletion include/linux/personality.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct pt_regs;

extern int register_exec_domain(struct exec_domain *);
extern int unregister_exec_domain(struct exec_domain *);
extern int __set_personality(unsigned long);
extern int __set_personality(unsigned int);

#endif /* __KERNEL__ */

Expand Down
2 changes: 1 addition & 1 deletion include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ asmlinkage long sys_capget(cap_user_header_t header,
cap_user_data_t dataptr);
asmlinkage long sys_capset(cap_user_header_t header,
const cap_user_data_t data);
asmlinkage long sys_personality(u_long personality);
asmlinkage long sys_personality(unsigned int personality);

asmlinkage long sys_sigpending(old_sigset_t __user *set);
asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set,
Expand Down
18 changes: 9 additions & 9 deletions kernel/exec_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static struct exec_domain *exec_domains = &default_exec_domain;
static DEFINE_RWLOCK(exec_domains_lock);


static u_long ident_map[32] = {
static unsigned long ident_map[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
Expand Down Expand Up @@ -56,10 +56,10 @@ default_handler(int segment, struct pt_regs *regp)
}

static struct exec_domain *
lookup_exec_domain(u_long personality)
lookup_exec_domain(unsigned int personality)
{
struct exec_domain * ep;
u_long pers = personality(personality);
unsigned int pers = personality(personality);
struct exec_domain *ep;

read_lock(&exec_domains_lock);
for (ep = exec_domains; ep; ep = ep->next) {
Expand All @@ -70,7 +70,7 @@ lookup_exec_domain(u_long personality)

#ifdef CONFIG_MODULES
read_unlock(&exec_domains_lock);
request_module("personality-%ld", pers);
request_module("personality-%d", pers);
read_lock(&exec_domains_lock);

for (ep = exec_domains; ep; ep = ep->next) {
Expand Down Expand Up @@ -135,7 +135,7 @@ unregister_exec_domain(struct exec_domain *ep)
}

int
__set_personality(u_long personality)
__set_personality(unsigned int personality)
{
struct exec_domain *ep, *oep;

Expand Down Expand Up @@ -188,17 +188,17 @@ static int __init proc_execdomains_init(void)
module_init(proc_execdomains_init);
#endif

SYSCALL_DEFINE1(personality, u_long, personality)
SYSCALL_DEFINE1(personality, unsigned int, personality)
{
u_long old = current->personality;
unsigned int old = current->personality;

if (personality != 0xffffffff) {
set_personality(personality);
if (current->personality != personality)
return -EINVAL;
}

return (long)old;
return old;
}


Expand Down

0 comments on commit 485d527

Please sign in to comment.