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 *);
......
This diff is collapsed.
...@@ -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)
...@@ -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