static elf_addr_t * create_elf_tables(char *p, int argc, int envc, struct elfhdr * exec, unsigned long load_addr, unsigned long load_bias, unsigned long interp_load_addr, int ibcs) { elf_caddr_t *argv; elf_caddr_t *envp; elf_addr_t *sp, *csp; char *k_platform, *u_platform; long hwcap; size_t platform_len = 0; size_t len; /* * Get hold of platform and hardware capabilities masks for * the machine we are running on. In some cases (Sparc), * this info is impossible to get, in others (i386) it is * merely difficult. */ hwcap = ELF_HWCAP; k_platform = ELF_PLATFORM; if (k_platform) { platform_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) /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions * by the processes running on the same package. One thing we can do * is to shuffle the initial stack for them. * * The conditionals here are unneeded, but kept in to make the * code behaviour the same as pre change unless we have hyperthreaded * processors. This keeps Mr Marcelo Person happier but should be * removed for 2.5 */ if(smp_num_siblings > 1) u_platform = u_platform - ((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 csp -= envc+1; csp -= argc+1; csp -= (!ibcs ? 3 : 1); /* argc itself */ if ((unsigned long)csp & 15UL) sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); /* * Put the ELF interpreter info on the stack */ #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 /* * ARCH_DLINFO must come last so platform specific code can enforce * special alignment requirements on the AUXV if necessary (eg. PPC). */ ARCH_DLINFO; #endif #undef NEW_AUX_ENT sp -= envc+1; envp = (elf_caddr_t *) sp; sp -= argc+1; argv = (elf_caddr_t *) sp; if (!ibcs) { __put_user((elf_addr_t)(unsigned long) envp,--sp); __put_user((elf_addr_t)(unsigned long) argv,--sp); } __put_user((elf_addr_t)argc,--sp); current->mm->arg_start = current->mm->arg_end = (unsigned long) p; while (argc-->0) { __put_user((elf_caddr_t)(unsigned long)p,argv++); len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) return NULL; p += len; } __put_user(NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { __put_user((elf_caddr_t)(unsigned long)p,envp++); len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) return NULL; p += len; } __put_user(NULL, envp); current->mm->env_end = (unsigned long) p; return sp; }
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, struct elfhdr * exec, abi_ulong load_addr, abi_ulong load_bias, abi_ulong interp_load_addr, int ibcs, struct image_info *info) { abi_ulong sp; int size; abi_ulong u_platform; const char *k_platform; const int n = sizeof(elf_addr_t); sp = p; u_platform = 0; k_platform = ELF_PLATFORM; if (k_platform) { size_t len = strlen(k_platform) + 1; sp -= (len + n - 1) & ~(n - 1); u_platform = sp; /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(sp, k_platform, len); } /* * Force 16 byte _final_ alignment here for generality. */ sp = sp &~ (abi_ulong)15; size = (DLINFO_ITEMS + 1) * 2; if (k_platform) size += 2; #ifdef DLINFO_ARCH_ITEMS size += DLINFO_ARCH_ITEMS * 2; #endif size += envc + argc + 2; size += (!ibcs ? 3 : 1); /* argc itself */ size *= n; if (size & 15) sp -= 16 - (size & 15); /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off */ #define NEW_AUX_ENT(id, val) do { \ sp -= n; put_user_ual(val, sp); \ sp -= n; put_user_ual(id, sp); \ } while(0) NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO /* * ARCH_DLINFO must come last so platform specific code can enforce * special alignment requirements on the AUXV if necessary (eg. PPC). */ ARCH_DLINFO; #endif #undef NEW_AUX_ENT sp = loader_build_argptr(envc, argc, sp, p, !ibcs); return sp; }
static unsigned long * create_irix_tables(char * p, int argc, int envc, struct elfhdr * exec, unsigned int load_addr, unsigned int interp_load_addr, struct pt_regs *regs, struct elf_phdr *ephdr) { elf_addr_t *argv; elf_addr_t *envp; elf_addr_t *sp, *csp; pr_debug("create_irix_tables: p[%p] argc[%d] envc[%d] " "load_addr[%08x] interp_load_addr[%08x]\n", p, argc, envc, load_addr, interp_load_addr); sp = (elf_addr_t *) (~15UL & (unsigned long) p); csp = sp; csp -= exec ? DLINFO_ITEMS*2 : 2; csp -= envc+1; csp -= argc+1; csp -= 1; /* argc itself */ if ((unsigned long)csp & 15UL) { sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp); } /* * Put the ELF interpreter info on the stack */ #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 (exec) { sp -= 11*2; NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT(1, AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(4, AT_BASE, interp_load_addr); NEW_AUX_ENT(5, AT_FLAGS, 0); NEW_AUX_ENT(6, AT_ENTRY, (elf_addr_t) exec->e_entry); NEW_AUX_ENT(7, AT_UID, (elf_addr_t) current->uid); NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) current->euid); NEW_AUX_ENT(9, AT_GID, (elf_addr_t) current->gid); NEW_AUX_ENT(10, AT_EGID, (elf_addr_t) current->egid); } #undef NEW_AUX_ENT sp -= envc+1; envp = sp; sp -= argc+1; argv = sp; __put_user((elf_addr_t)argc, --sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { __put_user((unsigned long)p, argv++); p += strlen_user(p); } __put_user((unsigned long) NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { __put_user((unsigned long)p, envp++); p += strlen_user(p); } __put_user((unsigned long) NULL, envp); current->mm->env_end = (unsigned long) p; return sp; }
static elf_addr_t * create_elf_tables(char *p, int argc, int envc, struct elfhdr * exec, unsigned long load_addr, unsigned long load_bias, unsigned long interp_load_addr, int ibcs) { elf_caddr_t *argv; elf_caddr_t *envp; elf_addr_t *sp, *csp; char *k_platform, *u_platform; long hwcap; size_t platform_len = 0; /* * Get hold of platform and hardware capabilities masks for * the machine we are running on. In some cases (Sparc), * this info is impossible to get, in others (i386) it is * merely difficult. */ hwcap = ELF_HWCAP; k_platform = ELF_PLATFORM; if (k_platform) { platform_len = strlen(k_platform) + 1; u_platform = p - platform_len; memcpy(u_platform, k_platform, platform_len); } else u_platform = p; /* * Force 16 byte _final_ alignment here for generality. * Leave an extra 16 bytes free so that on the PowerPC we * can move the aux table up to start on a 16-byte boundary. */ sp = (elf_addr_t *)((~15UL & (unsigned long)(u_platform)) - 16UL); csp = sp; csp -= ((exec ? DLINFO_ITEMS*2 : 4) + (k_platform ? 2 : 0)); csp -= envc+1; csp -= argc+1; csp -= (!ibcs ? 3 : 1); /* argc itself */ if ((unsigned long)csp & 15UL) sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); /* * Put the ELF interpreter info on the stack */ #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 -= 2; NEW_AUX_ENT(0, AT_HWCAP, hwcap); if (exec) { sp -= 11*2; NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT(1, AT_PHENT, sizeof (struct elf_phdr)); NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(4, AT_BASE, interp_load_addr); NEW_AUX_ENT(5, AT_FLAGS, 0); NEW_AUX_ENT(6, AT_ENTRY, load_bias + exec->e_entry); NEW_AUX_ENT(7, AT_UID, (elf_addr_t) getuid()); NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) geteuid()); NEW_AUX_ENT(9, AT_GID, (elf_addr_t) getgid()); NEW_AUX_ENT(10, AT_EGID, (elf_addr_t) getegid()); } #undef NEW_AUX_ENT sp -= envc+1; envp = (elf_caddr_t *) sp; sp -= argc+1; argv = (elf_caddr_t *) sp; if (!ibcs) { __put_user((elf_addr_t)(unsigned long) envp,--sp); __put_user((elf_addr_t)(unsigned long) argv,--sp); } __put_user((elf_addr_t)argc,--sp); current->arg_start = (unsigned long) p; while (argc-->0) { __put_user((elf_caddr_t)(unsigned long)p,argv++); p += strlen(p)+1; } __put_user(NULL, argv); current->arg_end = current->env_start = (unsigned long) p; while (envc-->0) { __put_user((elf_caddr_t)(unsigned long)p,envp++); p += strlen(p)+1; } __put_user(NULL, envp); current->env_end = (unsigned long) p; return sp; }
/* * create_elf_tables */ static int create_elf_tables_aux(struct linux_binprm *bprm, unsigned long ntdll_load_addr, elf_off_t ntdll_phoff, elf_half_t ntdll_phnum, unsigned long ntdll_start_thunk, unsigned long exeso_load_addr, elf_off_t exeso_phoff, elf_half_t exeso_phnum, unsigned long exeso_start_thunk, unsigned long interp_load_addr, unsigned long interp_entry, unsigned long init_entry) { unsigned long p = bprm->p; int argc = bprm->argc; int envc = bprm->envc; elf_addr_t __user *argv; elf_addr_t __user *envp; elf_addr_t __user *sp; elf_addr_t __user *u_platform; const char *k_platform = ELF_PLATFORM; int items; elf_addr_t *elf_info; elf_addr_t *elf_info2; int ei_index = 0; const struct cred *cred = current_cred(); /* * If this architecture has a platform capability string, copy it * to userspace. In some cases (Sparc), this info is impossible * for userspace to get any other way, in others (i386) it is * merely difficult. */ u_platform = NULL; if (k_platform) { size_t len = strlen(k_platform) + 1; /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 * evictions by the processes running on the same package. One * thing we can do is to shuffle the initial stack for them. */ p = arch_align_stack(p); u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); if (__copy_to_user(u_platform, k_platform, len)) return -EFAULT; } /* Create the ELF interpreter info */ elf_info = (elf_addr_t *) current->mm->saved_auxv; #define NEW_AUX_ENT(id, val) \ do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0) #ifdef ARCH_DLINFO11 /* * ARCH_DLINFO must come first so PPC can do its special alignment of * AUXV. */ ARCH_DLINFO; #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, ntdll_load_addr + ntdll_phoff); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, ntdll_phnum); NEW_AUX_ENT(AT_BASE, interp_load_addr); NEW_AUX_ENT(AT_FLAGS, 0); NEW_AUX_ENT(AT_ENTRY, ntdll_start_thunk); NEW_AUX_ENT(AT_UID, cred->uid); NEW_AUX_ENT(AT_EUID, cred->euid); NEW_AUX_ENT(AT_GID, cred->gid); NEW_AUX_ENT(AT_EGID, cred->egid); NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm)); #if 0 if (k_platform) { /* FIXME */ NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform); } #endif if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data); } #undef NEW_AUX_ENT /* AT_NULL is zero; clear the rest too */ memset(&elf_info[ei_index], 0, sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); /* And advance past the AT_NULL entry. */ ei_index += 2; sp = STACK_ADD(p, ei_index * 2); items = (argc + 1) + (envc + 1); items += 1; /* ELF interpreters only put argc on the stack */ items += 3; /* interp entry address & _init address & load_base */ bprm->p = STACK_ROUND(sp, items); /* Point sp at the lowest address on the stack */ #ifdef CONFIG_STACK_GROWSUP sp = (elf_addr_t __user *)bprm->p - items - ei_index; bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */ #else sp = (elf_addr_t __user *)bprm->p; #endif /* Now, let's put argc (and argv, envp if appropriate) on the stack */ if (__put_user(argc, sp)) return -EFAULT; ++sp; argv = sp; envp = argv + argc + 1; /* Populate argv and envp */ p = current->mm->arg_end = current->mm->arg_start; while (argc-- > 0) { size_t len; __put_user((elf_addr_t)p, argv); ++argv; len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) return 0; p += len; } if (__put_user(0, argv)) return -EFAULT; current->mm->arg_end = current->mm->env_start = p; while (envc-- > 0) { size_t len; __put_user((elf_addr_t)p, envp); ++envp; len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); if (!len || len > MAX_ARG_STRLEN) return 0; p += len; } if (__put_user(0, envp)) return -EFAULT; current->mm->env_end = p; /* Put the elf_info on the stack in the right place. */ sp = (elf_addr_t __user *)envp + 1; if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) return -EFAULT; sp += ei_index; elf_info2 = (elf_addr_t *)kmalloc(sizeof(current->mm->saved_auxv), GFP_KERNEL); if(!elf_info2) return -ENOMEM; ei_index = 0; #define NEW_AUX_ENT(id, val) \ do { elf_info2[ei_index++] = id; elf_info2[ei_index++] = val; } while (0) #ifdef ARCH_DLINFO11 /* * ARCH_DLINFO must come first so PPC can do its special alignment of * AUXV. */ ARCH_DLINFO; #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, exeso_load_addr + exeso_phoff); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, exeso_phnum); NEW_AUX_ENT(AT_BASE, interp_load_addr); NEW_AUX_ENT(AT_FLAGS, 0); NEW_AUX_ENT(AT_ENTRY, exeso_start_thunk); NEW_AUX_ENT(AT_UID, cred->uid); NEW_AUX_ENT(AT_EUID, cred->euid); NEW_AUX_ENT(AT_GID, cred->gid); NEW_AUX_ENT(AT_EGID, cred->egid); NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm)); #if 0 if (k_platform) { /* FIXME */ NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform); } #endif if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data); } #undef NEW_AUX_ENT /* AT_NULL is zero; clear the rest too */ memset(&elf_info2[ei_index], 0, sizeof(current->mm->saved_auxv) - ei_index * sizeof elf_info2[0]); ei_index += 2; if (copy_to_user(sp, elf_info2, ei_index * sizeof(elf_addr_t))) { kfree(elf_info2); return -EFAULT; } kfree(elf_info2); sp += ei_index; __put_user(interp_entry, sp); ++sp; __put_user(init_entry, sp); ++sp; __put_user(exeso_load_addr, sp); memset(current->mm->saved_auxv, 0, sizeof(current->mm->saved_auxv)); return 0; } /* end create_elf_tables */
/* * present useful information to the program */ static int create_elf_fdpic_tables(struct linux_binprm *bprm, struct mm_struct *mm, struct elf_fdpic_params *exec_params, struct elf_fdpic_params *interp_params) { unsigned long sp, csp, nitems; elf_caddr_t *argv, *envp; size_t platform_len = 0, len; char *k_platform, *u_platform, *p; long hwcap; int loop; /* we're going to shovel a whole load of stuff onto the stack */ #ifdef CONFIG_MMU sp = bprm->p; #else sp = mm->start_stack; /* stack the program arguments and environment */ if (elf_fdpic_transfer_args_to_stack(bprm, &sp) < 0) return -EFAULT; #endif /* get hold of platform and hardware capabilities masks for the machine * we are running on. In some cases (Sparc), this info is impossible * to get, in others (i386) it is merely difficult. */ hwcap = ELF_HWCAP; k_platform = ELF_PLATFORM; if (k_platform) { platform_len = strlen(k_platform) + 1; sp -= platform_len; if (__copy_to_user(u_platform, k_platform, platform_len) != 0) return -EFAULT; } u_platform = (char *) sp; #if defined(__i386__) && defined(CONFIG_SMP) /* in some cases (e.g. Hyper-Threading), we want to avoid L1 evictions * by the processes running on the same package. One thing we can do * is to shuffle the initial stack for them. * * the conditionals here are unneeded, but kept in to make the * code behaviour the same as pre change unless we have hyperthreaded * processors. This keeps Mr Marcelo Person happier but should be * removed for 2.5 */ if (smp_num_siblings > 1) sp = sp - ((current->pid % 64) << 7); #endif sp &= ~7UL; /* stack the load map(s) */ len = sizeof(struct elf32_fdpic_loadmap); len += sizeof(struct elf32_fdpic_loadseg) * exec_params->loadmap->nsegs; sp = (sp - len) & ~7UL; exec_params->map_addr = sp; if (copy_to_user((void *) sp, exec_params->loadmap, len) != 0) return -EFAULT; current->mm->context.exec_fdpic_loadmap = (unsigned long) sp; if (interp_params->loadmap) { len = sizeof(struct elf32_fdpic_loadmap); len += sizeof(struct elf32_fdpic_loadseg) * interp_params->loadmap->nsegs; sp = (sp - len) & ~7UL; interp_params->map_addr = sp; if (copy_to_user((void *) sp, interp_params->loadmap, len) != 0) return -EFAULT; current->mm->context.interp_fdpic_loadmap = (unsigned long) sp; } /* force 16 byte _final_ alignment here for generality */ #define DLINFO_ITEMS 13 nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0); #ifdef DLINFO_ARCH_ITEMS nitems += DLINFO_ARCH_ITEMS; #endif csp = sp; sp -= nitems * 2 * sizeof(unsigned long); sp -= (bprm->envc + 1) * sizeof(char *); /* envv[] */ sp -= (bprm->argc + 1) * sizeof(char *); /* argv[] */ sp -= 1 * sizeof(unsigned long); /* argc */ csp -= sp & 15UL; sp -= sp & 15UL; /* put the ELF interpreter info on the stack */ #define NEW_AUX_ENT(nr, id, val) \ do { \ struct { unsigned long _id, _val; } *ent = (void *) csp; \ __put_user((id), &ent[nr]._id); \ __put_user((val), &ent[nr]._val); \ } while (0) csp -= 2 * sizeof(unsigned long); NEW_AUX_ENT(0, AT_NULL, 0); if (k_platform) { csp -= 2 * sizeof(unsigned long); NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform); } csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long); NEW_AUX_ENT( 0, AT_HWCAP, hwcap); NEW_AUX_ENT( 1, AT_PAGESZ, PAGE_SIZE); NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC); NEW_AUX_ENT( 3, AT_PHDR, exec_params->ph_addr); NEW_AUX_ENT( 4, AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT( 5, AT_PHNUM, exec_params->hdr.e_phnum); NEW_AUX_ENT( 6, AT_BASE, interp_params->elfhdr_addr); NEW_AUX_ENT( 7, AT_FLAGS, 0); NEW_AUX_ENT( 8, AT_ENTRY, exec_params->entry_addr); 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 /* ARCH_DLINFO must come last so platform specific code can enforce * special alignment requirements on the AUXV if necessary (eg. PPC). */ ARCH_DLINFO; #endif #undef NEW_AUX_ENT /* allocate room for argv[] and envv[] */ csp -= (bprm->envc + 1) * sizeof(elf_caddr_t); envp = (elf_caddr_t *) csp; csp -= (bprm->argc + 1) * sizeof(elf_caddr_t); argv = (elf_caddr_t *) csp; /* stack argc */ csp -= sizeof(unsigned long); __put_user(bprm->argc, (unsigned long *) csp); if (csp != sp) BUG(); /* fill in the argv[] array */ #ifdef CONFIG_MMU current->mm->arg_start = bprm->p; #else current->mm->arg_start = current->mm->start_stack - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p); #endif p = (char *) current->mm->arg_start; for (loop = bprm->argc; loop > 0; loop--) { __put_user((elf_caddr_t) p, argv++); len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES); if (!len || len > PAGE_SIZE * MAX_ARG_PAGES) return -EINVAL; p += len; } __put_user(NULL, argv); current->mm->arg_end = (unsigned long) p; /* fill in the envv[] array */ current->mm->env_start = (unsigned long) p; for (loop = bprm->envc; loop > 0; loop--) { __put_user((elf_caddr_t)(unsigned long) p, envp++); len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES); if (!len || len > PAGE_SIZE * MAX_ARG_PAGES) return -EINVAL; p += len; } __put_user(NULL, envp); current->mm->env_end = (unsigned long) p; mm->start_stack = (unsigned long) sp; return 0; } /* end create_elf_fdpic_tables() */