Commit ea3bc13f authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] More support for upward growing stacks

 - remove elf_caddr_t. It's positively dangerous to #define this since
   elf_caddr_t foo, bar; creates variables of different types (foo is
   char *, bar is char).
 - rewrite large chunks of create_elf_tables(), it needed cleaning anyway.
 - add upwards-growing stack support to create_elf_tables.
 - redefine the ARCH_DLINFO stuff on powerpc -- it's tested, works.
 - add upwards-growing-stack support to exec.c too.
parent b4093e0c
...@@ -54,7 +54,6 @@ static struct linux_binfmt irix_format = { ...@@ -54,7 +54,6 @@ static struct linux_binfmt irix_format = {
#ifndef elf_addr_t #ifndef elf_addr_t
#define elf_addr_t unsigned long #define elf_addr_t unsigned long
#define elf_caddr_t char *
#endif #endif
#ifdef DEBUG_ELF #ifdef DEBUG_ELF
...@@ -155,8 +154,8 @@ unsigned long * create_irix_tables(char * p, int argc, int envc, ...@@ -155,8 +154,8 @@ unsigned long * create_irix_tables(char * p, int argc, int envc,
unsigned int interp_load_addr, unsigned int interp_load_addr,
struct pt_regs *regs, struct elf_phdr *ephdr) struct pt_regs *regs, struct elf_phdr *ephdr)
{ {
elf_caddr_t *argv; elf_addr_t *argv;
elf_caddr_t *envp; elf_addr_t *envp;
elf_addr_t *sp, *csp; elf_addr_t *sp, *csp;
#ifdef DEBUG_ELF #ifdef DEBUG_ELF
...@@ -202,20 +201,20 @@ unsigned long * create_irix_tables(char * p, int argc, int envc, ...@@ -202,20 +201,20 @@ unsigned long * create_irix_tables(char * p, int argc, int envc,
#undef NEW_AUX_ENT #undef NEW_AUX_ENT
sp -= envc+1; sp -= envc+1;
envp = (elf_caddr_t *) sp; envp = sp;
sp -= argc+1; sp -= argc+1;
argv = (elf_caddr_t *) sp; argv = sp;
__put_user((elf_addr_t)argc,--sp); __put_user((elf_addr_t)argc,--sp);
current->mm->arg_start = (unsigned long) p; current->mm->arg_start = (unsigned long) p;
while (argc-->0) { while (argc-->0) {
__put_user((elf_caddr_t)(unsigned long)p,argv++); __put_user((unsigned long)p,argv++);
p += strlen_user(p); p += strlen_user(p);
} }
__put_user(NULL, argv); __put_user(NULL, argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p; current->mm->arg_end = current->mm->env_start = (unsigned long) p;
while (envc-->0) { while (envc-->0) {
__put_user((elf_caddr_t)(unsigned long)p,envp++); __put_user((unsigned long)p,envp++);
p += strlen_user(p); p += strlen_user(p);
} }
__put_user(NULL, envp); __put_user(NULL, envp);
......
...@@ -80,7 +80,6 @@ struct elf_prpsinfo32 ...@@ -80,7 +80,6 @@ struct elf_prpsinfo32
}; };
#define elf_addr_t u32 #define elf_addr_t u32
#define elf_caddr_t u32
#define init_elf_binfmt init_elf32_binfmt #define init_elf_binfmt init_elf32_binfmt
#undef CONFIG_BINFMT_ELF #undef CONFIG_BINFMT_ELF
#ifdef CONFIG_BINFMT_ELF32 #ifdef CONFIG_BINFMT_ELF32
......
...@@ -166,7 +166,6 @@ struct elf_prpsinfo32 ...@@ -166,7 +166,6 @@ struct elf_prpsinfo32
#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) #define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
#define elf_addr_t u32 #define elf_addr_t u32
#define elf_caddr_t u32
/* /*
#define init_elf_binfmt init_elf32_binfmt #define init_elf_binfmt init_elf32_binfmt
*/ */
......
...@@ -147,7 +147,6 @@ jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value) ...@@ -147,7 +147,6 @@ jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value)
} }
#define elf_addr_t u32 #define elf_addr_t u32
#define elf_caddr_t u32
#undef start_thread #undef start_thread
#define start_thread start_thread32 #define start_thread start_thread32
#define init_elf_binfmt init_elf32_binfmt #define init_elf_binfmt init_elf32_binfmt
......
...@@ -186,7 +186,6 @@ MODULE_AUTHOR("Eric Youngdale, Andi Kleen"); ...@@ -186,7 +186,6 @@ MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
#undef MODULE_AUTHOR #undef MODULE_AUTHOR
#define elf_addr_t __u32 #define elf_addr_t __u32
#define elf_caddr_t __u32
static void elf32_init(struct pt_regs *); static void elf32_init(struct pt_regs *);
......
...@@ -39,19 +39,15 @@ ...@@ -39,19 +39,15 @@
#include <asm/param.h> #include <asm/param.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#define DLINFO_ITEMS 13
#include <linux/elf.h> #include <linux/elf.h>
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_elf_library(struct file*); static int load_elf_library(struct file*);
static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
extern void dump_thread(struct pt_regs *, struct user *);
#ifndef elf_addr_t #ifndef elf_addr_t
#define elf_addr_t unsigned long #define elf_addr_t unsigned long
#define elf_caddr_t char *
#endif #endif
/* /*
...@@ -88,9 +84,9 @@ static void set_brk(unsigned long start, unsigned long end) ...@@ -88,9 +84,9 @@ static void set_brk(unsigned long start, unsigned long end)
{ {
start = ELF_PAGEALIGN(start); start = ELF_PAGEALIGN(start);
end = ELF_PAGEALIGN(end); end = ELF_PAGEALIGN(end);
if (end <= start) if (end > start)
return; do_brk(start, end - start);
do_brk(start, end - start); current->mm->start_brk = current->mm->brk = end;
} }
...@@ -111,134 +107,149 @@ static void padzero(unsigned long elf_bss) ...@@ -111,134 +107,149 @@ static void padzero(unsigned long elf_bss)
} }
} }
static elf_addr_t * /* Let's use some macros to make this stack manipulation a litle clearer */
create_elf_tables(char *p, int argc, int envc, #ifdef ARCH_STACK_GROWSUP
struct elfhdr * exec, #define STACK_ADD(sp, items) ((elf_addr_t *)(sp) + (items))
unsigned long load_addr, #define STACK_ROUND(sp, items) \
unsigned long load_bias, ((15 + (unsigned long) ((sp) + (items))) &~ 15UL)
unsigned long interp_load_addr, int ibcs) #define STACK_ALLOC(sp, len) ({ elf_addr_t old_sp = sp; sp += len; old_sp; })
#else
#define STACK_ADD(sp, items) ((elf_addr_t *)(sp) - (items))
#define STACK_ROUND(sp, items) \
(((unsigned long) (sp - items)) &~ 15UL)
#define STACK_ALLOC(sp, len) sp -= len
#endif
static void
create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
int interp_aout, unsigned long load_addr,
unsigned long interp_load_addr)
{ {
elf_caddr_t *argv; unsigned long p = bprm->p;
elf_caddr_t *envp; int argc = bprm->argc;
elf_addr_t *sp, *csp; int envc = bprm->envc;
char *k_platform, *u_platform; elf_addr_t *argv, *envp;
long hwcap; elf_addr_t *sp, u_platform;
size_t platform_len = 0; const char *k_platform = ELF_PLATFORM;
size_t len; int items;
elf_addr_t elf_info[30];
int ei_index = 0;
/* /*
* Get hold of platform and hardware capabilities masks for * If this architecture has a platform capability string, copy it
* the machine we are running on. In some cases (Sparc), * to userspace. In some cases (Sparc), this info is impossible
* this info is impossible to get, in others (i386) it is * for userspace to get any other way, in others (i386) it is
* merely difficult. * merely difficult.
*/ */
hwcap = ELF_HWCAP;
k_platform = ELF_PLATFORM;
if (k_platform) { if (k_platform) {
platform_len = strlen(k_platform) + 1; size_t len = strlen(k_platform) + 1;
u_platform = p - platform_len;
__copy_to_user(u_platform, k_platform, platform_len);
} else
u_platform = p;
#if defined(__i386__) && defined(CONFIG_SMP) #if defined(__i386__) && defined(CONFIG_SMP)
/* /*
* In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions * In some cases (e.g. Hyper-Threading), we want to avoid L1
* by the processes running on the same package. One thing we can do * evictions by the processes running on the same package. One
* is to shuffle the initial stack for them. * thing we can do is to shuffle the initial stack for them.
* *
* The conditionals here are unneeded, but kept in to make the * The conditionals here are unneeded, but kept in to make the
* code behaviour the same as pre change unless we have hyperthreaded * code behaviour the same as pre change unless we have
* processors. This should be cleaned up before 2.6 * hyperthreaded processors. This should be cleaned up
*/ * before 2.6
*/
if(smp_num_siblings > 1) if (smp_num_siblings > 1)
u_platform = u_platform - ((current->pid % 64) << 7); STACK_ALLOC(p, ((current->pid % 64) << 7));
#endif
/*
* Force 16 byte _final_ alignment here for generality.
*/
sp = (elf_addr_t *)(~15UL & (unsigned long)(u_platform));
csp = sp;
csp -= (1+DLINFO_ITEMS)*2 + (k_platform ? 2 : 0);
#ifdef DLINFO_ARCH_ITEMS
csp -= DLINFO_ARCH_ITEMS*2;
#endif #endif
csp -= envc+1; u_platform = STACK_ALLOC(p, len);
csp -= argc+1; __copy_to_user((void *)u_platform, k_platform, len);
csp -= (!ibcs ? 3 : 1); /* argc itself */ }
if ((unsigned long)csp & 15UL)
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
/* /* Create the ELF interpreter info */
* Put the ELF interpreter info on the stack #define NEW_AUX_ENT(id, val) \
*/ do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0)
#define NEW_AUX_ENT(nr, id, val) \
__put_user ((id), sp+(nr*2)); \
__put_user ((val), sp+(nr*2+1)); \
sp -= 2;
NEW_AUX_ENT(0, AT_NULL, 0);
if (k_platform) {
sp -= 2;
NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform);
}
sp -= DLINFO_ITEMS*2;
NEW_AUX_ENT( 0, AT_HWCAP, hwcap);
NEW_AUX_ENT( 1, AT_PAGESZ, ELF_EXEC_PAGESIZE);
NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC);
NEW_AUX_ENT( 3, AT_PHDR, load_addr + exec->e_phoff);
NEW_AUX_ENT( 4, AT_PHENT, sizeof (struct elf_phdr));
NEW_AUX_ENT( 5, AT_PHNUM, exec->e_phnum);
NEW_AUX_ENT( 6, AT_BASE, interp_load_addr);
NEW_AUX_ENT( 7, AT_FLAGS, 0);
NEW_AUX_ENT( 8, AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT( 9, AT_UID, (elf_addr_t) current->uid);
NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid);
NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid);
NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid);
#ifdef ARCH_DLINFO #ifdef ARCH_DLINFO
/* /*
* ARCH_DLINFO must come last so platform specific code can enforce * ARCH_DLINFO must come first so PPC can do its special alignment of
* special alignment requirements on the AUXV if necessary (eg. PPC). * AUXV.
*/ */
ARCH_DLINFO; ARCH_DLINFO;
#endif #endif
NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP);
NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE);
NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC);
NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff);
NEW_AUX_ENT(AT_PHENT, sizeof (struct elf_phdr));
NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
NEW_AUX_ENT(AT_BASE, interp_load_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
NEW_AUX_ENT(AT_UID, (elf_addr_t) current->uid);
NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->euid);
NEW_AUX_ENT(AT_GID, (elf_addr_t) current->gid);
NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->egid);
if (k_platform) {
NEW_AUX_ENT(AT_PLATFORM, u_platform);
}
NEW_AUX_ENT(AT_NULL, 0);
#undef NEW_AUX_ENT #undef NEW_AUX_ENT
sp -= envc+1; sp = STACK_ADD(p, ei_index);
envp = (elf_caddr_t *) sp;
sp -= argc+1; items = (argc + 1) + (envc + 1);
argv = (elf_caddr_t *) sp; if (interp_aout) {
if (!ibcs) { items += 3; /* a.out interpreters require argv & envp too */
__put_user((elf_addr_t)(unsigned long) envp,--sp); } else {
__put_user((elf_addr_t)(unsigned long) argv,--sp); items += 1; /* ELF interpreters only put argc on the stack */
} }
bprm->p = STACK_ROUND(sp, items);
/* Point sp at the lowest address on the stack */
#ifdef ARCH_STACK_GROWSUP
sp = (elf_addr_t *)bprm->p - items - ei_index;
bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */
#else
sp = (elf_addr_t *)bprm->p;
#endif
__put_user((elf_addr_t)argc,--sp); /* Now, let's put argc (and argv, envp if appropriate) on the stack */
current->mm->arg_start = (unsigned long) p; __put_user(argc, sp++);
while (argc-->0) { if (interp_aout) {
__put_user((elf_caddr_t)(unsigned long)p,argv++); argv = sp + 2;
len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); envp = argv + argc + 1;
__put_user((elf_addr_t)argv, sp++);
__put_user((elf_addr_t)envp, sp++);
} else {
argv = sp;
envp = argv + argc + 1;
}
/* Populate argv and envp */
p = current->mm->arg_start;
while (argc-- > 0) {
size_t len;
__put_user((elf_addr_t)p, argv++);
len = strnlen_user((void *)p, PAGE_SIZE*MAX_ARG_PAGES);
if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
return NULL; return;
p += len; p += len;
} }
__put_user(NULL, argv); __put_user(NULL, argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p; current->mm->arg_end = current->mm->env_start = p;
while (envc-->0) { while (envc-- > 0) {
__put_user((elf_caddr_t)(unsigned long)p,envp++); size_t len;
len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); __put_user((elf_addr_t)p, envp++);
len = strnlen_user((void *)p, PAGE_SIZE*MAX_ARG_PAGES);
if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
return NULL; return;
p += len; p += len;
} }
__put_user(NULL, envp); __put_user(NULL, envp);
current->mm->env_end = (unsigned long) p; current->mm->env_end = p;
return sp;
/* Put the elf_info on the stack in the right place. */
sp = (elf_addr_t *)envp + 1;
copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t));
} }
#ifndef elf_map #ifndef elf_map
...@@ -438,7 +449,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -438,7 +449,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned char ibcs2_interpreter = 0; unsigned char ibcs2_interpreter = 0;
unsigned long error; unsigned long error;
struct elf_phdr * elf_ppnt, *elf_phdata; struct elf_phdr * elf_ppnt, *elf_phdata;
unsigned long elf_bss, k, elf_brk; unsigned long elf_bss, elf_brk;
int elf_exec_fileno; int elf_exec_fileno;
int retval, i; int retval, i;
unsigned int size; unsigned int size;
...@@ -576,19 +587,15 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -576,19 +587,15 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* OK, we are done with that, now set up the arg stuff, /* OK, we are done with that, now set up the arg stuff,
and then start this sucker up */ and then start this sucker up */
if (!bprm->sh_bang) { if ((!bprm->sh_bang) && (interpreter_type == INTERPRETER_AOUT)) {
char * passed_p; char *passed_p = passed_fileno;
sprintf(passed_fileno, "%d", elf_exec_fileno);
if (interpreter_type == INTERPRETER_AOUT) { if (elf_interpreter) {
sprintf(passed_fileno, "%d", elf_exec_fileno); retval = copy_strings_kernel(1, &passed_p, bprm);
passed_p = passed_fileno;
if (elf_interpreter) {
retval = copy_strings_kernel(1,&passed_p,bprm);
if (retval) if (retval)
goto out_free_dentry; goto out_free_dentry;
bprm->argc++; bprm->argc++;
}
} }
} }
...@@ -603,7 +610,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -603,7 +610,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->end_code = 0; current->mm->end_code = 0;
current->mm->mmap = NULL; current->mm->mmap = NULL;
current->flags &= ~PF_FORKNOEXEC; current->flags &= ~PF_FORKNOEXEC;
elf_entry = (unsigned long) elf_ex.e_entry;
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */
SET_PERSONALITY(elf_ex, ibcs2_interpreter);
/* Do this so that we can load the interpreter, if need be. We will /* Do this so that we can load the interpreter, if need be. We will
change some of these later */ change some of these later */
...@@ -623,7 +633,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -623,7 +633,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags; int elf_prot = 0, elf_flags;
unsigned long vaddr; unsigned long k, vaddr;
if (elf_ppnt->p_type != PT_LOAD) if (elf_ppnt->p_type != PT_LOAD)
continue; continue;
...@@ -656,7 +666,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -656,7 +666,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
} else if (elf_ex.e_type == ET_DYN) { } else if (elf_ex.e_type == ET_DYN) {
/* Try and get dynamic programs out of the way of the default mmap /* Try and get dynamic programs out of the way of the default mmap
base, as well as whatever program they might try to exec. This base, as well as whatever program they might try to exec. This
is because the brk will follow the loader, and is not movable. */ is because the brk will follow the loader, and is not movable. */
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
} }
...@@ -681,7 +691,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -681,7 +691,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (k > elf_bss) if (k > elf_bss)
elf_bss = k; elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < k) if ((elf_ppnt->p_flags & PF_X) && end_code < k)
end_code = k; end_code = k;
if (end_data < k) if (end_data < k)
end_data = k; end_data = k;
...@@ -690,7 +700,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -690,7 +700,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_brk = k; elf_brk = k;
} }
elf_entry += load_bias; elf_ex.e_entry += load_bias;
elf_bss += load_bias; elf_bss += load_bias;
elf_brk += load_bias; elf_brk += load_bias;
start_code += load_bias; start_code += load_bias;
...@@ -717,6 +727,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -717,6 +727,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
send_sig(SIGSEGV, current, 0); send_sig(SIGSEGV, current, 0);
return 0; return 0;
} }
} else {
elf_entry = elf_ex.e_entry;
} }
kfree(elf_phdata); kfree(elf_phdata);
...@@ -728,18 +740,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -728,18 +740,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
compute_creds(bprm); compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC; current->flags &= ~PF_FORKNOEXEC;
bprm->p = (unsigned long) create_elf_tables(bprm, &elf_ex, (interpreter_type == INTERPRETER_AOUT),
create_elf_tables((char *)bprm->p, load_addr, interp_load_addr);
bprm->argc,
bprm->envc,
&elf_ex,
load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
/* N.B. passed_fileno might not be initialized? */ /* N.B. passed_fileno might not be initialized? */
if (interpreter_type == INTERPRETER_AOUT) if (interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1; current->mm->arg_start += strlen(passed_fileno) + 1;
current->mm->start_brk = current->mm->brk = elf_brk;
current->mm->end_code = end_code; current->mm->end_code = end_code;
current->mm->start_code = start_code; current->mm->start_code = start_code;
current->mm->start_data = start_data; current->mm->start_data = start_data;
......
...@@ -323,9 +323,50 @@ int setup_arg_pages(struct linux_binprm *bprm) ...@@ -323,9 +323,50 @@ int setup_arg_pages(struct linux_binprm *bprm)
{ {
unsigned long stack_base; unsigned long stack_base;
struct vm_area_struct *mpnt; struct vm_area_struct *mpnt;
struct mm_struct *mm = current->mm;
int i; int i;
stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; #ifdef ARCH_STACK_GROWSUP
/* Move the argument and environment strings to the bottom of the
* stack space.
*/
int offset, j;
char *to, *from;
/* Start by shifting all the pages down */
i = 0;
for (j = 0; j < MAX_ARG_PAGES; j++) {
struct page *page = bprm->page[j];
if (!page)
continue;
bprm->page[i++] = page;
}
/* Now move them within their pages */
offset = bprm->p % PAGE_SIZE;
to = kmap(bprm->page[0]);
for (j = 1; j < i; j++) {
memmove(to, to + offset, PAGE_SIZE - offset);
from = kmap(bprm->page[j]);
memcpy(to + PAGE_SIZE - offset, from, offset);
kunmap(bprm[j - 1]);
to = from;
}
memmove(to, to + offset, PAGE_SIZE - offset);
kunmap(bprm[j - 1]);
/* Adjust bprm->p to point to the end of the strings. */
bprm->p = PAGE_SIZE * i - offset;
stack_base = STACK_TOP - current->rlim[RLIMIT_STACK].rlim_max;
mm->arg_start = stack_base;
/* zero pages that were copied above */
while (i < MAX_ARG_PAGES)
bprm->page[i++] = NULL;
#else
stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE;
mm->arg_start = bprm->p + stack_base;
#endif
bprm->p += stack_base; bprm->p += stack_base;
if (bprm->loader) if (bprm->loader)
...@@ -333,7 +374,7 @@ int setup_arg_pages(struct linux_binprm *bprm) ...@@ -333,7 +374,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
bprm->exec += stack_base; bprm->exec += stack_base;
mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
if (!mpnt) if (!mpnt)
return -ENOMEM; return -ENOMEM;
if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) {
...@@ -341,19 +382,25 @@ int setup_arg_pages(struct linux_binprm *bprm) ...@@ -341,19 +382,25 @@ int setup_arg_pages(struct linux_binprm *bprm)
return -ENOMEM; return -ENOMEM;
} }
down_write(&current->mm->mmap_sem); down_write(&mm->mmap_sem);
{ {
mpnt->vm_mm = current->mm; mpnt->vm_mm = mm;
#ifdef ARCH_STACK_GROWSUP
mpnt->vm_start = stack_base;
mpnt->vm_end = PAGE_MASK &
(PAGE_SIZE - 1 + (unsigned long) bprm->p);
#else
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
mpnt->vm_end = STACK_TOP; mpnt->vm_end = STACK_TOP;
#endif
mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_ops = NULL; mpnt->vm_ops = NULL;
mpnt->vm_pgoff = 0; mpnt->vm_pgoff = 0;
mpnt->vm_file = NULL; mpnt->vm_file = NULL;
mpnt->vm_private_data = (void *) 0; mpnt->vm_private_data = (void *) 0;
insert_vm_struct(current->mm, mpnt); insert_vm_struct(mm, mpnt);
current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
} }
for (i = 0 ; i < MAX_ARG_PAGES ; i++) { for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
...@@ -364,7 +411,7 @@ int setup_arg_pages(struct linux_binprm *bprm) ...@@ -364,7 +411,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
} }
stack_base += PAGE_SIZE; stack_base += PAGE_SIZE;
} }
up_write(&current->mm->mmap_sem); up_write(&mm->mmap_sem);
return 0; return 0;
} }
...@@ -732,7 +779,6 @@ void compute_creds(struct linux_binprm *bprm) ...@@ -732,7 +779,6 @@ void compute_creds(struct linux_binprm *bprm)
security_ops->bprm_compute_creds(bprm); security_ops->bprm_compute_creds(bprm);
} }
void remove_arg_zero(struct linux_binprm *bprm) void remove_arg_zero(struct linux_binprm *bprm)
{ {
if (bprm->argc) { if (bprm->argc) {
...@@ -854,7 +900,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) ...@@ -854,7 +900,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
return retval; return retval;
} }
/* /*
* sys_execve() executes a new program. * sys_execve() executes a new program.
*/ */
......
...@@ -334,7 +334,6 @@ void ia64_elf32_init(struct pt_regs *regs); ...@@ -334,7 +334,6 @@ void ia64_elf32_init(struct pt_regs *regs);
#define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) #define ELF_PLAT_INIT(_r) ia64_elf32_init(_r)
#define elf_addr_t u32 #define elf_addr_t u32
#define elf_caddr_t u32
/* ELF register definitions. This is needed for core dump support. */ /* ELF register definitions. This is needed for core dump support. */
......
...@@ -31,7 +31,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; ...@@ -31,7 +31,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
\ \
if (__h->e_machine != EM_MIPS) \ if (__h->e_machine != EM_MIPS) \
__res = 0; \ __res = 0; \
if (sizeof(elf_caddr_t) == 8 && \ if (sizeof(elf_addr_t) == 8 && \
__h->e_ident[EI_CLASS] == ELFCLASS32) \ __h->e_ident[EI_CLASS] == ELFCLASS32) \
__res = 0; \ __res = 0; \
\ \
......
...@@ -98,19 +98,14 @@ extern int ucache_bsize; ...@@ -98,19 +98,14 @@ extern int ucache_bsize;
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined. * even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
*/ */
#define DLINFO_ARCH_ITEMS 3
#define ARCH_DLINFO \ #define ARCH_DLINFO \
do { \ do { \
sp -= DLINFO_ARCH_ITEMS * 2; \ NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \
NEW_AUX_ENT(0, AT_DCACHEBSIZE, dcache_bsize); \ NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \
NEW_AUX_ENT(1, AT_ICACHEBSIZE, icache_bsize); \ NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \
NEW_AUX_ENT(2, AT_UCACHEBSIZE, ucache_bsize); \ /* Now handle glibc compatibility. */ \
/* \ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
* Now handle glibc compatibility. \ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
*/ \
sp -= 2*2; \
NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \
NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \
} while (0) } while (0)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -31,13 +31,11 @@ typedef elf_greg_t32 elf_gregset_t32[ELF_NGREG]; ...@@ -31,13 +31,11 @@ typedef elf_greg_t32 elf_gregset_t32[ELF_NGREG];
typedef elf_greg_t64 elf_greg_t; typedef elf_greg_t64 elf_greg_t;
typedef elf_gregset_t64 elf_gregset_t; typedef elf_gregset_t64 elf_gregset_t;
# define elf_addr_t unsigned long # define elf_addr_t unsigned long
# define elf_caddr_t char *
#else #else
/* Assumption: ELF_ARCH == EM_PPC and ELF_CLASS == ELFCLASS32 */ /* Assumption: ELF_ARCH == EM_PPC and ELF_CLASS == ELFCLASS32 */
typedef elf_greg_t32 elf_greg_t; typedef elf_greg_t32 elf_greg_t;
typedef elf_gregset_t32 elf_gregset_t; typedef elf_gregset_t32 elf_gregset_t;
# define elf_addr_t u32 # define elf_addr_t u32
# define elf_caddr_t u32
#endif #endif
typedef double elf_fpreg_t; typedef double elf_fpreg_t;
...@@ -122,19 +120,14 @@ extern int ucache_bsize; ...@@ -122,19 +120,14 @@ extern int ucache_bsize;
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined. * even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
*/ */
#define DLINFO_ARCH_ITEMS 3
#define ARCH_DLINFO \ #define ARCH_DLINFO \
do { \ do { \
sp -= DLINFO_ARCH_ITEMS * 2; \ NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \
NEW_AUX_ENT(0, AT_DCACHEBSIZE, dcache_bsize); \ NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \
NEW_AUX_ENT(1, AT_ICACHEBSIZE, icache_bsize); \ NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \
NEW_AUX_ENT(2, AT_UCACHEBSIZE, ucache_bsize); \ /* Now handle glibc compatibility. */ \
/* \ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
* Now handle glibc compatibility. \ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
*/ \
sp -= 2*2; \
NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \
NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \
} while (0) } while (0)
#endif /* __PPC64_ELF_H */ #endif /* __PPC64_ELF_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment