On 25/10/2023 17:57, Teo Couprie Diaz wrote:
argv and envp strings can be large enough so that a capability cannot be created to access them exclusively: their bounds would not be exactly representable and go outside of the strings.
During allocation on the stack, align the strings that need an adjusted base and pad if needed for alignment or a representable length. Handle this potential padding in fs/binfmt_elf by detecting unexpected 0s.
This is done irrespective of the calling binary or loaded binary ABIs. Indeed, at the point where strings are put on the stack during `execve` we can only know the ABI of the calling binary, but not that of the loaded binary. Thus the compat path will be slightly slower and the memory used by the strings will be larger, as if to create capabilities with exact bounds. However, this memory impact should stay minimal and in rare cases where argv or envp strings are more than a couple thousand characters.
Add a a helper function to put already created capabilities on the stack during elf setup.
Additionally, align the newly created stack to a multiple of the maximum argument length to make sure the relocated arguments will still be respresentable with their new alignment in a PC-uABI kernel.
Signed-off-by: Teo Couprie Diaz teo.coupriediaz@arm.com
fs/binfmt_elf.c | 101 +++++++++++++++++++++++++++++++++++++++++------- fs/exec.c | 58 +++++++++++++++++++++++++-- 2 files changed, 142 insertions(+), 17 deletions(-)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6455313d7f36..198c1ed442a6 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -213,6 +291,7 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, #if defined(CONFIG_CHERI_PURECAP_UABI) && (ELF_COMPAT == 0) elf_stack_item_t *mm_at_argv, *mm_at_envp; #endif
- long str_ret = 0;
Just noticed that since the while loops have been reintroduced, this variable can be made local to them.
Will take into account if v4 is needed (probably !)
/* * In some cases (e.g. Hyper-Threading), we want to avoid L1 @@ -397,13 +476,10 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, /* In PCuABI, this derives a capability from SP pointing to arg_start */ ustr = sp + (mm->arg_start - user_ptr_addr(sp)); while (argc-- > 0) {
size_t len;
if (elf_stack_put_user(ustr, stack_item++))
return -EFAULT;
len = strnlen_user(ustr, MAX_ARG_STRLEN);
if (!len || len > MAX_ARG_STRLEN)
return -EINVAL;
ustr += len;
str_ret = put_str_ptr(ustr, stack_item++);
if (str_ret < 0)
return str_ret;
} if (elf_stack_put_user(0, stack_item++)) return -EFAULT;ustr += str_ret;
@@ -415,13 +491,10 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, #endif mm->env_start = user_ptr_addr(ustr); while (envc-- > 0) {
size_t len;
if (elf_stack_put_user(ustr, stack_item++))
return -EFAULT;
len = strnlen_user(ustr, MAX_ARG_STRLEN);
if (!len || len > MAX_ARG_STRLEN)
return -EINVAL;
ustr += len;
str_ret = put_str_ptr(ustr, stack_item++);
if (str_ret < 0)
return str_ret;
} if (elf_stack_put_user(0, stack_item++)) return -EFAULT;ustr += str_ret;