18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/exec.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * #!-checking implemented by tytso. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * Demand-loading implemented 01.12.91 - no need to read anything but 138c2ecf20Sopenharmony_ci * the header into memory. The inode of the executable is put into 148c2ecf20Sopenharmony_ci * "current->executable", and page faults do the actual loading. Clean. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Once more I can proudly say that linux stood up to being changed: it 178c2ecf20Sopenharmony_ci * was less than 2 hours work to get demand-loading completely implemented. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Demand loading changed July 1993 by Eric Youngdale. Use mmap instead, 208c2ecf20Sopenharmony_ci * current->executable is only used by the procfs. This allows a dispatch 218c2ecf20Sopenharmony_ci * table to check for several different types of binary formats. We keep 228c2ecf20Sopenharmony_ci * trying until we recognize the file or we run out of supported binary 238c2ecf20Sopenharmony_ci * formats. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/kernel_read_file.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/file.h> 298c2ecf20Sopenharmony_ci#include <linux/fdtable.h> 308c2ecf20Sopenharmony_ci#include <linux/mm.h> 318c2ecf20Sopenharmony_ci#include <linux/vmacache.h> 328c2ecf20Sopenharmony_ci#include <linux/stat.h> 338c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 348c2ecf20Sopenharmony_ci#include <linux/swap.h> 358c2ecf20Sopenharmony_ci#include <linux/string.h> 368c2ecf20Sopenharmony_ci#include <linux/init.h> 378c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 388c2ecf20Sopenharmony_ci#include <linux/sched/coredump.h> 398c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 408c2ecf20Sopenharmony_ci#include <linux/sched/numa_balancing.h> 418c2ecf20Sopenharmony_ci#include <linux/sched/task.h> 428c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 438c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 448c2ecf20Sopenharmony_ci#include <linux/highmem.h> 458c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 468c2ecf20Sopenharmony_ci#include <linux/key.h> 478c2ecf20Sopenharmony_ci#include <linux/personality.h> 488c2ecf20Sopenharmony_ci#include <linux/binfmts.h> 498c2ecf20Sopenharmony_ci#include <linux/utsname.h> 508c2ecf20Sopenharmony_ci#include <linux/pid_namespace.h> 518c2ecf20Sopenharmony_ci#include <linux/module.h> 528c2ecf20Sopenharmony_ci#include <linux/namei.h> 538c2ecf20Sopenharmony_ci#include <linux/mount.h> 548c2ecf20Sopenharmony_ci#include <linux/security.h> 558c2ecf20Sopenharmony_ci#include <linux/syscalls.h> 568c2ecf20Sopenharmony_ci#include <linux/tsacct_kern.h> 578c2ecf20Sopenharmony_ci#include <linux/cn_proc.h> 588c2ecf20Sopenharmony_ci#include <linux/audit.h> 598c2ecf20Sopenharmony_ci#include <linux/tracehook.h> 608c2ecf20Sopenharmony_ci#include <linux/kmod.h> 618c2ecf20Sopenharmony_ci#include <linux/fsnotify.h> 628c2ecf20Sopenharmony_ci#include <linux/fs_struct.h> 638c2ecf20Sopenharmony_ci#include <linux/oom.h> 648c2ecf20Sopenharmony_ci#include <linux/compat.h> 658c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 668c2ecf20Sopenharmony_ci#include <linux/io_uring.h> 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 698c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 708c2ecf20Sopenharmony_ci#include <asm/tlb.h> 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#include <trace/events/task.h> 738c2ecf20Sopenharmony_ci#include "internal.h" 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#include <trace/events/sched.h> 768c2ecf20Sopenharmony_ci#include <linux/hck/lite_hck_ced.h> 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int bprm_creds_from_file(struct linux_binprm *bprm); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciint suid_dumpable = 0; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic LIST_HEAD(formats); 838c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(binfmt_lock); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_civoid __register_binfmt(struct linux_binfmt * fmt, int insert) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci BUG_ON(!fmt); 888c2ecf20Sopenharmony_ci if (WARN_ON(!fmt->load_binary)) 898c2ecf20Sopenharmony_ci return; 908c2ecf20Sopenharmony_ci write_lock(&binfmt_lock); 918c2ecf20Sopenharmony_ci insert ? list_add(&fmt->lh, &formats) : 928c2ecf20Sopenharmony_ci list_add_tail(&fmt->lh, &formats); 938c2ecf20Sopenharmony_ci write_unlock(&binfmt_lock); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__register_binfmt); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_civoid unregister_binfmt(struct linux_binfmt * fmt) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci write_lock(&binfmt_lock); 1018c2ecf20Sopenharmony_ci list_del(&fmt->lh); 1028c2ecf20Sopenharmony_ci write_unlock(&binfmt_lock); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(unregister_binfmt); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline void put_binfmt(struct linux_binfmt * fmt) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci module_put(fmt->module); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cibool path_noexec(const struct path *path) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci return (path->mnt->mnt_flags & MNT_NOEXEC) || 1158c2ecf20Sopenharmony_ci (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#ifdef CONFIG_USELIB 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Note that a shared library must be both readable and executable due to 1218c2ecf20Sopenharmony_ci * security reasons. 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * Also note that we take the address to load from from the file itself. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ciSYSCALL_DEFINE1(uselib, const char __user *, library) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct linux_binfmt *fmt; 1288c2ecf20Sopenharmony_ci struct file *file; 1298c2ecf20Sopenharmony_ci struct filename *tmp = getname(library); 1308c2ecf20Sopenharmony_ci int error = PTR_ERR(tmp); 1318c2ecf20Sopenharmony_ci static const struct open_flags uselib_flags = { 1328c2ecf20Sopenharmony_ci .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 1338c2ecf20Sopenharmony_ci .acc_mode = MAY_READ | MAY_EXEC, 1348c2ecf20Sopenharmony_ci .intent = LOOKUP_OPEN, 1358c2ecf20Sopenharmony_ci .lookup_flags = LOOKUP_FOLLOW, 1368c2ecf20Sopenharmony_ci }; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (IS_ERR(tmp)) 1398c2ecf20Sopenharmony_ci goto out; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci file = do_filp_open(AT_FDCWD, tmp, &uselib_flags); 1428c2ecf20Sopenharmony_ci putname(tmp); 1438c2ecf20Sopenharmony_ci error = PTR_ERR(file); 1448c2ecf20Sopenharmony_ci if (IS_ERR(file)) 1458c2ecf20Sopenharmony_ci goto out; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* 1488c2ecf20Sopenharmony_ci * may_open() has already checked for this, so it should be 1498c2ecf20Sopenharmony_ci * impossible to trip now. But we need to be extra cautious 1508c2ecf20Sopenharmony_ci * and check again at the very end too. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci error = -EACCES; 1538c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) || 1548c2ecf20Sopenharmony_ci path_noexec(&file->f_path))) 1558c2ecf20Sopenharmony_ci goto exit; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci fsnotify_open(file); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci error = -ENOEXEC; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci read_lock(&binfmt_lock); 1628c2ecf20Sopenharmony_ci list_for_each_entry(fmt, &formats, lh) { 1638c2ecf20Sopenharmony_ci if (!fmt->load_shlib) 1648c2ecf20Sopenharmony_ci continue; 1658c2ecf20Sopenharmony_ci if (!try_module_get(fmt->module)) 1668c2ecf20Sopenharmony_ci continue; 1678c2ecf20Sopenharmony_ci read_unlock(&binfmt_lock); 1688c2ecf20Sopenharmony_ci error = fmt->load_shlib(file); 1698c2ecf20Sopenharmony_ci read_lock(&binfmt_lock); 1708c2ecf20Sopenharmony_ci put_binfmt(fmt); 1718c2ecf20Sopenharmony_ci if (error != -ENOEXEC) 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci read_unlock(&binfmt_lock); 1758c2ecf20Sopenharmony_ciexit: 1768c2ecf20Sopenharmony_ci fput(file); 1778c2ecf20Sopenharmony_ciout: 1788c2ecf20Sopenharmony_ci return error; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci#endif /* #ifdef CONFIG_USELIB */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 1838c2ecf20Sopenharmony_ci/* 1848c2ecf20Sopenharmony_ci * The nascent bprm->mm is not visible until exec_mmap() but it can 1858c2ecf20Sopenharmony_ci * use a lot of memory, account these pages in current->mm temporary 1868c2ecf20Sopenharmony_ci * for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we 1878c2ecf20Sopenharmony_ci * change the counter back via acct_arg_size(0). 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cistatic void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 1928c2ecf20Sopenharmony_ci long diff = (long)(pages - bprm->vma_pages); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (!mm || !diff) 1958c2ecf20Sopenharmony_ci return; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci bprm->vma_pages = pages; 1988c2ecf20Sopenharmony_ci add_mm_counter(mm, MM_ANONPAGES, diff); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, 2028c2ecf20Sopenharmony_ci int write) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct page *page; 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci unsigned int gup_flags = FOLL_FORCE; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 2098c2ecf20Sopenharmony_ci if (write) { 2108c2ecf20Sopenharmony_ci ret = expand_downwards(bprm->vma, pos); 2118c2ecf20Sopenharmony_ci if (ret < 0) 2128c2ecf20Sopenharmony_ci return NULL; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci#endif 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (write) 2178c2ecf20Sopenharmony_ci gup_flags |= FOLL_WRITE; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * We are doing an exec(). 'current' is the process 2218c2ecf20Sopenharmony_ci * doing the exec and bprm->mm is the new process's mm. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci ret = get_user_pages_remote(bprm->mm, pos, 1, gup_flags, 2248c2ecf20Sopenharmony_ci &page, NULL, NULL); 2258c2ecf20Sopenharmony_ci if (ret <= 0) 2268c2ecf20Sopenharmony_ci return NULL; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (write) 2298c2ecf20Sopenharmony_ci acct_arg_size(bprm, vma_pages(bprm->vma)); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return page; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void put_arg_page(struct page *page) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci put_page(page); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void free_arg_pages(struct linux_binprm *bprm) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void flush_arg_page(struct linux_binprm *bprm, unsigned long pos, 2448c2ecf20Sopenharmony_ci struct page *page) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci flush_cache_page(bprm->vma, pos, page_to_pfn(page)); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int __bprm_mm_init(struct linux_binprm *bprm) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci int err; 2528c2ecf20Sopenharmony_ci struct vm_area_struct *vma = NULL; 2538c2ecf20Sopenharmony_ci struct mm_struct *mm = bprm->mm; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci bprm->vma = vma = vm_area_alloc(mm); 2568c2ecf20Sopenharmony_ci if (!vma) 2578c2ecf20Sopenharmony_ci return -ENOMEM; 2588c2ecf20Sopenharmony_ci vma_set_anonymous(vma); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (mmap_write_lock_killable(mm)) { 2618c2ecf20Sopenharmony_ci err = -EINTR; 2628c2ecf20Sopenharmony_ci goto err_free; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * Place the stack at the largest stack address the architecture 2678c2ecf20Sopenharmony_ci * supports. Later, we'll move this to an appropriate place. We don't 2688c2ecf20Sopenharmony_ci * use STACK_TOP because that can depend on attributes which aren't 2698c2ecf20Sopenharmony_ci * configured yet. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci BUILD_BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP); 2728c2ecf20Sopenharmony_ci vma->vm_end = STACK_TOP_MAX; 2738c2ecf20Sopenharmony_ci vma->vm_start = vma->vm_end - PAGE_SIZE; 2748c2ecf20Sopenharmony_ci vma->vm_flags = VM_SOFTDIRTY | VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; 2758c2ecf20Sopenharmony_ci vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci err = insert_vm_struct(mm, vma); 2788c2ecf20Sopenharmony_ci if (err) 2798c2ecf20Sopenharmony_ci goto err; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci mm->stack_vm = mm->total_vm = 1; 2828c2ecf20Sopenharmony_ci mmap_write_unlock(mm); 2838c2ecf20Sopenharmony_ci bprm->p = vma->vm_end - sizeof(void *); 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_cierr: 2868c2ecf20Sopenharmony_ci mmap_write_unlock(mm); 2878c2ecf20Sopenharmony_cierr_free: 2888c2ecf20Sopenharmony_ci bprm->vma = NULL; 2898c2ecf20Sopenharmony_ci vm_area_free(vma); 2908c2ecf20Sopenharmony_ci return err; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic bool valid_arg_len(struct linux_binprm *bprm, long len) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci return len <= MAX_ARG_STRLEN; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci#else 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, 3058c2ecf20Sopenharmony_ci int write) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct page *page; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci page = bprm->page[pos / PAGE_SIZE]; 3108c2ecf20Sopenharmony_ci if (!page && write) { 3118c2ecf20Sopenharmony_ci page = alloc_page(GFP_HIGHUSER|__GFP_ZERO); 3128c2ecf20Sopenharmony_ci if (!page) 3138c2ecf20Sopenharmony_ci return NULL; 3148c2ecf20Sopenharmony_ci bprm->page[pos / PAGE_SIZE] = page; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return page; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void put_arg_page(struct page *page) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void free_arg_page(struct linux_binprm *bprm, int i) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci if (bprm->page[i]) { 3278c2ecf20Sopenharmony_ci __free_page(bprm->page[i]); 3288c2ecf20Sopenharmony_ci bprm->page[i] = NULL; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void free_arg_pages(struct linux_binprm *bprm) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci int i; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci for (i = 0; i < MAX_ARG_PAGES; i++) 3378c2ecf20Sopenharmony_ci free_arg_page(bprm, i); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void flush_arg_page(struct linux_binprm *bprm, unsigned long pos, 3418c2ecf20Sopenharmony_ci struct page *page) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int __bprm_mm_init(struct linux_binprm *bprm) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *); 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic bool valid_arg_len(struct linux_binprm *bprm, long len) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci return len <= bprm->p; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci#endif /* CONFIG_MMU */ 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/* 3598c2ecf20Sopenharmony_ci * Create a new mm_struct and populate it with a temporary stack 3608c2ecf20Sopenharmony_ci * vm_area_struct. We don't have enough context at this point to set the stack 3618c2ecf20Sopenharmony_ci * flags, permissions, and offset, so we use temporary values. We'll update 3628c2ecf20Sopenharmony_ci * them later in setup_arg_pages(). 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic int bprm_mm_init(struct linux_binprm *bprm) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci int err; 3678c2ecf20Sopenharmony_ci struct mm_struct *mm = NULL; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci bprm->mm = mm = mm_alloc(); 3708c2ecf20Sopenharmony_ci err = -ENOMEM; 3718c2ecf20Sopenharmony_ci if (!mm) 3728c2ecf20Sopenharmony_ci goto err; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Save current stack limit for all calculations made during exec. */ 3758c2ecf20Sopenharmony_ci task_lock(current->group_leader); 3768c2ecf20Sopenharmony_ci bprm->rlim_stack = current->signal->rlim[RLIMIT_STACK]; 3778c2ecf20Sopenharmony_ci task_unlock(current->group_leader); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci err = __bprm_mm_init(bprm); 3808c2ecf20Sopenharmony_ci if (err) 3818c2ecf20Sopenharmony_ci goto err; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cierr: 3868c2ecf20Sopenharmony_ci if (mm) { 3878c2ecf20Sopenharmony_ci bprm->mm = NULL; 3888c2ecf20Sopenharmony_ci mmdrop(mm); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return err; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistruct user_arg_ptr { 3958c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 3968c2ecf20Sopenharmony_ci bool is_compat; 3978c2ecf20Sopenharmony_ci#endif 3988c2ecf20Sopenharmony_ci union { 3998c2ecf20Sopenharmony_ci const char __user *const __user *native; 4008c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 4018c2ecf20Sopenharmony_ci const compat_uptr_t __user *compat; 4028c2ecf20Sopenharmony_ci#endif 4038c2ecf20Sopenharmony_ci } ptr; 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci const char __user *native; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 4118c2ecf20Sopenharmony_ci if (unlikely(argv.is_compat)) { 4128c2ecf20Sopenharmony_ci compat_uptr_t compat; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (get_user(compat, argv.ptr.compat + nr)) 4158c2ecf20Sopenharmony_ci return ERR_PTR(-EFAULT); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return compat_ptr(compat); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci#endif 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (get_user(native, argv.ptr.native + nr)) 4228c2ecf20Sopenharmony_ci return ERR_PTR(-EFAULT); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return native; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* 4288c2ecf20Sopenharmony_ci * count() counts the number of strings in array ARGV. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_cistatic int count(struct user_arg_ptr argv, int max) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci int i = 0; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (argv.ptr.native != NULL) { 4358c2ecf20Sopenharmony_ci for (;;) { 4368c2ecf20Sopenharmony_ci const char __user *p = get_user_arg_ptr(argv, i); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (!p) 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (IS_ERR(p)) 4428c2ecf20Sopenharmony_ci return -EFAULT; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (i >= max) 4458c2ecf20Sopenharmony_ci return -E2BIG; 4468c2ecf20Sopenharmony_ci ++i; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) 4498c2ecf20Sopenharmony_ci return -ERESTARTNOHAND; 4508c2ecf20Sopenharmony_ci cond_resched(); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci return i; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int count_strings_kernel(const char *const *argv) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci int i; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (!argv) 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci for (i = 0; argv[i]; ++i) { 4648c2ecf20Sopenharmony_ci if (i >= MAX_ARG_STRINGS) 4658c2ecf20Sopenharmony_ci return -E2BIG; 4668c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) 4678c2ecf20Sopenharmony_ci return -ERESTARTNOHAND; 4688c2ecf20Sopenharmony_ci cond_resched(); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci return i; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic int bprm_stack_limits(struct linux_binprm *bprm) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci unsigned long limit, ptr_size; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* 4788c2ecf20Sopenharmony_ci * Limit to 1/4 of the max stack size or 3/4 of _STK_LIM 4798c2ecf20Sopenharmony_ci * (whichever is smaller) for the argv+env strings. 4808c2ecf20Sopenharmony_ci * This ensures that: 4818c2ecf20Sopenharmony_ci * - the remaining binfmt code will not run out of stack space, 4828c2ecf20Sopenharmony_ci * - the program will have a reasonable amount of stack left 4838c2ecf20Sopenharmony_ci * to work from. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci limit = _STK_LIM / 4 * 3; 4868c2ecf20Sopenharmony_ci limit = min(limit, bprm->rlim_stack.rlim_cur / 4); 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * We've historically supported up to 32 pages (ARG_MAX) 4898c2ecf20Sopenharmony_ci * of argument strings even with small stacks 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ci limit = max_t(unsigned long, limit, ARG_MAX); 4928c2ecf20Sopenharmony_ci /* 4938c2ecf20Sopenharmony_ci * We must account for the size of all the argv and envp pointers to 4948c2ecf20Sopenharmony_ci * the argv and envp strings, since they will also take up space in 4958c2ecf20Sopenharmony_ci * the stack. They aren't stored until much later when we can't 4968c2ecf20Sopenharmony_ci * signal to the parent that the child has run out of stack space. 4978c2ecf20Sopenharmony_ci * Instead, calculate it here so it's possible to fail gracefully. 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * In the case of argc = 0, make sure there is space for adding a 5008c2ecf20Sopenharmony_ci * empty string (which will bump argc to 1), to ensure confused 5018c2ecf20Sopenharmony_ci * userspace programs don't start processing from argv[1], thinking 5028c2ecf20Sopenharmony_ci * argc can never be 0, to keep them from walking envp by accident. 5038c2ecf20Sopenharmony_ci * See do_execveat_common(). 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci ptr_size = (max(bprm->argc, 1) + bprm->envc) * sizeof(void *); 5068c2ecf20Sopenharmony_ci if (limit <= ptr_size) 5078c2ecf20Sopenharmony_ci return -E2BIG; 5088c2ecf20Sopenharmony_ci limit -= ptr_size; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci bprm->argmin = bprm->p - limit; 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/* 5158c2ecf20Sopenharmony_ci * 'copy_strings()' copies argument/environment strings from the old 5168c2ecf20Sopenharmony_ci * processes's memory to the new process's stack. The call to get_user_pages() 5178c2ecf20Sopenharmony_ci * ensures the destination page is created and not swapped out. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_cistatic int copy_strings(int argc, struct user_arg_ptr argv, 5208c2ecf20Sopenharmony_ci struct linux_binprm *bprm) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct page *kmapped_page = NULL; 5238c2ecf20Sopenharmony_ci char *kaddr = NULL; 5248c2ecf20Sopenharmony_ci unsigned long kpos = 0; 5258c2ecf20Sopenharmony_ci int ret; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci while (argc-- > 0) { 5288c2ecf20Sopenharmony_ci const char __user *str; 5298c2ecf20Sopenharmony_ci int len; 5308c2ecf20Sopenharmony_ci unsigned long pos; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ret = -EFAULT; 5338c2ecf20Sopenharmony_ci str = get_user_arg_ptr(argv, argc); 5348c2ecf20Sopenharmony_ci if (IS_ERR(str)) 5358c2ecf20Sopenharmony_ci goto out; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci len = strnlen_user(str, MAX_ARG_STRLEN); 5388c2ecf20Sopenharmony_ci if (!len) 5398c2ecf20Sopenharmony_ci goto out; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci ret = -E2BIG; 5428c2ecf20Sopenharmony_ci if (!valid_arg_len(bprm, len)) 5438c2ecf20Sopenharmony_ci goto out; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* We're going to work our way backwords. */ 5468c2ecf20Sopenharmony_ci pos = bprm->p; 5478c2ecf20Sopenharmony_ci str += len; 5488c2ecf20Sopenharmony_ci bprm->p -= len; 5498c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 5508c2ecf20Sopenharmony_ci if (bprm->p < bprm->argmin) 5518c2ecf20Sopenharmony_ci goto out; 5528c2ecf20Sopenharmony_ci#endif 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci while (len > 0) { 5558c2ecf20Sopenharmony_ci int offset, bytes_to_copy; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) { 5588c2ecf20Sopenharmony_ci ret = -ERESTARTNOHAND; 5598c2ecf20Sopenharmony_ci goto out; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci cond_resched(); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci offset = pos % PAGE_SIZE; 5648c2ecf20Sopenharmony_ci if (offset == 0) 5658c2ecf20Sopenharmony_ci offset = PAGE_SIZE; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci bytes_to_copy = offset; 5688c2ecf20Sopenharmony_ci if (bytes_to_copy > len) 5698c2ecf20Sopenharmony_ci bytes_to_copy = len; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci offset -= bytes_to_copy; 5728c2ecf20Sopenharmony_ci pos -= bytes_to_copy; 5738c2ecf20Sopenharmony_ci str -= bytes_to_copy; 5748c2ecf20Sopenharmony_ci len -= bytes_to_copy; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (!kmapped_page || kpos != (pos & PAGE_MASK)) { 5778c2ecf20Sopenharmony_ci struct page *page; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci page = get_arg_page(bprm, pos, 1); 5808c2ecf20Sopenharmony_ci if (!page) { 5818c2ecf20Sopenharmony_ci ret = -E2BIG; 5828c2ecf20Sopenharmony_ci goto out; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (kmapped_page) { 5868c2ecf20Sopenharmony_ci flush_kernel_dcache_page(kmapped_page); 5878c2ecf20Sopenharmony_ci kunmap(kmapped_page); 5888c2ecf20Sopenharmony_ci put_arg_page(kmapped_page); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci kmapped_page = page; 5918c2ecf20Sopenharmony_ci kaddr = kmap(kmapped_page); 5928c2ecf20Sopenharmony_ci kpos = pos & PAGE_MASK; 5938c2ecf20Sopenharmony_ci flush_arg_page(bprm, kpos, kmapped_page); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci if (copy_from_user(kaddr+offset, str, bytes_to_copy)) { 5968c2ecf20Sopenharmony_ci ret = -EFAULT; 5978c2ecf20Sopenharmony_ci goto out; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci ret = 0; 6028c2ecf20Sopenharmony_ciout: 6038c2ecf20Sopenharmony_ci if (kmapped_page) { 6048c2ecf20Sopenharmony_ci flush_kernel_dcache_page(kmapped_page); 6058c2ecf20Sopenharmony_ci kunmap(kmapped_page); 6068c2ecf20Sopenharmony_ci put_arg_page(kmapped_page); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci return ret; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* 6128c2ecf20Sopenharmony_ci * Copy and argument/environment string from the kernel to the processes stack. 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_ciint copy_string_kernel(const char *arg, struct linux_binprm *bprm) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci int len = strnlen(arg, MAX_ARG_STRLEN) + 1 /* terminating NUL */; 6178c2ecf20Sopenharmony_ci unsigned long pos = bprm->p; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (len == 0) 6208c2ecf20Sopenharmony_ci return -EFAULT; 6218c2ecf20Sopenharmony_ci if (!valid_arg_len(bprm, len)) 6228c2ecf20Sopenharmony_ci return -E2BIG; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* We're going to work our way backwards. */ 6258c2ecf20Sopenharmony_ci arg += len; 6268c2ecf20Sopenharmony_ci bprm->p -= len; 6278c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_MMU) && bprm->p < bprm->argmin) 6288c2ecf20Sopenharmony_ci return -E2BIG; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci while (len > 0) { 6318c2ecf20Sopenharmony_ci unsigned int bytes_to_copy = min_t(unsigned int, len, 6328c2ecf20Sopenharmony_ci min_not_zero(offset_in_page(pos), PAGE_SIZE)); 6338c2ecf20Sopenharmony_ci struct page *page; 6348c2ecf20Sopenharmony_ci char *kaddr; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci pos -= bytes_to_copy; 6378c2ecf20Sopenharmony_ci arg -= bytes_to_copy; 6388c2ecf20Sopenharmony_ci len -= bytes_to_copy; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci page = get_arg_page(bprm, pos, 1); 6418c2ecf20Sopenharmony_ci if (!page) 6428c2ecf20Sopenharmony_ci return -E2BIG; 6438c2ecf20Sopenharmony_ci kaddr = kmap_atomic(page); 6448c2ecf20Sopenharmony_ci flush_arg_page(bprm, pos & PAGE_MASK, page); 6458c2ecf20Sopenharmony_ci memcpy(kaddr + offset_in_page(pos), arg, bytes_to_copy); 6468c2ecf20Sopenharmony_ci flush_kernel_dcache_page(page); 6478c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 6488c2ecf20Sopenharmony_ci put_arg_page(page); 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci return 0; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(copy_string_kernel); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int copy_strings_kernel(int argc, const char *const *argv, 6568c2ecf20Sopenharmony_ci struct linux_binprm *bprm) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci while (argc-- > 0) { 6598c2ecf20Sopenharmony_ci int ret = copy_string_kernel(argv[argc], bprm); 6608c2ecf20Sopenharmony_ci if (ret < 0) 6618c2ecf20Sopenharmony_ci return ret; 6628c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) 6638c2ecf20Sopenharmony_ci return -ERESTARTNOHAND; 6648c2ecf20Sopenharmony_ci cond_resched(); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci/* 6728c2ecf20Sopenharmony_ci * During bprm_mm_init(), we create a temporary stack at STACK_TOP_MAX. Once 6738c2ecf20Sopenharmony_ci * the binfmt code determines where the new stack should reside, we shift it to 6748c2ecf20Sopenharmony_ci * its final location. The process proceeds as follows: 6758c2ecf20Sopenharmony_ci * 6768c2ecf20Sopenharmony_ci * 1) Use shift to calculate the new vma endpoints. 6778c2ecf20Sopenharmony_ci * 2) Extend vma to cover both the old and new ranges. This ensures the 6788c2ecf20Sopenharmony_ci * arguments passed to subsequent functions are consistent. 6798c2ecf20Sopenharmony_ci * 3) Move vma's page tables to the new range. 6808c2ecf20Sopenharmony_ci * 4) Free up any cleared pgd range. 6818c2ecf20Sopenharmony_ci * 5) Shrink the vma to cover only the new range. 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_cistatic int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct mm_struct *mm = vma->vm_mm; 6868c2ecf20Sopenharmony_ci unsigned long old_start = vma->vm_start; 6878c2ecf20Sopenharmony_ci unsigned long old_end = vma->vm_end; 6888c2ecf20Sopenharmony_ci unsigned long length = old_end - old_start; 6898c2ecf20Sopenharmony_ci unsigned long new_start = old_start - shift; 6908c2ecf20Sopenharmony_ci unsigned long new_end = old_end - shift; 6918c2ecf20Sopenharmony_ci struct mmu_gather tlb; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci BUG_ON(new_start > new_end); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * ensure there are no vmas between where we want to go 6978c2ecf20Sopenharmony_ci * and where we are 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci if (vma != find_vma(mm, new_start)) 7008c2ecf20Sopenharmony_ci return -EFAULT; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* 7038c2ecf20Sopenharmony_ci * cover the whole range: [new_start, old_end) 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_ci if (vma_adjust(vma, new_start, old_end, vma->vm_pgoff, NULL)) 7068c2ecf20Sopenharmony_ci return -ENOMEM; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * move the page tables downwards, on failure we rely on 7108c2ecf20Sopenharmony_ci * process cleanup to remove whatever mess we made. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci if (length != move_page_tables(vma, old_start, 7138c2ecf20Sopenharmony_ci vma, new_start, length, false)) 7148c2ecf20Sopenharmony_ci return -ENOMEM; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci lru_add_drain(); 7178c2ecf20Sopenharmony_ci tlb_gather_mmu(&tlb, mm, old_start, old_end); 7188c2ecf20Sopenharmony_ci if (new_end > old_start) { 7198c2ecf20Sopenharmony_ci /* 7208c2ecf20Sopenharmony_ci * when the old and new regions overlap clear from new_end. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci free_pgd_range(&tlb, new_end, old_end, new_end, 7238c2ecf20Sopenharmony_ci vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING); 7248c2ecf20Sopenharmony_ci } else { 7258c2ecf20Sopenharmony_ci /* 7268c2ecf20Sopenharmony_ci * otherwise, clean from old_start; this is done to not touch 7278c2ecf20Sopenharmony_ci * the address space in [new_end, old_start) some architectures 7288c2ecf20Sopenharmony_ci * have constraints on va-space that make this illegal (IA64) - 7298c2ecf20Sopenharmony_ci * for the others its just a little faster. 7308c2ecf20Sopenharmony_ci */ 7318c2ecf20Sopenharmony_ci free_pgd_range(&tlb, old_start, old_end, new_end, 7328c2ecf20Sopenharmony_ci vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci tlb_finish_mmu(&tlb, old_start, old_end); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * Shrink the vma to just the new range. Always succeeds. 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_ci vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/* 7458c2ecf20Sopenharmony_ci * Finalizes the stack vm_area_struct. The flags and permissions are updated, 7468c2ecf20Sopenharmony_ci * the stack is optionally relocated, and some extra space is added. 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_ciint setup_arg_pages(struct linux_binprm *bprm, 7498c2ecf20Sopenharmony_ci unsigned long stack_top, 7508c2ecf20Sopenharmony_ci int executable_stack) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci unsigned long ret; 7538c2ecf20Sopenharmony_ci unsigned long stack_shift; 7548c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 7558c2ecf20Sopenharmony_ci struct vm_area_struct *vma = bprm->vma; 7568c2ecf20Sopenharmony_ci struct vm_area_struct *prev = NULL; 7578c2ecf20Sopenharmony_ci unsigned long vm_flags; 7588c2ecf20Sopenharmony_ci unsigned long stack_base; 7598c2ecf20Sopenharmony_ci unsigned long stack_size; 7608c2ecf20Sopenharmony_ci unsigned long stack_expand; 7618c2ecf20Sopenharmony_ci unsigned long rlim_stack; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 7648c2ecf20Sopenharmony_ci /* Limit stack size */ 7658c2ecf20Sopenharmony_ci stack_base = bprm->rlim_stack.rlim_max; 7668c2ecf20Sopenharmony_ci if (stack_base > STACK_SIZE_MAX) 7678c2ecf20Sopenharmony_ci stack_base = STACK_SIZE_MAX; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* Add space for stack randomization. */ 7708c2ecf20Sopenharmony_ci stack_base += (STACK_RND_MASK << PAGE_SHIFT); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* Make sure we didn't let the argument array grow too large. */ 7738c2ecf20Sopenharmony_ci if (vma->vm_end - vma->vm_start > stack_base) 7748c2ecf20Sopenharmony_ci return -ENOMEM; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci stack_base = PAGE_ALIGN(stack_top - stack_base); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci stack_shift = vma->vm_start - stack_base; 7798c2ecf20Sopenharmony_ci mm->arg_start = bprm->p - stack_shift; 7808c2ecf20Sopenharmony_ci bprm->p = vma->vm_end - stack_shift; 7818c2ecf20Sopenharmony_ci#else 7828c2ecf20Sopenharmony_ci stack_top = arch_align_stack(stack_top); 7838c2ecf20Sopenharmony_ci stack_top = PAGE_ALIGN(stack_top); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (unlikely(stack_top < mmap_min_addr) || 7868c2ecf20Sopenharmony_ci unlikely(vma->vm_end - vma->vm_start >= stack_top - mmap_min_addr)) 7878c2ecf20Sopenharmony_ci return -ENOMEM; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci stack_shift = vma->vm_end - stack_top; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci bprm->p -= stack_shift; 7928c2ecf20Sopenharmony_ci mm->arg_start = bprm->p; 7938c2ecf20Sopenharmony_ci#endif 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (bprm->loader) 7968c2ecf20Sopenharmony_ci bprm->loader -= stack_shift; 7978c2ecf20Sopenharmony_ci bprm->exec -= stack_shift; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (mmap_write_lock_killable(mm)) 8008c2ecf20Sopenharmony_ci return -EINTR; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci vm_flags = VM_STACK_FLAGS; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* 8058c2ecf20Sopenharmony_ci * Adjust stack execute permissions; explicitly enable for 8068c2ecf20Sopenharmony_ci * EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X and leave alone 8078c2ecf20Sopenharmony_ci * (arch default) otherwise. 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ci if (unlikely(executable_stack == EXSTACK_ENABLE_X)) 8108c2ecf20Sopenharmony_ci vm_flags |= VM_EXEC; 8118c2ecf20Sopenharmony_ci else if (executable_stack == EXSTACK_DISABLE_X) 8128c2ecf20Sopenharmony_ci vm_flags &= ~VM_EXEC; 8138c2ecf20Sopenharmony_ci vm_flags |= mm->def_flags; 8148c2ecf20Sopenharmony_ci vm_flags |= VM_STACK_INCOMPLETE_SETUP; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end, 8178c2ecf20Sopenharmony_ci vm_flags); 8188c2ecf20Sopenharmony_ci if (ret) 8198c2ecf20Sopenharmony_ci goto out_unlock; 8208c2ecf20Sopenharmony_ci BUG_ON(prev != vma); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (unlikely(vm_flags & VM_EXEC)) { 8238c2ecf20Sopenharmony_ci pr_warn_once("process '%pD4' started with executable stack\n", 8248c2ecf20Sopenharmony_ci bprm->file); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci /* Move stack pages down in memory. */ 8288c2ecf20Sopenharmony_ci if (stack_shift) { 8298c2ecf20Sopenharmony_ci ret = shift_arg_pages(vma, stack_shift); 8308c2ecf20Sopenharmony_ci if (ret) 8318c2ecf20Sopenharmony_ci goto out_unlock; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* mprotect_fixup is overkill to remove the temporary stack flags */ 8358c2ecf20Sopenharmony_ci vma->vm_flags &= ~VM_STACK_INCOMPLETE_SETUP; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci stack_expand = 131072UL; /* randomly 32*4k (or 2*64k) pages */ 8388c2ecf20Sopenharmony_ci stack_size = vma->vm_end - vma->vm_start; 8398c2ecf20Sopenharmony_ci /* 8408c2ecf20Sopenharmony_ci * Align this down to a page boundary as expand_stack 8418c2ecf20Sopenharmony_ci * will align it up. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci rlim_stack = bprm->rlim_stack.rlim_cur & PAGE_MASK; 8448c2ecf20Sopenharmony_ci#ifdef CONFIG_STACK_GROWSUP 8458c2ecf20Sopenharmony_ci if (stack_size + stack_expand > rlim_stack) 8468c2ecf20Sopenharmony_ci stack_base = vma->vm_start + rlim_stack; 8478c2ecf20Sopenharmony_ci else 8488c2ecf20Sopenharmony_ci stack_base = vma->vm_end + stack_expand; 8498c2ecf20Sopenharmony_ci#else 8508c2ecf20Sopenharmony_ci if (stack_size + stack_expand > rlim_stack) 8518c2ecf20Sopenharmony_ci stack_base = vma->vm_end - rlim_stack; 8528c2ecf20Sopenharmony_ci else 8538c2ecf20Sopenharmony_ci stack_base = vma->vm_start - stack_expand; 8548c2ecf20Sopenharmony_ci#endif 8558c2ecf20Sopenharmony_ci current->mm->start_stack = bprm->p; 8568c2ecf20Sopenharmony_ci ret = expand_stack(vma, stack_base); 8578c2ecf20Sopenharmony_ci if (ret) 8588c2ecf20Sopenharmony_ci ret = -EFAULT; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ciout_unlock: 8618c2ecf20Sopenharmony_ci mmap_write_unlock(mm); 8628c2ecf20Sopenharmony_ci return ret; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(setup_arg_pages); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci#else 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci/* 8698c2ecf20Sopenharmony_ci * Transfer the program arguments and environment from the holding pages 8708c2ecf20Sopenharmony_ci * onto the stack. The provided stack pointer is adjusted accordingly. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ciint transfer_args_to_stack(struct linux_binprm *bprm, 8738c2ecf20Sopenharmony_ci unsigned long *sp_location) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci unsigned long index, stop, sp; 8768c2ecf20Sopenharmony_ci int ret = 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci stop = bprm->p >> PAGE_SHIFT; 8798c2ecf20Sopenharmony_ci sp = *sp_location; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { 8828c2ecf20Sopenharmony_ci unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0; 8838c2ecf20Sopenharmony_ci char *src = kmap(bprm->page[index]) + offset; 8848c2ecf20Sopenharmony_ci sp -= PAGE_SIZE - offset; 8858c2ecf20Sopenharmony_ci if (copy_to_user((void *) sp, src, PAGE_SIZE - offset) != 0) 8868c2ecf20Sopenharmony_ci ret = -EFAULT; 8878c2ecf20Sopenharmony_ci kunmap(bprm->page[index]); 8888c2ecf20Sopenharmony_ci if (ret) 8898c2ecf20Sopenharmony_ci goto out; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci *sp_location = sp; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ciout: 8958c2ecf20Sopenharmony_ci return ret; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(transfer_args_to_stack); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci#endif /* CONFIG_MMU */ 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic struct file *do_open_execat(int fd, struct filename *name, int flags) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci struct file *file; 9048c2ecf20Sopenharmony_ci int err; 9058c2ecf20Sopenharmony_ci struct open_flags open_exec_flags = { 9068c2ecf20Sopenharmony_ci .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 9078c2ecf20Sopenharmony_ci .acc_mode = MAY_EXEC, 9088c2ecf20Sopenharmony_ci .intent = LOOKUP_OPEN, 9098c2ecf20Sopenharmony_ci .lookup_flags = LOOKUP_FOLLOW, 9108c2ecf20Sopenharmony_ci }; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) 9138c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 9148c2ecf20Sopenharmony_ci if (flags & AT_SYMLINK_NOFOLLOW) 9158c2ecf20Sopenharmony_ci open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW; 9168c2ecf20Sopenharmony_ci if (flags & AT_EMPTY_PATH) 9178c2ecf20Sopenharmony_ci open_exec_flags.lookup_flags |= LOOKUP_EMPTY; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci file = do_filp_open(fd, name, &open_exec_flags); 9208c2ecf20Sopenharmony_ci if (IS_ERR(file)) 9218c2ecf20Sopenharmony_ci goto out; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* 9248c2ecf20Sopenharmony_ci * may_open() has already checked for this, so it should be 9258c2ecf20Sopenharmony_ci * impossible to trip now. But we need to be extra cautious 9268c2ecf20Sopenharmony_ci * and check again at the very end too. 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_ci err = -EACCES; 9298c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) || 9308c2ecf20Sopenharmony_ci path_noexec(&file->f_path))) 9318c2ecf20Sopenharmony_ci goto exit; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci err = deny_write_access(file); 9348c2ecf20Sopenharmony_ci if (err) 9358c2ecf20Sopenharmony_ci goto exit; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (name->name[0] != '\0') 9388c2ecf20Sopenharmony_ci fsnotify_open(file); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ciout: 9418c2ecf20Sopenharmony_ci return file; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ciexit: 9448c2ecf20Sopenharmony_ci fput(file); 9458c2ecf20Sopenharmony_ci return ERR_PTR(err); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistruct file *open_exec(const char *name) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct filename *filename = getname_kernel(name); 9518c2ecf20Sopenharmony_ci struct file *f = ERR_CAST(filename); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (!IS_ERR(filename)) { 9548c2ecf20Sopenharmony_ci f = do_open_execat(AT_FDCWD, filename, 0); 9558c2ecf20Sopenharmony_ci putname(filename); 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci return f; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(open_exec); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_AOUT) || defined(CONFIG_BINFMT_FLAT) || \ 9628c2ecf20Sopenharmony_ci defined(CONFIG_BINFMT_ELF_FDPIC) 9638c2ecf20Sopenharmony_cissize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci ssize_t res = vfs_read(file, (void __user *)addr, len, &pos); 9668c2ecf20Sopenharmony_ci if (res > 0) 9678c2ecf20Sopenharmony_ci flush_icache_user_range(addr, addr + len); 9688c2ecf20Sopenharmony_ci return res; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(read_code); 9718c2ecf20Sopenharmony_ci#endif 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci/* 9748c2ecf20Sopenharmony_ci * Maps the mm_struct mm into the current task struct. 9758c2ecf20Sopenharmony_ci * On success, this function returns with exec_update_lock 9768c2ecf20Sopenharmony_ci * held for writing. 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_cistatic int exec_mmap(struct mm_struct *mm) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct task_struct *tsk; 9818c2ecf20Sopenharmony_ci struct mm_struct *old_mm, *active_mm; 9828c2ecf20Sopenharmony_ci int ret; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* Notify parent that we're no longer interested in the old VM */ 9858c2ecf20Sopenharmony_ci tsk = current; 9868c2ecf20Sopenharmony_ci old_mm = current->mm; 9878c2ecf20Sopenharmony_ci exec_mm_release(tsk, old_mm); 9888c2ecf20Sopenharmony_ci if (old_mm) 9898c2ecf20Sopenharmony_ci sync_mm_rss(old_mm); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci ret = down_write_killable(&tsk->signal->exec_update_lock); 9928c2ecf20Sopenharmony_ci if (ret) 9938c2ecf20Sopenharmony_ci return ret; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (old_mm) { 9968c2ecf20Sopenharmony_ci /* 9978c2ecf20Sopenharmony_ci * Make sure that if there is a core dump in progress 9988c2ecf20Sopenharmony_ci * for the old mm, we get out and die instead of going 9998c2ecf20Sopenharmony_ci * through with the exec. We must hold mmap_lock around 10008c2ecf20Sopenharmony_ci * checking core_state and changing tsk->mm. 10018c2ecf20Sopenharmony_ci */ 10028c2ecf20Sopenharmony_ci mmap_read_lock(old_mm); 10038c2ecf20Sopenharmony_ci if (unlikely(old_mm->core_state)) { 10048c2ecf20Sopenharmony_ci mmap_read_unlock(old_mm); 10058c2ecf20Sopenharmony_ci up_write(&tsk->signal->exec_update_lock); 10068c2ecf20Sopenharmony_ci return -EINTR; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci task_lock(tsk); 10118c2ecf20Sopenharmony_ci membarrier_exec_mmap(mm); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci local_irq_disable(); 10148c2ecf20Sopenharmony_ci active_mm = tsk->active_mm; 10158c2ecf20Sopenharmony_ci tsk->active_mm = mm; 10168c2ecf20Sopenharmony_ci tsk->mm = mm; 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * This prevents preemption while active_mm is being loaded and 10198c2ecf20Sopenharmony_ci * it and mm are being updated, which could cause problems for 10208c2ecf20Sopenharmony_ci * lazy tlb mm refcounting when these are updated by context 10218c2ecf20Sopenharmony_ci * switches. Not all architectures can handle irqs off over 10228c2ecf20Sopenharmony_ci * activate_mm yet. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) 10258c2ecf20Sopenharmony_ci local_irq_enable(); 10268c2ecf20Sopenharmony_ci activate_mm(active_mm, mm); 10278c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) 10288c2ecf20Sopenharmony_ci local_irq_enable(); 10298c2ecf20Sopenharmony_ci tsk->mm->vmacache_seqnum = 0; 10308c2ecf20Sopenharmony_ci vmacache_flush(tsk); 10318c2ecf20Sopenharmony_ci task_unlock(tsk); 10328c2ecf20Sopenharmony_ci if (old_mm) { 10338c2ecf20Sopenharmony_ci mmap_read_unlock(old_mm); 10348c2ecf20Sopenharmony_ci BUG_ON(active_mm != old_mm); 10358c2ecf20Sopenharmony_ci setmax_mm_hiwater_rss(&tsk->signal->maxrss, old_mm); 10368c2ecf20Sopenharmony_ci mm_update_next_owner(old_mm); 10378c2ecf20Sopenharmony_ci mmput(old_mm); 10388c2ecf20Sopenharmony_ci return 0; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci mmdrop(active_mm); 10418c2ecf20Sopenharmony_ci return 0; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cistatic int de_thread(struct task_struct *tsk) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci struct signal_struct *sig = tsk->signal; 10478c2ecf20Sopenharmony_ci struct sighand_struct *oldsighand = tsk->sighand; 10488c2ecf20Sopenharmony_ci spinlock_t *lock = &oldsighand->siglock; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (thread_group_empty(tsk)) 10518c2ecf20Sopenharmony_ci goto no_thread_group; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* 10548c2ecf20Sopenharmony_ci * Kill all other threads in the thread group. 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci spin_lock_irq(lock); 10578c2ecf20Sopenharmony_ci if (signal_group_exit(sig)) { 10588c2ecf20Sopenharmony_ci /* 10598c2ecf20Sopenharmony_ci * Another group action in progress, just 10608c2ecf20Sopenharmony_ci * return so that the signal is processed. 10618c2ecf20Sopenharmony_ci */ 10628c2ecf20Sopenharmony_ci spin_unlock_irq(lock); 10638c2ecf20Sopenharmony_ci return -EAGAIN; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci sig->group_exit_task = tsk; 10678c2ecf20Sopenharmony_ci sig->notify_count = zap_other_threads(tsk); 10688c2ecf20Sopenharmony_ci if (!thread_group_leader(tsk)) 10698c2ecf20Sopenharmony_ci sig->notify_count--; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci while (sig->notify_count) { 10728c2ecf20Sopenharmony_ci __set_current_state(TASK_KILLABLE); 10738c2ecf20Sopenharmony_ci spin_unlock_irq(lock); 10748c2ecf20Sopenharmony_ci schedule(); 10758c2ecf20Sopenharmony_ci if (__fatal_signal_pending(tsk)) 10768c2ecf20Sopenharmony_ci goto killed; 10778c2ecf20Sopenharmony_ci spin_lock_irq(lock); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci spin_unlock_irq(lock); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* 10828c2ecf20Sopenharmony_ci * At this point all other threads have exited, all we have to 10838c2ecf20Sopenharmony_ci * do is to wait for the thread group leader to become inactive, 10848c2ecf20Sopenharmony_ci * and to assume its PID: 10858c2ecf20Sopenharmony_ci */ 10868c2ecf20Sopenharmony_ci if (!thread_group_leader(tsk)) { 10878c2ecf20Sopenharmony_ci struct task_struct *leader = tsk->group_leader; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci for (;;) { 10908c2ecf20Sopenharmony_ci cgroup_threadgroup_change_begin(tsk); 10918c2ecf20Sopenharmony_ci write_lock_irq(&tasklist_lock); 10928c2ecf20Sopenharmony_ci /* 10938c2ecf20Sopenharmony_ci * Do this under tasklist_lock to ensure that 10948c2ecf20Sopenharmony_ci * exit_notify() can't miss ->group_exit_task 10958c2ecf20Sopenharmony_ci */ 10968c2ecf20Sopenharmony_ci sig->notify_count = -1; 10978c2ecf20Sopenharmony_ci if (likely(leader->exit_state)) 10988c2ecf20Sopenharmony_ci break; 10998c2ecf20Sopenharmony_ci __set_current_state(TASK_KILLABLE); 11008c2ecf20Sopenharmony_ci write_unlock_irq(&tasklist_lock); 11018c2ecf20Sopenharmony_ci cgroup_threadgroup_change_end(tsk); 11028c2ecf20Sopenharmony_ci schedule(); 11038c2ecf20Sopenharmony_ci if (__fatal_signal_pending(tsk)) 11048c2ecf20Sopenharmony_ci goto killed; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* 11088c2ecf20Sopenharmony_ci * The only record we have of the real-time age of a 11098c2ecf20Sopenharmony_ci * process, regardless of execs it's done, is start_time. 11108c2ecf20Sopenharmony_ci * All the past CPU time is accumulated in signal_struct 11118c2ecf20Sopenharmony_ci * from sister threads now dead. But in this non-leader 11128c2ecf20Sopenharmony_ci * exec, nothing survives from the original leader thread, 11138c2ecf20Sopenharmony_ci * whose birth marks the true age of this process now. 11148c2ecf20Sopenharmony_ci * When we take on its identity by switching to its PID, we 11158c2ecf20Sopenharmony_ci * also take its birthdate (always earlier than our own). 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_ci tsk->start_time = leader->start_time; 11188c2ecf20Sopenharmony_ci tsk->start_boottime = leader->start_boottime; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci BUG_ON(!same_thread_group(leader, tsk)); 11218c2ecf20Sopenharmony_ci /* 11228c2ecf20Sopenharmony_ci * An exec() starts a new thread group with the 11238c2ecf20Sopenharmony_ci * TGID of the previous thread group. Rehash the 11248c2ecf20Sopenharmony_ci * two threads with a switched PID, and release 11258c2ecf20Sopenharmony_ci * the former thread group leader: 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* Become a process group leader with the old leader's pid. 11298c2ecf20Sopenharmony_ci * The old leader becomes a thread of the this thread group. 11308c2ecf20Sopenharmony_ci */ 11318c2ecf20Sopenharmony_ci exchange_tids(tsk, leader); 11328c2ecf20Sopenharmony_ci transfer_pid(leader, tsk, PIDTYPE_TGID); 11338c2ecf20Sopenharmony_ci transfer_pid(leader, tsk, PIDTYPE_PGID); 11348c2ecf20Sopenharmony_ci transfer_pid(leader, tsk, PIDTYPE_SID); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci list_replace_rcu(&leader->tasks, &tsk->tasks); 11378c2ecf20Sopenharmony_ci list_replace_init(&leader->sibling, &tsk->sibling); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci tsk->group_leader = tsk; 11408c2ecf20Sopenharmony_ci leader->group_leader = tsk; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci tsk->exit_signal = SIGCHLD; 11438c2ecf20Sopenharmony_ci leader->exit_signal = -1; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci BUG_ON(leader->exit_state != EXIT_ZOMBIE); 11468c2ecf20Sopenharmony_ci leader->exit_state = EXIT_DEAD; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* 11498c2ecf20Sopenharmony_ci * We are going to release_task()->ptrace_unlink() silently, 11508c2ecf20Sopenharmony_ci * the tracer can sleep in do_wait(). EXIT_DEAD guarantees 11518c2ecf20Sopenharmony_ci * the tracer wont't block again waiting for this thread. 11528c2ecf20Sopenharmony_ci */ 11538c2ecf20Sopenharmony_ci if (unlikely(leader->ptrace)) 11548c2ecf20Sopenharmony_ci __wake_up_parent(leader, leader->parent); 11558c2ecf20Sopenharmony_ci write_unlock_irq(&tasklist_lock); 11568c2ecf20Sopenharmony_ci cgroup_threadgroup_change_end(tsk); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci release_task(leader); 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci sig->group_exit_task = NULL; 11628c2ecf20Sopenharmony_ci sig->notify_count = 0; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cino_thread_group: 11658c2ecf20Sopenharmony_ci /* we have changed execution domain */ 11668c2ecf20Sopenharmony_ci tsk->exit_signal = SIGCHLD; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci BUG_ON(!thread_group_leader(tsk)); 11698c2ecf20Sopenharmony_ci return 0; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cikilled: 11728c2ecf20Sopenharmony_ci /* protects against exit_notify() and __exit_signal() */ 11738c2ecf20Sopenharmony_ci read_lock(&tasklist_lock); 11748c2ecf20Sopenharmony_ci sig->group_exit_task = NULL; 11758c2ecf20Sopenharmony_ci sig->notify_count = 0; 11768c2ecf20Sopenharmony_ci read_unlock(&tasklist_lock); 11778c2ecf20Sopenharmony_ci return -EAGAIN; 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci/* 11828c2ecf20Sopenharmony_ci * This function makes sure the current process has its own signal table, 11838c2ecf20Sopenharmony_ci * so that flush_signal_handlers can later reset the handlers without 11848c2ecf20Sopenharmony_ci * disturbing other processes. (Other processes might share the signal 11858c2ecf20Sopenharmony_ci * table via the CLONE_SIGHAND option to clone().) 11868c2ecf20Sopenharmony_ci */ 11878c2ecf20Sopenharmony_cistatic int unshare_sighand(struct task_struct *me) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci struct sighand_struct *oldsighand = me->sighand; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (refcount_read(&oldsighand->count) != 1) { 11928c2ecf20Sopenharmony_ci struct sighand_struct *newsighand; 11938c2ecf20Sopenharmony_ci /* 11948c2ecf20Sopenharmony_ci * This ->sighand is shared with the CLONE_SIGHAND 11958c2ecf20Sopenharmony_ci * but not CLONE_THREAD task, switch to the new one. 11968c2ecf20Sopenharmony_ci */ 11978c2ecf20Sopenharmony_ci newsighand = kmem_cache_alloc(sighand_cachep, GFP_KERNEL); 11988c2ecf20Sopenharmony_ci if (!newsighand) 11998c2ecf20Sopenharmony_ci return -ENOMEM; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci refcount_set(&newsighand->count, 1); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci write_lock_irq(&tasklist_lock); 12048c2ecf20Sopenharmony_ci spin_lock(&oldsighand->siglock); 12058c2ecf20Sopenharmony_ci memcpy(newsighand->action, oldsighand->action, 12068c2ecf20Sopenharmony_ci sizeof(newsighand->action)); 12078c2ecf20Sopenharmony_ci rcu_assign_pointer(me->sighand, newsighand); 12088c2ecf20Sopenharmony_ci spin_unlock(&oldsighand->siglock); 12098c2ecf20Sopenharmony_ci write_unlock_irq(&tasklist_lock); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci __cleanup_sighand(oldsighand); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci return 0; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cichar *__get_task_comm(char *buf, size_t buf_size, struct task_struct *tsk) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci task_lock(tsk); 12198c2ecf20Sopenharmony_ci strncpy(buf, tsk->comm, buf_size); 12208c2ecf20Sopenharmony_ci task_unlock(tsk); 12218c2ecf20Sopenharmony_ci return buf; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__get_task_comm); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci/* 12268c2ecf20Sopenharmony_ci * These functions flushes out all traces of the currently running executable 12278c2ecf20Sopenharmony_ci * so that a new one can be started 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_civoid __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci task_lock(tsk); 12338c2ecf20Sopenharmony_ci trace_task_rename(tsk, buf); 12348c2ecf20Sopenharmony_ci strlcpy(tsk->comm, buf, sizeof(tsk->comm)); 12358c2ecf20Sopenharmony_ci task_unlock(tsk); 12368c2ecf20Sopenharmony_ci perf_event_comm(tsk, exec); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/* 12408c2ecf20Sopenharmony_ci * Calling this is the point of no return. None of the failures will be 12418c2ecf20Sopenharmony_ci * seen by userspace since either the process is already taking a fatal 12428c2ecf20Sopenharmony_ci * signal (via de_thread() or coredump), or will have SEGV raised 12438c2ecf20Sopenharmony_ci * (after exec_mmap()) by search_binary_handler (see below). 12448c2ecf20Sopenharmony_ci */ 12458c2ecf20Sopenharmony_ciint begin_new_exec(struct linux_binprm * bprm) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci struct task_struct *me = current; 12488c2ecf20Sopenharmony_ci struct files_struct *displaced; 12498c2ecf20Sopenharmony_ci int retval; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* Once we are committed compute the creds */ 12528c2ecf20Sopenharmony_ci retval = bprm_creds_from_file(bprm); 12538c2ecf20Sopenharmony_ci if (retval) 12548c2ecf20Sopenharmony_ci return retval; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* 12578c2ecf20Sopenharmony_ci * Ensure all future errors are fatal. 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_ci bprm->point_of_no_return = true; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* 12628c2ecf20Sopenharmony_ci * Make this the only thread in the thread group. 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci retval = de_thread(me); 12658c2ecf20Sopenharmony_ci if (retval) 12668c2ecf20Sopenharmony_ci goto out; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* Ensure the files table is not shared. */ 12698c2ecf20Sopenharmony_ci retval = unshare_files(&displaced); 12708c2ecf20Sopenharmony_ci if (retval) 12718c2ecf20Sopenharmony_ci goto out; 12728c2ecf20Sopenharmony_ci if (displaced) 12738c2ecf20Sopenharmony_ci put_files_struct(displaced); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* 12768c2ecf20Sopenharmony_ci * Must be called _before_ exec_mmap() as bprm->mm is 12778c2ecf20Sopenharmony_ci * not visibile until then. This also enables the update 12788c2ecf20Sopenharmony_ci * to be lockless. 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ci set_mm_exe_file(bprm->mm, bprm->file); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci /* If the binary is not readable then enforce mm->dumpable=0 */ 12838c2ecf20Sopenharmony_ci would_dump(bprm, bprm->file); 12848c2ecf20Sopenharmony_ci if (bprm->have_execfd) 12858c2ecf20Sopenharmony_ci would_dump(bprm, bprm->executable); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* 12888c2ecf20Sopenharmony_ci * Release all of the old mmap stuff 12898c2ecf20Sopenharmony_ci */ 12908c2ecf20Sopenharmony_ci acct_arg_size(bprm, 0); 12918c2ecf20Sopenharmony_ci retval = exec_mmap(bprm->mm); 12928c2ecf20Sopenharmony_ci if (retval) 12938c2ecf20Sopenharmony_ci goto out; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci bprm->mm = NULL; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci#ifdef CONFIG_POSIX_TIMERS 12988c2ecf20Sopenharmony_ci spin_lock_irq(&me->sighand->siglock); 12998c2ecf20Sopenharmony_ci posix_cpu_timers_exit(me); 13008c2ecf20Sopenharmony_ci spin_unlock_irq(&me->sighand->siglock); 13018c2ecf20Sopenharmony_ci exit_itimers(me); 13028c2ecf20Sopenharmony_ci flush_itimer_signals(); 13038c2ecf20Sopenharmony_ci#endif 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* 13068c2ecf20Sopenharmony_ci * Make the signal table private. 13078c2ecf20Sopenharmony_ci */ 13088c2ecf20Sopenharmony_ci retval = unshare_sighand(me); 13098c2ecf20Sopenharmony_ci if (retval) 13108c2ecf20Sopenharmony_ci goto out_unlock; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* 13138c2ecf20Sopenharmony_ci * Ensure that the uaccess routines can actually operate on userspace 13148c2ecf20Sopenharmony_ci * pointers: 13158c2ecf20Sopenharmony_ci */ 13168c2ecf20Sopenharmony_ci force_uaccess_begin(); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | 13198c2ecf20Sopenharmony_ci PF_NOFREEZE | PF_NO_SETAFFINITY); 13208c2ecf20Sopenharmony_ci flush_thread(); 13218c2ecf20Sopenharmony_ci me->personality &= ~bprm->per_clear; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* 13248c2ecf20Sopenharmony_ci * We have to apply CLOEXEC before we change whether the process is 13258c2ecf20Sopenharmony_ci * dumpable (in setup_new_exec) to avoid a race with a process in userspace 13268c2ecf20Sopenharmony_ci * trying to access the should-be-closed file descriptors of a process 13278c2ecf20Sopenharmony_ci * undergoing exec(2). 13288c2ecf20Sopenharmony_ci */ 13298c2ecf20Sopenharmony_ci do_close_on_exec(me->files); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (bprm->secureexec) { 13328c2ecf20Sopenharmony_ci /* Make sure parent cannot signal privileged process. */ 13338c2ecf20Sopenharmony_ci me->pdeath_signal = 0; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* 13368c2ecf20Sopenharmony_ci * For secureexec, reset the stack limit to sane default to 13378c2ecf20Sopenharmony_ci * avoid bad behavior from the prior rlimits. This has to 13388c2ecf20Sopenharmony_ci * happen before arch_pick_mmap_layout(), which examines 13398c2ecf20Sopenharmony_ci * RLIMIT_STACK, but after the point of no return to avoid 13408c2ecf20Sopenharmony_ci * needing to clean up the change on failure. 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ci if (bprm->rlim_stack.rlim_cur > _STK_LIM) 13438c2ecf20Sopenharmony_ci bprm->rlim_stack.rlim_cur = _STK_LIM; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci me->sas_ss_sp = me->sas_ss_size = 0; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* 13498c2ecf20Sopenharmony_ci * Figure out dumpability. Note that this checking only of current 13508c2ecf20Sopenharmony_ci * is wrong, but userspace depends on it. This should be testing 13518c2ecf20Sopenharmony_ci * bprm->secureexec instead. 13528c2ecf20Sopenharmony_ci */ 13538c2ecf20Sopenharmony_ci if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP || 13548c2ecf20Sopenharmony_ci !(uid_eq(current_euid(), current_uid()) && 13558c2ecf20Sopenharmony_ci gid_eq(current_egid(), current_gid()))) 13568c2ecf20Sopenharmony_ci set_dumpable(current->mm, suid_dumpable); 13578c2ecf20Sopenharmony_ci else 13588c2ecf20Sopenharmony_ci set_dumpable(current->mm, SUID_DUMP_USER); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci perf_event_exec(); 13618c2ecf20Sopenharmony_ci __set_task_comm(me, kbasename(bprm->filename), true); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* An exec changes our domain. We are no longer part of the thread 13648c2ecf20Sopenharmony_ci group */ 13658c2ecf20Sopenharmony_ci WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1); 13668c2ecf20Sopenharmony_ci flush_signal_handlers(me, 0); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* 13698c2ecf20Sopenharmony_ci * install the new credentials for this executable 13708c2ecf20Sopenharmony_ci */ 13718c2ecf20Sopenharmony_ci security_bprm_committing_creds(bprm); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci commit_creds(bprm->cred); 13748c2ecf20Sopenharmony_ci bprm->cred = NULL; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci /* 13778c2ecf20Sopenharmony_ci * Disable monitoring for regular users 13788c2ecf20Sopenharmony_ci * when executing setuid binaries. Must 13798c2ecf20Sopenharmony_ci * wait until new credentials are committed 13808c2ecf20Sopenharmony_ci * by commit_creds() above 13818c2ecf20Sopenharmony_ci */ 13828c2ecf20Sopenharmony_ci if (get_dumpable(me->mm) != SUID_DUMP_USER) 13838c2ecf20Sopenharmony_ci perf_event_exit_task(me); 13848c2ecf20Sopenharmony_ci /* 13858c2ecf20Sopenharmony_ci * cred_guard_mutex must be held at least to this point to prevent 13868c2ecf20Sopenharmony_ci * ptrace_attach() from altering our determination of the task's 13878c2ecf20Sopenharmony_ci * credentials; any time after this it may be unlocked. 13888c2ecf20Sopenharmony_ci */ 13898c2ecf20Sopenharmony_ci security_bprm_committed_creds(bprm); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci /* Pass the opened binary to the interpreter. */ 13928c2ecf20Sopenharmony_ci if (bprm->have_execfd) { 13938c2ecf20Sopenharmony_ci retval = get_unused_fd_flags(0); 13948c2ecf20Sopenharmony_ci if (retval < 0) 13958c2ecf20Sopenharmony_ci goto out_unlock; 13968c2ecf20Sopenharmony_ci fd_install(retval, bprm->executable); 13978c2ecf20Sopenharmony_ci bprm->executable = NULL; 13988c2ecf20Sopenharmony_ci bprm->execfd = retval; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci return 0; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ciout_unlock: 14038c2ecf20Sopenharmony_ci up_write(&me->signal->exec_update_lock); 14048c2ecf20Sopenharmony_ci if (!bprm->cred) 14058c2ecf20Sopenharmony_ci mutex_unlock(&me->signal->cred_guard_mutex); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ciout: 14088c2ecf20Sopenharmony_ci return retval; 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(begin_new_exec); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_civoid would_dump(struct linux_binprm *bprm, struct file *file) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 14158c2ecf20Sopenharmony_ci if (inode_permission(inode, MAY_READ) < 0) { 14168c2ecf20Sopenharmony_ci struct user_namespace *old, *user_ns; 14178c2ecf20Sopenharmony_ci bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci /* Ensure mm->user_ns contains the executable */ 14208c2ecf20Sopenharmony_ci user_ns = old = bprm->mm->user_ns; 14218c2ecf20Sopenharmony_ci while ((user_ns != &init_user_ns) && 14228c2ecf20Sopenharmony_ci !privileged_wrt_inode_uidgid(user_ns, inode)) 14238c2ecf20Sopenharmony_ci user_ns = user_ns->parent; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (old != user_ns) { 14268c2ecf20Sopenharmony_ci bprm->mm->user_ns = get_user_ns(user_ns); 14278c2ecf20Sopenharmony_ci put_user_ns(old); 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(would_dump); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_civoid setup_new_exec(struct linux_binprm * bprm) 14348c2ecf20Sopenharmony_ci{ 14358c2ecf20Sopenharmony_ci /* Setup things that can depend upon the personality */ 14368c2ecf20Sopenharmony_ci struct task_struct *me = current; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci arch_pick_mmap_layout(me->mm, &bprm->rlim_stack); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci arch_setup_new_exec(); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci /* Set the new mm task size. We have to do that late because it may 14438c2ecf20Sopenharmony_ci * depend on TIF_32BIT which is only updated in flush_thread() on 14448c2ecf20Sopenharmony_ci * some architectures like powerpc 14458c2ecf20Sopenharmony_ci */ 14468c2ecf20Sopenharmony_ci me->mm->task_size = TASK_SIZE; 14478c2ecf20Sopenharmony_ci up_write(&me->signal->exec_update_lock); 14488c2ecf20Sopenharmony_ci mutex_unlock(&me->signal->cred_guard_mutex); 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(setup_new_exec); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci/* Runs immediately before start_thread() takes over. */ 14538c2ecf20Sopenharmony_civoid finalize_exec(struct linux_binprm *bprm) 14548c2ecf20Sopenharmony_ci{ 14558c2ecf20Sopenharmony_ci /* Store any stack rlimit changes before starting thread. */ 14568c2ecf20Sopenharmony_ci task_lock(current->group_leader); 14578c2ecf20Sopenharmony_ci current->signal->rlim[RLIMIT_STACK] = bprm->rlim_stack; 14588c2ecf20Sopenharmony_ci task_unlock(current->group_leader); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(finalize_exec); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci/* 14638c2ecf20Sopenharmony_ci * Prepare credentials and lock ->cred_guard_mutex. 14648c2ecf20Sopenharmony_ci * setup_new_exec() commits the new creds and drops the lock. 14658c2ecf20Sopenharmony_ci * Or, if exec fails before, free_bprm() should release ->cred and 14668c2ecf20Sopenharmony_ci * and unlock. 14678c2ecf20Sopenharmony_ci */ 14688c2ecf20Sopenharmony_cistatic int prepare_bprm_creds(struct linux_binprm *bprm) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(¤t->signal->cred_guard_mutex)) 14718c2ecf20Sopenharmony_ci return -ERESTARTNOINTR; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci bprm->cred = prepare_exec_creds(); 14748c2ecf20Sopenharmony_ci if (likely(bprm->cred)) 14758c2ecf20Sopenharmony_ci return 0; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci mutex_unlock(¤t->signal->cred_guard_mutex); 14788c2ecf20Sopenharmony_ci return -ENOMEM; 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_cistatic void free_bprm(struct linux_binprm *bprm) 14828c2ecf20Sopenharmony_ci{ 14838c2ecf20Sopenharmony_ci if (bprm->mm) { 14848c2ecf20Sopenharmony_ci acct_arg_size(bprm, 0); 14858c2ecf20Sopenharmony_ci mmput(bprm->mm); 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci free_arg_pages(bprm); 14888c2ecf20Sopenharmony_ci if (bprm->cred) { 14898c2ecf20Sopenharmony_ci mutex_unlock(¤t->signal->cred_guard_mutex); 14908c2ecf20Sopenharmony_ci abort_creds(bprm->cred); 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci if (bprm->file) { 14938c2ecf20Sopenharmony_ci allow_write_access(bprm->file); 14948c2ecf20Sopenharmony_ci fput(bprm->file); 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci if (bprm->executable) 14978c2ecf20Sopenharmony_ci fput(bprm->executable); 14988c2ecf20Sopenharmony_ci /* If a binfmt changed the interp, free it. */ 14998c2ecf20Sopenharmony_ci if (bprm->interp != bprm->filename) 15008c2ecf20Sopenharmony_ci kfree(bprm->interp); 15018c2ecf20Sopenharmony_ci kfree(bprm->fdpath); 15028c2ecf20Sopenharmony_ci kfree(bprm); 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic struct linux_binprm *alloc_bprm(int fd, struct filename *filename) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci struct linux_binprm *bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); 15088c2ecf20Sopenharmony_ci int retval = -ENOMEM; 15098c2ecf20Sopenharmony_ci if (!bprm) 15108c2ecf20Sopenharmony_ci goto out; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (fd == AT_FDCWD || filename->name[0] == '/') { 15138c2ecf20Sopenharmony_ci bprm->filename = filename->name; 15148c2ecf20Sopenharmony_ci } else { 15158c2ecf20Sopenharmony_ci if (filename->name[0] == '\0') 15168c2ecf20Sopenharmony_ci bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d", fd); 15178c2ecf20Sopenharmony_ci else 15188c2ecf20Sopenharmony_ci bprm->fdpath = kasprintf(GFP_KERNEL, "/dev/fd/%d/%s", 15198c2ecf20Sopenharmony_ci fd, filename->name); 15208c2ecf20Sopenharmony_ci if (!bprm->fdpath) 15218c2ecf20Sopenharmony_ci goto out_free; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci bprm->filename = bprm->fdpath; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci bprm->interp = bprm->filename; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci retval = bprm_mm_init(bprm); 15288c2ecf20Sopenharmony_ci if (retval) 15298c2ecf20Sopenharmony_ci goto out_free; 15308c2ecf20Sopenharmony_ci return bprm; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ciout_free: 15338c2ecf20Sopenharmony_ci free_bprm(bprm); 15348c2ecf20Sopenharmony_ciout: 15358c2ecf20Sopenharmony_ci return ERR_PTR(retval); 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ciint bprm_change_interp(const char *interp, struct linux_binprm *bprm) 15398c2ecf20Sopenharmony_ci{ 15408c2ecf20Sopenharmony_ci /* If a binfmt changed the interp, free it first. */ 15418c2ecf20Sopenharmony_ci if (bprm->interp != bprm->filename) 15428c2ecf20Sopenharmony_ci kfree(bprm->interp); 15438c2ecf20Sopenharmony_ci bprm->interp = kstrdup(interp, GFP_KERNEL); 15448c2ecf20Sopenharmony_ci if (!bprm->interp) 15458c2ecf20Sopenharmony_ci return -ENOMEM; 15468c2ecf20Sopenharmony_ci return 0; 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bprm_change_interp); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci/* 15518c2ecf20Sopenharmony_ci * determine how safe it is to execute the proposed program 15528c2ecf20Sopenharmony_ci * - the caller must hold ->cred_guard_mutex to protect against 15538c2ecf20Sopenharmony_ci * PTRACE_ATTACH or seccomp thread-sync 15548c2ecf20Sopenharmony_ci */ 15558c2ecf20Sopenharmony_cistatic void check_unsafe_exec(struct linux_binprm *bprm) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci struct task_struct *p = current, *t; 15588c2ecf20Sopenharmony_ci unsigned n_fs; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (p->ptrace) 15618c2ecf20Sopenharmony_ci bprm->unsafe |= LSM_UNSAFE_PTRACE; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* 15648c2ecf20Sopenharmony_ci * This isn't strictly necessary, but it makes it harder for LSMs to 15658c2ecf20Sopenharmony_ci * mess up. 15668c2ecf20Sopenharmony_ci */ 15678c2ecf20Sopenharmony_ci if (task_no_new_privs(current)) 15688c2ecf20Sopenharmony_ci bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci t = p; 15718c2ecf20Sopenharmony_ci n_fs = 1; 15728c2ecf20Sopenharmony_ci spin_lock(&p->fs->lock); 15738c2ecf20Sopenharmony_ci rcu_read_lock(); 15748c2ecf20Sopenharmony_ci while_each_thread(p, t) { 15758c2ecf20Sopenharmony_ci if (t->fs == p->fs) 15768c2ecf20Sopenharmony_ci n_fs++; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci rcu_read_unlock(); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci if (p->fs->users > n_fs) 15818c2ecf20Sopenharmony_ci bprm->unsafe |= LSM_UNSAFE_SHARE; 15828c2ecf20Sopenharmony_ci else 15838c2ecf20Sopenharmony_ci p->fs->in_exec = 1; 15848c2ecf20Sopenharmony_ci spin_unlock(&p->fs->lock); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic void bprm_fill_uid(struct linux_binprm *bprm, struct file *file) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci /* Handle suid and sgid on files */ 15908c2ecf20Sopenharmony_ci struct inode *inode; 15918c2ecf20Sopenharmony_ci unsigned int mode; 15928c2ecf20Sopenharmony_ci kuid_t uid; 15938c2ecf20Sopenharmony_ci kgid_t gid; 15948c2ecf20Sopenharmony_ci int err; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (!mnt_may_suid(file->f_path.mnt)) 15978c2ecf20Sopenharmony_ci return; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if (task_no_new_privs(current)) 16008c2ecf20Sopenharmony_ci return; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci inode = file->f_path.dentry->d_inode; 16038c2ecf20Sopenharmony_ci mode = READ_ONCE(inode->i_mode); 16048c2ecf20Sopenharmony_ci if (!(mode & (S_ISUID|S_ISGID))) 16058c2ecf20Sopenharmony_ci return; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci /* Be careful if suid/sgid is set */ 16088c2ecf20Sopenharmony_ci inode_lock(inode); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci /* Atomically reload and check mode/uid/gid now that lock held. */ 16118c2ecf20Sopenharmony_ci mode = inode->i_mode; 16128c2ecf20Sopenharmony_ci uid = inode->i_uid; 16138c2ecf20Sopenharmony_ci gid = inode->i_gid; 16148c2ecf20Sopenharmony_ci err = inode_permission(inode, MAY_EXEC); 16158c2ecf20Sopenharmony_ci inode_unlock(inode); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci /* Did the exec bit vanish out from under us? Give up. */ 16188c2ecf20Sopenharmony_ci if (err) 16198c2ecf20Sopenharmony_ci return; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci /* We ignore suid/sgid if there are no mappings for them in the ns */ 16228c2ecf20Sopenharmony_ci if (!kuid_has_mapping(bprm->cred->user_ns, uid) || 16238c2ecf20Sopenharmony_ci !kgid_has_mapping(bprm->cred->user_ns, gid)) 16248c2ecf20Sopenharmony_ci return; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (mode & S_ISUID) { 16278c2ecf20Sopenharmony_ci bprm->per_clear |= PER_CLEAR_ON_SETID; 16288c2ecf20Sopenharmony_ci bprm->cred->euid = uid; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 16328c2ecf20Sopenharmony_ci bprm->per_clear |= PER_CLEAR_ON_SETID; 16338c2ecf20Sopenharmony_ci bprm->cred->egid = gid; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci/* 16388c2ecf20Sopenharmony_ci * Compute brpm->cred based upon the final binary. 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_cistatic int bprm_creds_from_file(struct linux_binprm *bprm) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci /* Compute creds based on which file? */ 16438c2ecf20Sopenharmony_ci struct file *file = bprm->execfd_creds ? bprm->executable : bprm->file; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci bprm_fill_uid(bprm, file); 16468c2ecf20Sopenharmony_ci return security_bprm_creds_from_file(bprm, file); 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci/* 16508c2ecf20Sopenharmony_ci * Fill the binprm structure from the inode. 16518c2ecf20Sopenharmony_ci * Read the first BINPRM_BUF_SIZE bytes 16528c2ecf20Sopenharmony_ci * 16538c2ecf20Sopenharmony_ci * This may be called multiple times for binary chains (scripts for example). 16548c2ecf20Sopenharmony_ci */ 16558c2ecf20Sopenharmony_cistatic int prepare_binprm(struct linux_binprm *bprm) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci loff_t pos = 0; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci memset(bprm->buf, 0, BINPRM_BUF_SIZE); 16608c2ecf20Sopenharmony_ci return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos); 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci/* 16648c2ecf20Sopenharmony_ci * Arguments are '\0' separated strings found at the location bprm->p 16658c2ecf20Sopenharmony_ci * points to; chop off the first by relocating brpm->p to right after 16668c2ecf20Sopenharmony_ci * the first '\0' encountered. 16678c2ecf20Sopenharmony_ci */ 16688c2ecf20Sopenharmony_ciint remove_arg_zero(struct linux_binprm *bprm) 16698c2ecf20Sopenharmony_ci{ 16708c2ecf20Sopenharmony_ci int ret = 0; 16718c2ecf20Sopenharmony_ci unsigned long offset; 16728c2ecf20Sopenharmony_ci char *kaddr; 16738c2ecf20Sopenharmony_ci struct page *page; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci if (!bprm->argc) 16768c2ecf20Sopenharmony_ci return 0; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci do { 16798c2ecf20Sopenharmony_ci offset = bprm->p & ~PAGE_MASK; 16808c2ecf20Sopenharmony_ci page = get_arg_page(bprm, bprm->p, 0); 16818c2ecf20Sopenharmony_ci if (!page) { 16828c2ecf20Sopenharmony_ci ret = -EFAULT; 16838c2ecf20Sopenharmony_ci goto out; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci kaddr = kmap_atomic(page); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci for (; offset < PAGE_SIZE && kaddr[offset]; 16888c2ecf20Sopenharmony_ci offset++, bprm->p++) 16898c2ecf20Sopenharmony_ci ; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 16928c2ecf20Sopenharmony_ci put_arg_page(page); 16938c2ecf20Sopenharmony_ci } while (offset == PAGE_SIZE); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci bprm->p++; 16968c2ecf20Sopenharmony_ci bprm->argc--; 16978c2ecf20Sopenharmony_ci ret = 0; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ciout: 17008c2ecf20Sopenharmony_ci return ret; 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(remove_arg_zero); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e)) 17058c2ecf20Sopenharmony_ci/* 17068c2ecf20Sopenharmony_ci * cycle the list of binary formats handler, until one recognizes the image 17078c2ecf20Sopenharmony_ci */ 17088c2ecf20Sopenharmony_cistatic int search_binary_handler(struct linux_binprm *bprm) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci bool need_retry = IS_ENABLED(CONFIG_MODULES); 17118c2ecf20Sopenharmony_ci struct linux_binfmt *fmt; 17128c2ecf20Sopenharmony_ci int retval; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci retval = prepare_binprm(bprm); 17158c2ecf20Sopenharmony_ci if (retval < 0) 17168c2ecf20Sopenharmony_ci return retval; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci retval = security_bprm_check(bprm); 17198c2ecf20Sopenharmony_ci if (retval) 17208c2ecf20Sopenharmony_ci return retval; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci retval = -ENOENT; 17238c2ecf20Sopenharmony_ci retry: 17248c2ecf20Sopenharmony_ci read_lock(&binfmt_lock); 17258c2ecf20Sopenharmony_ci list_for_each_entry(fmt, &formats, lh) { 17268c2ecf20Sopenharmony_ci if (!try_module_get(fmt->module)) 17278c2ecf20Sopenharmony_ci continue; 17288c2ecf20Sopenharmony_ci read_unlock(&binfmt_lock); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci retval = fmt->load_binary(bprm); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci read_lock(&binfmt_lock); 17338c2ecf20Sopenharmony_ci put_binfmt(fmt); 17348c2ecf20Sopenharmony_ci if (bprm->point_of_no_return || (retval != -ENOEXEC)) { 17358c2ecf20Sopenharmony_ci read_unlock(&binfmt_lock); 17368c2ecf20Sopenharmony_ci return retval; 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci read_unlock(&binfmt_lock); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci if (need_retry) { 17428c2ecf20Sopenharmony_ci if (printable(bprm->buf[0]) && printable(bprm->buf[1]) && 17438c2ecf20Sopenharmony_ci printable(bprm->buf[2]) && printable(bprm->buf[3])) 17448c2ecf20Sopenharmony_ci return retval; 17458c2ecf20Sopenharmony_ci if (request_module("binfmt-%04x", *(ushort *)(bprm->buf + 2)) < 0) 17468c2ecf20Sopenharmony_ci return retval; 17478c2ecf20Sopenharmony_ci need_retry = false; 17488c2ecf20Sopenharmony_ci goto retry; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci return retval; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic int exec_binprm(struct linux_binprm *bprm) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci pid_t old_pid, old_vpid; 17578c2ecf20Sopenharmony_ci int ret, depth; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci /* Need to fetch pid before load_binary changes it */ 17608c2ecf20Sopenharmony_ci old_pid = current->pid; 17618c2ecf20Sopenharmony_ci rcu_read_lock(); 17628c2ecf20Sopenharmony_ci old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent)); 17638c2ecf20Sopenharmony_ci rcu_read_unlock(); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* This allows 4 levels of binfmt rewrites before failing hard. */ 17668c2ecf20Sopenharmony_ci for (depth = 0;; depth++) { 17678c2ecf20Sopenharmony_ci struct file *exec; 17688c2ecf20Sopenharmony_ci if (depth > 5) 17698c2ecf20Sopenharmony_ci return -ELOOP; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci ret = search_binary_handler(bprm); 17728c2ecf20Sopenharmony_ci if (ret < 0) 17738c2ecf20Sopenharmony_ci return ret; 17748c2ecf20Sopenharmony_ci if (!bprm->interpreter) 17758c2ecf20Sopenharmony_ci break; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci exec = bprm->file; 17788c2ecf20Sopenharmony_ci bprm->file = bprm->interpreter; 17798c2ecf20Sopenharmony_ci bprm->interpreter = NULL; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci allow_write_access(exec); 17828c2ecf20Sopenharmony_ci if (unlikely(bprm->have_execfd)) { 17838c2ecf20Sopenharmony_ci if (bprm->executable) { 17848c2ecf20Sopenharmony_ci fput(exec); 17858c2ecf20Sopenharmony_ci return -ENOEXEC; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci bprm->executable = exec; 17888c2ecf20Sopenharmony_ci } else 17898c2ecf20Sopenharmony_ci fput(exec); 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci audit_bprm(bprm); 17938c2ecf20Sopenharmony_ci trace_sched_process_exec(current, old_pid, bprm); 17948c2ecf20Sopenharmony_ci ptrace_event(PTRACE_EVENT_EXEC, old_vpid); 17958c2ecf20Sopenharmony_ci proc_exec_connector(current); 17968c2ecf20Sopenharmony_ci return 0; 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci/* 18008c2ecf20Sopenharmony_ci * sys_execve() executes a new program. 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_cistatic int bprm_execve(struct linux_binprm *bprm, 18038c2ecf20Sopenharmony_ci int fd, struct filename *filename, int flags) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci struct file *file; 18068c2ecf20Sopenharmony_ci int retval; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci /* 18098c2ecf20Sopenharmony_ci * Cancel any io_uring activity across execve 18108c2ecf20Sopenharmony_ci */ 18118c2ecf20Sopenharmony_ci io_uring_task_cancel(); 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci retval = prepare_bprm_creds(bprm); 18148c2ecf20Sopenharmony_ci if (retval) 18158c2ecf20Sopenharmony_ci return retval; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci check_unsafe_exec(bprm); 18188c2ecf20Sopenharmony_ci current->in_execve = 1; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci file = do_open_execat(fd, filename, flags); 18218c2ecf20Sopenharmony_ci retval = PTR_ERR(file); 18228c2ecf20Sopenharmony_ci if (IS_ERR(file)) 18238c2ecf20Sopenharmony_ci goto out_unmark; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci sched_exec(); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci bprm->file = file; 18288c2ecf20Sopenharmony_ci /* 18298c2ecf20Sopenharmony_ci * Record that a name derived from an O_CLOEXEC fd will be 18308c2ecf20Sopenharmony_ci * inaccessible after exec. This allows the code in exec to 18318c2ecf20Sopenharmony_ci * choose to fail when the executable is not mmaped into the 18328c2ecf20Sopenharmony_ci * interpreter and an open file descriptor is not passed to 18338c2ecf20Sopenharmony_ci * the interpreter. This makes for a better user experience 18348c2ecf20Sopenharmony_ci * than having the interpreter start and then immediately fail 18358c2ecf20Sopenharmony_ci * when it finds the executable is inaccessible. 18368c2ecf20Sopenharmony_ci */ 18378c2ecf20Sopenharmony_ci if (bprm->fdpath && get_close_on_exec(fd)) 18388c2ecf20Sopenharmony_ci bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci /* Set the unchanging part of bprm->cred */ 18418c2ecf20Sopenharmony_ci retval = security_bprm_creds_for_exec(bprm); 18428c2ecf20Sopenharmony_ci if (retval) 18438c2ecf20Sopenharmony_ci goto out; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci retval = exec_binprm(bprm); 18468c2ecf20Sopenharmony_ci if (retval < 0) 18478c2ecf20Sopenharmony_ci goto out; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci /* execve succeeded */ 18508c2ecf20Sopenharmony_ci current->fs->in_exec = 0; 18518c2ecf20Sopenharmony_ci current->in_execve = 0; 18528c2ecf20Sopenharmony_ci rseq_execve(current); 18538c2ecf20Sopenharmony_ci acct_update_integrals(current); 18548c2ecf20Sopenharmony_ci task_numa_free(current, false); 18558c2ecf20Sopenharmony_ci CALL_HCK_LITE_HOOK(ced_detection_lhck, current); 18568c2ecf20Sopenharmony_ci return retval; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ciout: 18598c2ecf20Sopenharmony_ci /* 18608c2ecf20Sopenharmony_ci * If past the point of no return ensure the the code never 18618c2ecf20Sopenharmony_ci * returns to the userspace process. Use an existing fatal 18628c2ecf20Sopenharmony_ci * signal if present otherwise terminate the process with 18638c2ecf20Sopenharmony_ci * SIGSEGV. 18648c2ecf20Sopenharmony_ci */ 18658c2ecf20Sopenharmony_ci if (bprm->point_of_no_return && !fatal_signal_pending(current)) 18668c2ecf20Sopenharmony_ci force_sigsegv(SIGSEGV); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ciout_unmark: 18698c2ecf20Sopenharmony_ci current->fs->in_exec = 0; 18708c2ecf20Sopenharmony_ci current->in_execve = 0; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci return retval; 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_cistatic int do_execveat_common(int fd, struct filename *filename, 18768c2ecf20Sopenharmony_ci struct user_arg_ptr argv, 18778c2ecf20Sopenharmony_ci struct user_arg_ptr envp, 18788c2ecf20Sopenharmony_ci int flags) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci struct linux_binprm *bprm; 18818c2ecf20Sopenharmony_ci int retval; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (IS_ERR(filename)) 18848c2ecf20Sopenharmony_ci return PTR_ERR(filename); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci /* 18878c2ecf20Sopenharmony_ci * We move the actual failure in case of RLIMIT_NPROC excess from 18888c2ecf20Sopenharmony_ci * set*uid() to execve() because too many poorly written programs 18898c2ecf20Sopenharmony_ci * don't check setuid() return code. Here we additionally recheck 18908c2ecf20Sopenharmony_ci * whether NPROC limit is still exceeded. 18918c2ecf20Sopenharmony_ci */ 18928c2ecf20Sopenharmony_ci if ((current->flags & PF_NPROC_EXCEEDED) && 18938c2ecf20Sopenharmony_ci atomic_read(¤t_user()->processes) > rlimit(RLIMIT_NPROC)) { 18948c2ecf20Sopenharmony_ci retval = -EAGAIN; 18958c2ecf20Sopenharmony_ci goto out_ret; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci /* We're below the limit (still or again), so we don't want to make 18998c2ecf20Sopenharmony_ci * further execve() calls fail. */ 19008c2ecf20Sopenharmony_ci current->flags &= ~PF_NPROC_EXCEEDED; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci bprm = alloc_bprm(fd, filename); 19038c2ecf20Sopenharmony_ci if (IS_ERR(bprm)) { 19048c2ecf20Sopenharmony_ci retval = PTR_ERR(bprm); 19058c2ecf20Sopenharmony_ci goto out_ret; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci retval = count(argv, MAX_ARG_STRINGS); 19098c2ecf20Sopenharmony_ci if (retval == 0) 19108c2ecf20Sopenharmony_ci pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n", 19118c2ecf20Sopenharmony_ci current->comm, bprm->filename); 19128c2ecf20Sopenharmony_ci if (retval < 0) 19138c2ecf20Sopenharmony_ci goto out_free; 19148c2ecf20Sopenharmony_ci bprm->argc = retval; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci retval = count(envp, MAX_ARG_STRINGS); 19178c2ecf20Sopenharmony_ci if (retval < 0) 19188c2ecf20Sopenharmony_ci goto out_free; 19198c2ecf20Sopenharmony_ci bprm->envc = retval; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci retval = bprm_stack_limits(bprm); 19228c2ecf20Sopenharmony_ci if (retval < 0) 19238c2ecf20Sopenharmony_ci goto out_free; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci retval = copy_string_kernel(bprm->filename, bprm); 19268c2ecf20Sopenharmony_ci if (retval < 0) 19278c2ecf20Sopenharmony_ci goto out_free; 19288c2ecf20Sopenharmony_ci bprm->exec = bprm->p; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci retval = copy_strings(bprm->envc, envp, bprm); 19318c2ecf20Sopenharmony_ci if (retval < 0) 19328c2ecf20Sopenharmony_ci goto out_free; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci retval = copy_strings(bprm->argc, argv, bprm); 19358c2ecf20Sopenharmony_ci if (retval < 0) 19368c2ecf20Sopenharmony_ci goto out_free; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci /* 19398c2ecf20Sopenharmony_ci * When argv is empty, add an empty string ("") as argv[0] to 19408c2ecf20Sopenharmony_ci * ensure confused userspace programs that start processing 19418c2ecf20Sopenharmony_ci * from argv[1] won't end up walking envp. See also 19428c2ecf20Sopenharmony_ci * bprm_stack_limits(). 19438c2ecf20Sopenharmony_ci */ 19448c2ecf20Sopenharmony_ci if (bprm->argc == 0) { 19458c2ecf20Sopenharmony_ci retval = copy_string_kernel("", bprm); 19468c2ecf20Sopenharmony_ci if (retval < 0) 19478c2ecf20Sopenharmony_ci goto out_free; 19488c2ecf20Sopenharmony_ci bprm->argc = 1; 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci retval = bprm_execve(bprm, fd, filename, flags); 19528c2ecf20Sopenharmony_ciout_free: 19538c2ecf20Sopenharmony_ci free_bprm(bprm); 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ciout_ret: 19568c2ecf20Sopenharmony_ci putname(filename); 19578c2ecf20Sopenharmony_ci return retval; 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ciint kernel_execve(const char *kernel_filename, 19618c2ecf20Sopenharmony_ci const char *const *argv, const char *const *envp) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci struct filename *filename; 19648c2ecf20Sopenharmony_ci struct linux_binprm *bprm; 19658c2ecf20Sopenharmony_ci int fd = AT_FDCWD; 19668c2ecf20Sopenharmony_ci int retval; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci filename = getname_kernel(kernel_filename); 19698c2ecf20Sopenharmony_ci if (IS_ERR(filename)) 19708c2ecf20Sopenharmony_ci return PTR_ERR(filename); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci bprm = alloc_bprm(fd, filename); 19738c2ecf20Sopenharmony_ci if (IS_ERR(bprm)) { 19748c2ecf20Sopenharmony_ci retval = PTR_ERR(bprm); 19758c2ecf20Sopenharmony_ci goto out_ret; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci retval = count_strings_kernel(argv); 19798c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(retval == 0)) 19808c2ecf20Sopenharmony_ci retval = -EINVAL; 19818c2ecf20Sopenharmony_ci if (retval < 0) 19828c2ecf20Sopenharmony_ci goto out_free; 19838c2ecf20Sopenharmony_ci bprm->argc = retval; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci retval = count_strings_kernel(envp); 19868c2ecf20Sopenharmony_ci if (retval < 0) 19878c2ecf20Sopenharmony_ci goto out_free; 19888c2ecf20Sopenharmony_ci bprm->envc = retval; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci retval = bprm_stack_limits(bprm); 19918c2ecf20Sopenharmony_ci if (retval < 0) 19928c2ecf20Sopenharmony_ci goto out_free; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci retval = copy_string_kernel(bprm->filename, bprm); 19958c2ecf20Sopenharmony_ci if (retval < 0) 19968c2ecf20Sopenharmony_ci goto out_free; 19978c2ecf20Sopenharmony_ci bprm->exec = bprm->p; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci retval = copy_strings_kernel(bprm->envc, envp, bprm); 20008c2ecf20Sopenharmony_ci if (retval < 0) 20018c2ecf20Sopenharmony_ci goto out_free; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci retval = copy_strings_kernel(bprm->argc, argv, bprm); 20048c2ecf20Sopenharmony_ci if (retval < 0) 20058c2ecf20Sopenharmony_ci goto out_free; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci retval = bprm_execve(bprm, fd, filename, 0); 20088c2ecf20Sopenharmony_ciout_free: 20098c2ecf20Sopenharmony_ci free_bprm(bprm); 20108c2ecf20Sopenharmony_ciout_ret: 20118c2ecf20Sopenharmony_ci putname(filename); 20128c2ecf20Sopenharmony_ci return retval; 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_cistatic int do_execve(struct filename *filename, 20168c2ecf20Sopenharmony_ci const char __user *const __user *__argv, 20178c2ecf20Sopenharmony_ci const char __user *const __user *__envp) 20188c2ecf20Sopenharmony_ci{ 20198c2ecf20Sopenharmony_ci struct user_arg_ptr argv = { .ptr.native = __argv }; 20208c2ecf20Sopenharmony_ci struct user_arg_ptr envp = { .ptr.native = __envp }; 20218c2ecf20Sopenharmony_ci return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic int do_execveat(int fd, struct filename *filename, 20258c2ecf20Sopenharmony_ci const char __user *const __user *__argv, 20268c2ecf20Sopenharmony_ci const char __user *const __user *__envp, 20278c2ecf20Sopenharmony_ci int flags) 20288c2ecf20Sopenharmony_ci{ 20298c2ecf20Sopenharmony_ci struct user_arg_ptr argv = { .ptr.native = __argv }; 20308c2ecf20Sopenharmony_ci struct user_arg_ptr envp = { .ptr.native = __envp }; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci return do_execveat_common(fd, filename, argv, envp, flags); 20338c2ecf20Sopenharmony_ci} 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 20368c2ecf20Sopenharmony_cistatic int compat_do_execve(struct filename *filename, 20378c2ecf20Sopenharmony_ci const compat_uptr_t __user *__argv, 20388c2ecf20Sopenharmony_ci const compat_uptr_t __user *__envp) 20398c2ecf20Sopenharmony_ci{ 20408c2ecf20Sopenharmony_ci struct user_arg_ptr argv = { 20418c2ecf20Sopenharmony_ci .is_compat = true, 20428c2ecf20Sopenharmony_ci .ptr.compat = __argv, 20438c2ecf20Sopenharmony_ci }; 20448c2ecf20Sopenharmony_ci struct user_arg_ptr envp = { 20458c2ecf20Sopenharmony_ci .is_compat = true, 20468c2ecf20Sopenharmony_ci .ptr.compat = __envp, 20478c2ecf20Sopenharmony_ci }; 20488c2ecf20Sopenharmony_ci return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cistatic int compat_do_execveat(int fd, struct filename *filename, 20528c2ecf20Sopenharmony_ci const compat_uptr_t __user *__argv, 20538c2ecf20Sopenharmony_ci const compat_uptr_t __user *__envp, 20548c2ecf20Sopenharmony_ci int flags) 20558c2ecf20Sopenharmony_ci{ 20568c2ecf20Sopenharmony_ci struct user_arg_ptr argv = { 20578c2ecf20Sopenharmony_ci .is_compat = true, 20588c2ecf20Sopenharmony_ci .ptr.compat = __argv, 20598c2ecf20Sopenharmony_ci }; 20608c2ecf20Sopenharmony_ci struct user_arg_ptr envp = { 20618c2ecf20Sopenharmony_ci .is_compat = true, 20628c2ecf20Sopenharmony_ci .ptr.compat = __envp, 20638c2ecf20Sopenharmony_ci }; 20648c2ecf20Sopenharmony_ci return do_execveat_common(fd, filename, argv, envp, flags); 20658c2ecf20Sopenharmony_ci} 20668c2ecf20Sopenharmony_ci#endif 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_civoid set_binfmt(struct linux_binfmt *new) 20698c2ecf20Sopenharmony_ci{ 20708c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if (mm->binfmt) 20738c2ecf20Sopenharmony_ci module_put(mm->binfmt->module); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci mm->binfmt = new; 20768c2ecf20Sopenharmony_ci if (new) 20778c2ecf20Sopenharmony_ci __module_get(new->module); 20788c2ecf20Sopenharmony_ci} 20798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(set_binfmt); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci/* 20828c2ecf20Sopenharmony_ci * set_dumpable stores three-value SUID_DUMP_* into mm->flags. 20838c2ecf20Sopenharmony_ci */ 20848c2ecf20Sopenharmony_civoid set_dumpable(struct mm_struct *mm, int value) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci if (WARN_ON((unsigned)value > SUID_DUMP_ROOT)) 20878c2ecf20Sopenharmony_ci return; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci set_mask_bits(&mm->flags, MMF_DUMPABLE_MASK, value); 20908c2ecf20Sopenharmony_ci} 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ciSYSCALL_DEFINE3(execve, 20938c2ecf20Sopenharmony_ci const char __user *, filename, 20948c2ecf20Sopenharmony_ci const char __user *const __user *, argv, 20958c2ecf20Sopenharmony_ci const char __user *const __user *, envp) 20968c2ecf20Sopenharmony_ci{ 20978c2ecf20Sopenharmony_ci return do_execve(getname(filename), argv, envp); 20988c2ecf20Sopenharmony_ci} 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ciSYSCALL_DEFINE5(execveat, 21018c2ecf20Sopenharmony_ci int, fd, const char __user *, filename, 21028c2ecf20Sopenharmony_ci const char __user *const __user *, argv, 21038c2ecf20Sopenharmony_ci const char __user *const __user *, envp, 21048c2ecf20Sopenharmony_ci int, flags) 21058c2ecf20Sopenharmony_ci{ 21068c2ecf20Sopenharmony_ci int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci return do_execveat(fd, 21098c2ecf20Sopenharmony_ci getname_flags(filename, lookup_flags, NULL), 21108c2ecf20Sopenharmony_ci argv, envp, flags); 21118c2ecf20Sopenharmony_ci} 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 21148c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, 21158c2ecf20Sopenharmony_ci const compat_uptr_t __user *, argv, 21168c2ecf20Sopenharmony_ci const compat_uptr_t __user *, envp) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci return compat_do_execve(getname(filename), argv, envp); 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(execveat, int, fd, 21228c2ecf20Sopenharmony_ci const char __user *, filename, 21238c2ecf20Sopenharmony_ci const compat_uptr_t __user *, argv, 21248c2ecf20Sopenharmony_ci const compat_uptr_t __user *, envp, 21258c2ecf20Sopenharmony_ci int, flags) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci return compat_do_execveat(fd, 21308c2ecf20Sopenharmony_ci getname_flags(filename, lookup_flags, NULL), 21318c2ecf20Sopenharmony_ci argv, envp, flags); 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ci#endif 2134