In PCuABI, the initial pointers (program counter, stack pointer, argv/envp/auxv) are written to registers in the arch-specific START_THREAD(). argv/envp are also stored in the auxiliary vector itself.
We are about to narrow down the bounds and permissions of those pointers, so to avoid duplicating capability operations, make the pointers directly available to START_THREAD() by storing them in the bprm struct.
Signed-off-by: Kevin Brodsky kevin.brodsky@arm.com --- fs/binfmt_elf.c | 36 ++++++++++++++++++++++++++++++------ include/linux/binfmts.h | 13 +++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index f1d9b57d35af..62c79b87729a 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -167,6 +167,27 @@ struct elf_load_info { unsigned long entry; };
+#if defined(CONFIG_CHERI_PURECAP_UABI) && (ELF_COMPAT == 0) +static void set_bprm_stack_caps(struct linux_binprm *bprm, void __user *sp) +{ + void __user *p; + size_t len; + + bprm->pcuabi.csp = sp; + + p = sp + sizeof(elf_stack_item_t); + len = (bprm->argc + 1) * sizeof(elf_stack_item_t); + bprm->pcuabi.argv = p; + + p += len; + len = (bprm->envc + 1) * sizeof(elf_stack_item_t); + bprm->pcuabi.envp = p; + + p += len; + bprm->pcuabi.auxv = p; +} +#endif /* CONFIG_CHERI_PURECAP_UABI && ELF_COMPAT == 0 */ + static int create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, unsigned long interp_load_addr, @@ -303,6 +324,9 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, /* * TODO [PCuABI] - Restrict bounds/perms for AT_CHERI_* entries */ + bprm->pcuabi.pcc = elf_uaddr_to_user_ptr(interp_load_addr ? + interp_load_info->entry : + exec_load_info->entry); NEW_AUX_ENT(AT_CHERI_EXEC_RW_CAP, (exec_load_info->start_elf_rw != ~0UL ? elf_uaddr_to_user_ptr(exec_load_info->start_elf_rw) : @@ -349,6 +373,12 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, sp = STACK_ROUND(sp, items); bprm->p = user_ptr_addr(sp);
+#if defined(CONFIG_CHERI_PURECAP_UABI) && (ELF_COMPAT == 0) + set_bprm_stack_caps(bprm, sp); + *mm_at_argv = (elf_stack_item_t)bprm->pcuabi.argv; + *mm_at_envp = (elf_stack_item_t)bprm->pcuabi.envp; +#endif + /* Point sp at the lowest address on the stack */ #ifdef CONFIG_STACK_GROWSUP sp -= (items + ei_index) * sizeof(elf_stack_item_t); @@ -374,9 +404,6 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, return -EFAULT;
/* Populate list of argv pointers back to argv strings. */ -#if defined(CONFIG_CHERI_PURECAP_UABI) && (ELF_COMPAT == 0) - *mm_at_argv = (elf_stack_item_t)stack_item; -#endif /* In PCuABI, this derives a capability from SP pointing to arg_start */ ustr = sp + (mm->arg_start - user_ptr_addr(sp)); while (argc-- > 0) { @@ -393,9 +420,6 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, mm->arg_end = user_ptr_addr(ustr);
/* Populate list of envp pointers back to envp strings. */ -#if defined(CONFIG_CHERI_PURECAP_UABI) && (ELF_COMPAT == 0) - *mm_at_envp = (elf_stack_item_t)stack_item; -#endif mm->env_start = user_ptr_addr(ustr); while (envc-- > 0) { size_t len; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 16d03f38f92e..e0e26c9a0ff9 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -12,6 +12,15 @@ struct coredump_params;
#define CORENAME_MAX_SIZE 128
+struct pcuabi_binprm { + void __user *pcc; + void __user *csp; + /* Capabilities to the initial arrays in the new process's address space */ + void __user *argv; + void __user *envp; + void __user *auxv; +}; + /* * This structure is used to hold the arguments that are used when loading binaries. */ @@ -62,6 +71,10 @@ struct linux_binprm { struct rlimit rlim_stack; /* Saved RLIMIT_STACK used during exec. */
char buf[BINPRM_BUF_SIZE]; + +#ifdef CONFIG_CHERI_PURECAP_UABI + struct pcuabi_binprm pcuabi; +#endif } __randomize_layout;
#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0