binfmt_elf_fdpic: fix /proc/<pid>/auxv
Althought FDPIC linux kernel provides /proc/<pid>/auxv files they are empty because there's no code that initializes mm->saved_auxv in the FDPIC ELF loader. Synchronize FDPIC ELF aux vector setup with ELF. Replace entry-by-entry aux vector copying to userspace with initialization of mm->saved_auxv first and then copying it to userspace as a whole. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Link: https://lore.kernel.org/r/20240322195418.2160164-1-jcmvbkbc@gmail.com Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
2a5eb99955
commit
10e29251be
1 changed files with 40 additions and 47 deletions
|
@ -505,8 +505,9 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
|
||||||
char *k_platform, *k_base_platform;
|
char *k_platform, *k_base_platform;
|
||||||
char __user *u_platform, *u_base_platform, *p;
|
char __user *u_platform, *u_base_platform, *p;
|
||||||
int loop;
|
int loop;
|
||||||
int nr; /* reset for each csp adjustment */
|
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
|
int ei_index;
|
||||||
|
elf_addr_t *elf_info;
|
||||||
|
|
||||||
#ifdef CONFIG_MMU
|
#ifdef CONFIG_MMU
|
||||||
/* 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 evictions
|
||||||
|
@ -601,44 +602,24 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
|
||||||
csp -= sp & 15UL;
|
csp -= sp & 15UL;
|
||||||
sp -= sp & 15UL;
|
sp -= sp & 15UL;
|
||||||
|
|
||||||
/* put the ELF interpreter info on the stack */
|
/* Create the ELF interpreter info */
|
||||||
#define NEW_AUX_ENT(id, val) \
|
elf_info = (elf_addr_t *)mm->saved_auxv;
|
||||||
do { \
|
/* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */
|
||||||
struct { unsigned long _id, _val; } __user *ent, v; \
|
#define NEW_AUX_ENT(id, val) \
|
||||||
\
|
do { \
|
||||||
ent = (void __user *) csp; \
|
*elf_info++ = id; \
|
||||||
v._id = (id); \
|
*elf_info++ = val; \
|
||||||
v._val = (val); \
|
|
||||||
if (copy_to_user(ent + nr, &v, sizeof(v))) \
|
|
||||||
return -EFAULT; \
|
|
||||||
nr++; \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
nr = 0;
|
#ifdef ARCH_DLINFO
|
||||||
csp -= 2 * sizeof(unsigned long);
|
/*
|
||||||
NEW_AUX_ENT(AT_NULL, 0);
|
* ARCH_DLINFO must come first so PPC can do its special alignment of
|
||||||
if (k_platform) {
|
* AUXV.
|
||||||
nr = 0;
|
* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in
|
||||||
csp -= 2 * sizeof(unsigned long);
|
* ARCH_DLINFO changes
|
||||||
NEW_AUX_ENT(AT_PLATFORM,
|
*/
|
||||||
(elf_addr_t) (unsigned long) u_platform);
|
ARCH_DLINFO;
|
||||||
}
|
#endif
|
||||||
|
|
||||||
if (k_base_platform) {
|
|
||||||
nr = 0;
|
|
||||||
csp -= 2 * sizeof(unsigned long);
|
|
||||||
NEW_AUX_ENT(AT_BASE_PLATFORM,
|
|
||||||
(elf_addr_t) (unsigned long) u_base_platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bprm->have_execfd) {
|
|
||||||
nr = 0;
|
|
||||||
csp -= 2 * sizeof(unsigned long);
|
|
||||||
NEW_AUX_ENT(AT_EXECFD, bprm->execfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
nr = 0;
|
|
||||||
csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
|
|
||||||
NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP);
|
NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP);
|
||||||
#ifdef ELF_HWCAP2
|
#ifdef ELF_HWCAP2
|
||||||
NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2);
|
NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2);
|
||||||
|
@ -659,17 +640,29 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
|
||||||
NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid));
|
NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid));
|
||||||
NEW_AUX_ENT(AT_SECURE, bprm->secureexec);
|
NEW_AUX_ENT(AT_SECURE, bprm->secureexec);
|
||||||
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
|
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
|
||||||
|
if (k_platform)
|
||||||
#ifdef ARCH_DLINFO
|
NEW_AUX_ENT(AT_PLATFORM,
|
||||||
nr = 0;
|
(elf_addr_t)(unsigned long)u_platform);
|
||||||
csp -= AT_VECTOR_SIZE_ARCH * 2 * sizeof(unsigned long);
|
if (k_base_platform)
|
||||||
|
NEW_AUX_ENT(AT_BASE_PLATFORM,
|
||||||
/* ARCH_DLINFO must come last so platform specific code can enforce
|
(elf_addr_t)(unsigned long)u_base_platform);
|
||||||
* special alignment requirements on the AUXV if necessary (eg. PPC).
|
if (bprm->have_execfd)
|
||||||
*/
|
NEW_AUX_ENT(AT_EXECFD, bprm->execfd);
|
||||||
ARCH_DLINFO;
|
|
||||||
#endif
|
|
||||||
#undef NEW_AUX_ENT
|
#undef NEW_AUX_ENT
|
||||||
|
/* AT_NULL is zero; clear the rest too */
|
||||||
|
memset(elf_info, 0, (char *)mm->saved_auxv +
|
||||||
|
sizeof(mm->saved_auxv) - (char *)elf_info);
|
||||||
|
|
||||||
|
/* And advance past the AT_NULL entry. */
|
||||||
|
elf_info += 2;
|
||||||
|
|
||||||
|
ei_index = elf_info - (elf_addr_t *)mm->saved_auxv;
|
||||||
|
csp -= ei_index * sizeof(elf_addr_t);
|
||||||
|
|
||||||
|
/* Put the elf_info on the stack in the right place. */
|
||||||
|
if (copy_to_user((void __user *)csp, mm->saved_auxv,
|
||||||
|
ei_index * sizeof(elf_addr_t)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
/* allocate room for argv[] and envv[] */
|
/* allocate room for argv[] and envv[] */
|
||||||
csp -= (bprm->envc + 1) * sizeof(elf_caddr_t);
|
csp -= (bprm->envc + 1) * sizeof(elf_caddr_t);
|
||||||
|
|
Loading…
Add table
Reference in a new issue