mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 __user *u_platform, *u_base_platform, *p;
 | 
			
		||||
	int loop;
 | 
			
		||||
	int nr;	/* reset for each csp adjustment */
 | 
			
		||||
	unsigned long flags = 0;
 | 
			
		||||
	int ei_index;
 | 
			
		||||
	elf_addr_t *elf_info;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MMU
 | 
			
		||||
	/* 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;
 | 
			
		||||
	sp -= sp & 15UL;
 | 
			
		||||
 | 
			
		||||
	/* put the ELF interpreter info on the stack */
 | 
			
		||||
#define NEW_AUX_ENT(id, val)						\
 | 
			
		||||
	do {								\
 | 
			
		||||
		struct { unsigned long _id, _val; } __user *ent, v;	\
 | 
			
		||||
									\
 | 
			
		||||
		ent = (void __user *) csp;				\
 | 
			
		||||
		v._id = (id);						\
 | 
			
		||||
		v._val = (val);						\
 | 
			
		||||
		if (copy_to_user(ent + nr, &v, sizeof(v)))		\
 | 
			
		||||
			return -EFAULT;					\
 | 
			
		||||
		nr++;							\
 | 
			
		||||
	/* Create the ELF interpreter info */
 | 
			
		||||
	elf_info = (elf_addr_t *)mm->saved_auxv;
 | 
			
		||||
	/* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */
 | 
			
		||||
#define NEW_AUX_ENT(id, val) \
 | 
			
		||||
	do { \
 | 
			
		||||
		*elf_info++ = id; \
 | 
			
		||||
		*elf_info++ = val; \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
	nr = 0;
 | 
			
		||||
	csp -= 2 * sizeof(unsigned long);
 | 
			
		||||
	NEW_AUX_ENT(AT_NULL, 0);
 | 
			
		||||
	if (k_platform) {
 | 
			
		||||
		nr = 0;
 | 
			
		||||
		csp -= 2 * sizeof(unsigned long);
 | 
			
		||||
		NEW_AUX_ENT(AT_PLATFORM,
 | 
			
		||||
			    (elf_addr_t) (unsigned long) u_platform);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
#ifdef ARCH_DLINFO
 | 
			
		||||
	/*
 | 
			
		||||
	 * ARCH_DLINFO must come first so PPC can do its special alignment of
 | 
			
		||||
	 * AUXV.
 | 
			
		||||
	 * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in
 | 
			
		||||
	 * ARCH_DLINFO changes
 | 
			
		||||
	 */
 | 
			
		||||
	ARCH_DLINFO;
 | 
			
		||||
#endif
 | 
			
		||||
	NEW_AUX_ENT(AT_HWCAP,	ELF_HWCAP);
 | 
			
		||||
#ifdef 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_SECURE,	bprm->secureexec);
 | 
			
		||||
	NEW_AUX_ENT(AT_EXECFN,	bprm->exec);
 | 
			
		||||
 | 
			
		||||
#ifdef ARCH_DLINFO
 | 
			
		||||
	nr = 0;
 | 
			
		||||
	csp -= AT_VECTOR_SIZE_ARCH * 2 * sizeof(unsigned long);
 | 
			
		||||
 | 
			
		||||
	/* ARCH_DLINFO must come last so platform specific code can enforce
 | 
			
		||||
	 * special alignment requirements on the AUXV if necessary (eg. PPC).
 | 
			
		||||
	 */
 | 
			
		||||
	ARCH_DLINFO;
 | 
			
		||||
#endif
 | 
			
		||||
	if (k_platform)
 | 
			
		||||
		NEW_AUX_ENT(AT_PLATFORM,
 | 
			
		||||
			    (elf_addr_t)(unsigned long)u_platform);
 | 
			
		||||
	if (k_base_platform)
 | 
			
		||||
		NEW_AUX_ENT(AT_BASE_PLATFORM,
 | 
			
		||||
			    (elf_addr_t)(unsigned long)u_base_platform);
 | 
			
		||||
	if (bprm->have_execfd)
 | 
			
		||||
		NEW_AUX_ENT(AT_EXECFD, bprm->execfd);
 | 
			
		||||
#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[] */
 | 
			
		||||
	csp -= (bprm->envc + 1) * sizeof(elf_caddr_t);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue