diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index c33bbfdc5f..de2c3b5133 100644 --- a/components/lwp/lwp.c +++ b/components/lwp/lwp.c @@ -56,8 +56,6 @@ #define O_BINARY 0x10000 #endif - -static const char elf_magic[] = {0x7f, 'E', 'L', 'F'}; #ifdef DFS_USING_WORKDIR extern char working_directory[]; #endif @@ -245,893 +243,6 @@ uint32_t *lwp_get_kernel_sp(void) #endif } -#ifdef ARCH_MM_MMU -struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp) -{ - int size = sizeof(size_t) * 5; /* store argc, argv, envp, aux, NULL */ - int *args; - char *str; - char *str_k; - char **new_argve; - int i; - int len; - size_t *args_k; - struct process_aux *aux; - size_t prot = PROT_READ | PROT_WRITE; - size_t flags = MAP_FIXED | MAP_PRIVATE; - size_t zero = 0; - - for (i = 0; i < argc; i++) - { - size += (rt_strlen(argv[i]) + 1); - } - size += (sizeof(size_t) * argc); - - i = 0; - if (envp) - { - while (envp[i] != 0) - { - size += (rt_strlen(envp[i]) + 1); - size += sizeof(size_t); - i++; - } - } - - /* for aux */ - size += sizeof(struct process_aux); - - if (size > ARCH_PAGE_SIZE) - { - return RT_NULL; - } - - args = lwp_mmap2(lwp, (void *)(USER_STACK_VEND), size, prot, flags, -1, 0); - if (args == RT_NULL || lwp_data_put(lwp, args, &zero, sizeof(zero)) != sizeof(zero)) - { - return RT_NULL; - } - - args_k = (size_t *)lwp_v2p(lwp, args); - args_k = (size_t *)((size_t)args_k - PV_OFFSET); - - /* argc, argv[], 0, envp[], 0 , aux[] */ - str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(size_t)); - str_k = (char *)((size_t)args_k + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(size_t)); - - new_argve = (char **)&args_k[1]; - args_k[0] = argc; - - for (i = 0; i < argc; i++) - { - len = rt_strlen(argv[i]) + 1; - new_argve[i] = str; - lwp_memcpy(str_k, argv[i], len); - str += len; - str_k += len; - } - new_argve[i] = 0; - i++; - - new_argve[i] = 0; - if (envp) - { - int j; - - for (j = 0; envp[j] != 0; j++) - { - len = rt_strlen(envp[j]) + 1; - new_argve[i] = str; - lwp_memcpy(str_k, envp[j], len); - str += len; - str_k += len; - i++; - } - new_argve[i] = 0; - } - i++; - - /* aux */ - aux = (struct process_aux *)(new_argve + i); - aux->item[0].key = AT_EXECFN; - aux->item[0].value = (size_t)(size_t)new_argve[0]; - i += AUX_ARRAY_ITEMS_NR * 2; - new_argve[i] = 0; - - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, args_k, size); - - lwp->args = args; - - return aux; -} -#else -static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp) -{ -#ifdef ARCH_MM_MMU - int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */ - struct process_aux *aux; -#else - int size = sizeof(int) * 4; /* store argc, argv, envp, NULL */ -#endif /* ARCH_MM_MMU */ - int *args; - char *str; - char **new_argve; - int i; - int len; - - for (i = 0; i < argc; i++) - { - size += (rt_strlen(argv[i]) + 1); - } - size += (sizeof(int) * argc); - - i = 0; - if (envp) - { - while (envp[i] != 0) - { - size += (rt_strlen(envp[i]) + 1); - size += sizeof(int); - i++; - } - } - -#ifdef ARCH_MM_MMU - /* for aux */ - size += sizeof(struct process_aux); - - args = (int *)rt_malloc(size); - if (args == RT_NULL) - { - return RT_NULL; - } - - /* argc, argv[], 0, envp[], 0 */ - str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int)); -#else - args = (int *)rt_malloc(size); - if (args == RT_NULL) - { - return RT_NULL; - } - str = (char*)((int)args + (argc + 2 + i + 1) * sizeof(int)); -#endif /* ARCH_MM_MMU */ - - new_argve = (char **)&args[1]; - args[0] = argc; - - for (i = 0; i < argc; i++) - { - len = rt_strlen(argv[i]) + 1; - new_argve[i] = str; - lwp_memcpy(str, argv[i], len); - str += len; - } - new_argve[i] = 0; - i++; - - new_argve[i] = 0; - if (envp) - { - int j; - for (j = 0; envp[j] != 0; j++) - { - len = rt_strlen(envp[j]) + 1; - new_argve[i] = str; - lwp_memcpy(str, envp[j], len); - str += len; - i++; - } - new_argve[i] = 0; - } -#ifdef ARCH_MM_MMU - /* aux */ - aux = (struct process_aux *)(new_argve + i); - aux->item[0].key = AT_EXECFN; - aux->item[0].value = (uint32_t)(size_t)new_argve[0]; - i += AUX_ARRAY_ITEMS_NR * 2; - new_argve[i] = 0; - - lwp->args = args; - - return aux; -#else - lwp->args = args; - lwp->args_length = size; - - return (struct process_aux *)(new_argve + i); -#endif /* ARCH_MM_MMU */ -} -#endif - -#ifdef ARCH_MM_MMU -#define check_off(voff, vlen) \ - do \ - { \ - if (voff > vlen) \ - { \ - result = -RT_ERROR; \ - goto _exit; \ - } \ - } while (0) - -#define check_read(vrlen, vrlen_want) \ - do \ - { \ - if (vrlen < vrlen_want) \ - { \ - result = -RT_ERROR; \ - goto _exit; \ - } \ - } while (0) - -static size_t load_fread(void *ptr, size_t size, size_t nmemb, int fd) -{ - size_t read_block = 0; - - while (nmemb) - { - size_t count; - - count = read(fd, ptr, size * nmemb) / size; - if (count < nmemb) - { - LOG_E("ERROR: file size error!"); - break; - } - - ptr = (void *)((uint8_t *)ptr + (count * size)); - nmemb -= count; - read_block += count; - } - - return read_block; -} - -typedef struct -{ - Elf_Word st_name; - Elf_Addr st_value; - Elf_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf_Half st_shndx; -} Elf_sym; - -#ifdef ARCH_MM_MMU -struct map_range -{ - void *start; - size_t size; -}; - -static void expand_map_range(struct map_range *m, void *start, size_t size) -{ - if (!m->start) - { - m->start = start; - m->size = size; - } - else - { - void *end = (void *)((char*)start + size); - void *mend = (void *)((char*)m->start + m->size); - - if (m->start > start) - { - m->start = start; - } - if (mend < end) - { - mend = end; - } - m->size = (char *)mend - (char *)m->start; - } -} - -static int map_range_ckeck(struct map_range *m1, struct map_range *m2) -{ - void *m1_start = (void *)((size_t)m1->start & ~ARCH_PAGE_MASK); - void *m1_end = (void *)((((size_t)m1->start + m1->size) + ARCH_PAGE_MASK) & ~ARCH_PAGE_MASK); - void *m2_start = (void *)((size_t)m2->start & ~ARCH_PAGE_MASK); - void *m2_end = (void *)((((size_t)m2->start + m2->size) + ARCH_PAGE_MASK) & ~ARCH_PAGE_MASK); - - if (m1->size) - { - if (m1_start < (void *)USER_LOAD_VADDR) - { - return -1; - } - if (m1_start > (void *)USER_STACK_VSTART) - { - return -1; - } - if (m1_end < (void *)USER_LOAD_VADDR) - { - return -1; - } - if (m1_end > (void *)USER_STACK_VSTART) - { - return -1; - } - } - if (m2->size) - { - if (m2_start < (void *)USER_LOAD_VADDR) - { - return -1; - } - if (m2_start > (void *)USER_STACK_VSTART) - { - return -1; - } - if (m2_end < (void *)USER_LOAD_VADDR) - { - return -1; - } - if (m2_end > (void *)USER_STACK_VSTART) - { - return -1; - } - } - - if ((m1->size != 0) && (m2->size != 0)) - { - if (m1_start < m2_start) - { - if (m1_end > m2_start) - { - return -1; - } - } - else /* m2_start <= m1_start */ - { - if (m2_end > m1_start) - { - return -1; - } - } - } - return 0; -} -#endif - -static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, struct process_aux *aux) -{ - uint32_t i; - uint32_t off = 0; - size_t load_off = 0; - char *p_section_str = 0; - Elf_sym *dynsym = 0; - Elf_Ehdr eheader; - Elf_Phdr pheader; - Elf_Shdr sheader; - int result = RT_EOK; - uint32_t magic; - size_t read_len; - void *got_start = 0; - size_t got_size = 0; - void *rel_dyn_start = 0; - size_t rel_dyn_size = 0; - size_t dynsym_off = 0; - size_t dynsym_size = 0; -#ifdef ARCH_MM_MMU - struct map_range user_area[2] = {{NULL, 0}, {NULL, 0}}; /* 0 is text, 1 is data */ - void *pa, *va; - void *va_self; - -#endif - - if (len < sizeof eheader) - { - LOG_E("len < sizeof eheader!"); - return -RT_ERROR; - } - - lseek(fd, 0, SEEK_SET); - read_len = load_fread(&magic, 1, sizeof magic, fd); - check_read(read_len, sizeof magic); - - if (memcmp(elf_magic, &magic, 4) != 0) - { - LOG_E("elf_magic not same, magic:0x%x!", magic); - return -RT_ERROR; - } - - lseek(fd, off, SEEK_SET); - read_len = load_fread(&eheader, 1, sizeof eheader, fd); - check_read(read_len, sizeof eheader); - -#ifndef ARCH_CPU_64BIT - if (eheader.e_ident[4] != 1) - { /* not 32bit */ - LOG_E("elf not 32bit, %d!", eheader.e_ident[4]); - return -RT_ERROR; - } -#else - if (eheader.e_ident[4] != 2) - { /* not 64bit */ - LOG_E("elf not 64bit, %d!", eheader.e_ident[4]); - return -RT_ERROR; - } -#endif - - if (eheader.e_ident[6] != 1) - { /* ver not 1 */ - LOG_E("elf Version not 1,ver:%d!", eheader.e_ident[6]); - return -RT_ERROR; - } - - if ((eheader.e_type != ET_DYN) -#ifdef ARCH_MM_MMU - && (eheader.e_type != ET_EXEC) -#endif - ) - { - /* not pie or exec elf */ - LOG_E("elf type not pie or exec, type:%d!", eheader.e_type); - return -RT_ERROR; - } - -#ifdef ARCH_MM_MMU - { - off = eheader.e_phoff; - for (i = 0; i < eheader.e_phnum; i++, off += sizeof pheader) - { - check_off(off, len); - lseek(fd, off, SEEK_SET); - read_len = load_fread(&pheader, 1, sizeof pheader, fd); - check_read(read_len, sizeof pheader); - - if (pheader.p_type == PT_DYNAMIC) - { - /* load ld.so */ - return 1; /* 1 means dynamic */ - } - } - } -#endif - - if (eheader.e_entry != 0) - { - if ((eheader.e_entry != USER_LOAD_VADDR) - && (eheader.e_entry != LDSO_LOAD_VADDR)) - { - /* the entry is invalidate */ - LOG_E("elf entry is invalidate, entry:0x%x!", eheader.e_entry); - return -RT_ERROR; - } - } - - { /* load aux */ - uint8_t *process_header; - size_t process_header_size; - - off = eheader.e_phoff; - process_header_size = eheader.e_phnum * sizeof pheader; -#ifdef ARCH_MM_MMU - if (process_header_size > ARCH_PAGE_SIZE - sizeof(char[16])) - { - LOG_E("process_header_size too big, size:0x%x!", process_header_size); - return -RT_ERROR; - } - va = (uint8_t *)lwp_map_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), process_header_size, 0); - if (!va) - { - LOG_E("lwp map user failed!"); - return -RT_ERROR; - } - pa = lwp_v2p(lwp, va); - process_header = (uint8_t *)pa - PV_OFFSET; -#else - process_header = (uint8_t *)rt_malloc(process_header_size + sizeof(char[16])); - if (!process_header) - { - LOG_E("process_header malloc failed, size:0x%x!", process_header_size + sizeof(char[16])); - return -RT_ERROR; - } -#endif - check_off(off, len); - lseek(fd, off, SEEK_SET); - read_len = load_fread(process_header, 1, process_header_size, fd); - check_read(read_len, process_header_size); -#ifdef ARCH_MM_MMU - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, process_header, process_header_size); -#endif - - aux->item[1].key = AT_PAGESZ; -#ifdef ARCH_MM_MMU - aux->item[1].value = ARCH_PAGE_SIZE; -#else - aux->item[1].value = RT_MM_PAGE_SIZE; -#endif - aux->item[2].key = AT_RANDOM; - { - uint32_t random_value = rt_tick_get(); - uint8_t *random; -#ifdef ARCH_MM_MMU - uint8_t *krandom; - - random = (uint8_t *)(USER_VADDR_TOP - ARCH_PAGE_SIZE - sizeof(char[16])); - - krandom = (uint8_t *)lwp_v2p(lwp, random); - krandom = (uint8_t *)krandom - PV_OFFSET; - rt_memcpy(krandom, &random_value, sizeof random_value); -#else - random = (uint8_t *)(process_header + process_header_size); - rt_memcpy(random, &random_value, sizeof random_value); -#endif - aux->item[2].value = (size_t)random; - } - aux->item[3].key = AT_PHDR; -#ifdef ARCH_MM_MMU - aux->item[3].value = (size_t)va; -#else - aux->item[3].value = (size_t)process_header; -#endif - aux->item[4].key = AT_PHNUM; - aux->item[4].value = eheader.e_phnum; - aux->item[5].key = AT_PHENT; - aux->item[5].value = sizeof pheader; -#ifdef ARCH_MM_MMU - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, aux, sizeof *aux); -#endif - } - - if (load_addr) - { - load_off = (size_t)load_addr; - } -#ifdef ARCH_MM_MMU - else - { - /* map user */ - off = eheader.e_shoff; - for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader) - { - check_off(off, len); - lseek(fd, off, SEEK_SET); - read_len = load_fread(&sheader, 1, sizeof sheader, fd); - check_read(read_len, sizeof sheader); - - if ((sheader.sh_flags & SHF_ALLOC) == 0) - { - continue; - } - - switch (sheader.sh_type) - { - case SHT_PROGBITS: - if ((sheader.sh_flags & SHF_WRITE) == 0) - { - expand_map_range(&user_area[0], (void *)sheader.sh_addr, sheader.sh_size); - } - else - { - expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size); - } - break; - case SHT_NOBITS: - expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size); - break; - default: - expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size); - break; - } - } - - if (user_area[0].size == 0) - { - /* no code */ - result = -RT_ERROR; - goto _exit; - } - - if (user_area[0].start == NULL) - { - /* DYN */ - load_off = USER_LOAD_VADDR; - user_area[0].start = (void *)((char*)user_area[0].start + load_off); - user_area[1].start = (void *)((char*)user_area[1].start + load_off); - } - - if (map_range_ckeck(&user_area[0], &user_area[1]) != 0) - { - result = -RT_ERROR; - goto _exit; - } - - /* text and data */ - for (i = 0; i < 2; i++) - { - if (user_area[i].size != 0) - { - va = lwp_map_user(lwp, user_area[i].start, user_area[i].size, (i == 0)); - if (!va || (va != user_area[i].start)) - { - result = -RT_ERROR; - goto _exit; - } - } - } - lwp->text_size = user_area[0].size; - } -#else - else - { - size_t start = -1UL; - size_t end = 0UL; - size_t total_size; - - off = eheader.e_shoff; - for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader) - { - check_off(off, len); - lseek(fd, off, SEEK_SET); - read_len = load_fread(&sheader, 1, sizeof sheader, fd); - check_read(read_len, sizeof sheader); - - if ((sheader.sh_flags & SHF_ALLOC) == 0) - { - continue; - } - - switch (sheader.sh_type) - { - case SHT_PROGBITS: - case SHT_NOBITS: - if (start > sheader.sh_addr) - { - start = sheader.sh_addr; - } - if (sheader.sh_addr + sheader.sh_size > end) - { - end = sheader.sh_addr + sheader.sh_size; - } - break; - default: - break; - } - } - - total_size = end - start; - -#ifdef RT_USING_CACHE - load_off = (size_t)rt_malloc_align(total_size, RT_CPU_CACHE_LINE_SZ); -#else - load_off = (size_t)rt_malloc(total_size); -#endif - if (load_off == 0) - { - LOG_E("alloc text memory faild!"); - result = -RT_ENOMEM; - goto _exit; - } - else - { - LOG_D("lwp text malloc : %p, size: %d!", (void *)load_off, lwp->text_size); - } - lwp->load_off = load_off; /* for free */ - lwp->text_size = total_size; - } -#endif - lwp->text_entry = (void *)(eheader.e_entry + load_off); - - off = eheader.e_phoff; - for (i = 0; i < eheader.e_phnum; i++, off += sizeof pheader) - { - check_off(off, len); - lseek(fd, off, SEEK_SET); - read_len = load_fread(&pheader, 1, sizeof pheader, fd); - check_read(read_len, sizeof pheader); - - if (pheader.p_type == PT_LOAD) - { - if (pheader.p_filesz > pheader.p_memsz) - { - LOG_E("pheader.p_filesz > pheader.p_memsz, p_filesz:0x%x;p_memsz:0x%x!", pheader.p_filesz, pheader.p_memsz); - return -RT_ERROR; - } - - check_off(pheader.p_offset, len); - lseek(fd, pheader.p_offset, SEEK_SET); -#ifdef ARCH_MM_MMU - { - uint32_t size = pheader.p_filesz; - size_t tmp_len = 0; - - va = (void *)(pheader.p_vaddr + load_addr); - read_len = 0; - while (size) - { - pa = lwp_v2p(lwp, va); - va_self = (void *)((char *)pa - PV_OFFSET); - LOG_D("va_self = %p pa = %p", va_self, pa); - tmp_len = (size < ARCH_PAGE_SIZE) ? size : ARCH_PAGE_SIZE; - tmp_len = load_fread(va_self, 1, tmp_len, fd); - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, va_self, tmp_len); - read_len += tmp_len; - size -= tmp_len; - va = (void *)((char *)va + ARCH_PAGE_SIZE); - } - } -#else - read_len = load_fread((void*)(pheader.p_vaddr + load_off), 1, pheader.p_filesz, fd); -#endif - check_read(read_len, pheader.p_filesz); - - if (pheader.p_filesz < pheader.p_memsz) - { -#ifdef ARCH_MM_MMU - uint32_t size = pheader.p_memsz - pheader.p_filesz; - uint32_t size_s; - uint32_t off; - - off = pheader.p_filesz & ARCH_PAGE_MASK; - va = (void *)((pheader.p_vaddr + pheader.p_filesz + load_off) & ~ARCH_PAGE_MASK); - while (size) - { - size_s = (size < ARCH_PAGE_SIZE - off) ? size : ARCH_PAGE_SIZE - off; - pa = lwp_v2p(lwp, va); - va_self = (void *)((char *)pa - PV_OFFSET); - memset((void *)((char *)va_self + off), 0, size_s); - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)((char *)va_self + off), size_s); - off = 0; - size -= size_s; - va = (void *)((char *)va + ARCH_PAGE_SIZE); - } -#else - memset((uint8_t *)pheader.p_vaddr + pheader.p_filesz + load_off, 0, (size_t)(pheader.p_memsz - pheader.p_filesz)); -#endif - } - } - } - - /* relocate */ - if (eheader.e_type == ET_DYN) - { - /* section info */ - off = eheader.e_shoff; - /* find section string table */ - check_off(off, len); - lseek(fd, off + (sizeof sheader) * eheader.e_shstrndx, SEEK_SET); - read_len = load_fread(&sheader, 1, sizeof sheader, fd); - check_read(read_len, sizeof sheader); - - p_section_str = (char *)rt_malloc(sheader.sh_size); - if (!p_section_str) - { - LOG_E("out of memory!"); - result = -ENOMEM; - goto _exit; - } - - check_off(sheader.sh_offset, len); - lseek(fd, sheader.sh_offset, SEEK_SET); - read_len = load_fread(p_section_str, 1, sheader.sh_size, fd); - check_read(read_len, sheader.sh_size); - - check_off(off, len); - lseek(fd, off, SEEK_SET); - for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader) - { - read_len = load_fread(&sheader, 1, sizeof sheader, fd); - check_read(read_len, sizeof sheader); - - if (strcmp(p_section_str + sheader.sh_name, ".got") == 0) - { - got_start = (void *)((uint8_t *)sheader.sh_addr + load_off); - got_size = (size_t)sheader.sh_size; - } - else if (strcmp(p_section_str + sheader.sh_name, ".rel.dyn") == 0) - { - rel_dyn_start = (void *)((uint8_t *)sheader.sh_addr + load_off); - rel_dyn_size = (size_t)sheader.sh_size; - } - else if (strcmp(p_section_str + sheader.sh_name, ".dynsym") == 0) - { - dynsym_off = (size_t)sheader.sh_offset; - dynsym_size = (size_t)sheader.sh_size; - } - } - /* reloc */ - if (dynsym_size) - { - dynsym = rt_malloc(dynsym_size); - if (!dynsym) - { - LOG_E("ERROR: Malloc error!"); - result = -ENOMEM; - goto _exit; - } - check_off(dynsym_off, len); - lseek(fd, dynsym_off, SEEK_SET); - read_len = load_fread(dynsym, 1, dynsym_size, fd); - check_read(read_len, dynsym_size); - } -#ifdef ARCH_MM_MMU - arch_elf_reloc(lwp->aspace, (void *)load_off, rel_dyn_start, rel_dyn_size, got_start, got_size, dynsym); -#else - arch_elf_reloc((void *)load_off, rel_dyn_start, rel_dyn_size, got_start, got_size, dynsym); - - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, lwp->text_size); - rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, lwp->text_entry, lwp->text_size); -#endif - } - LOG_D("lwp->text_entry = 0x%p", lwp->text_entry); - LOG_D("lwp->text_size = 0x%p", lwp->text_size); - -_exit: - if (dynsym) - { - rt_free(dynsym); - } - if (p_section_str) - { - rt_free(p_section_str); - } - if (result != RT_EOK) - { - LOG_E("lwp load faild, %d", result); - } - return result; -} -#endif /* ARCH_MM_MMU */ - -rt_weak int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux) -{ - uint8_t *ptr; - int ret = -1; - int len; - int fd = -1; - - /* check file name */ - RT_ASSERT(filename != RT_NULL); - /* check lwp control block */ - RT_ASSERT(lwp != RT_NULL); - - /* copy file name to process name */ - rt_strncpy(lwp->cmd, filename, RT_NAME_MAX); - - if (load_addr != RT_NULL) - { - lwp->lwp_type = LWP_TYPE_FIX_ADDR; - ptr = load_addr; - } - else - { - lwp->lwp_type = LWP_TYPE_DYN_ADDR; - ptr = RT_NULL; - } - - fd = open(filename, O_BINARY | O_RDONLY, 0); - if (fd < 0) - { - LOG_E("ERROR: Can't open elf file %s!", filename); - goto out; - } - len = lseek(fd, 0, SEEK_END); - if (len < 0) - { - LOG_E("ERROR: File %s size error!", filename); - goto out; - } - - lseek(fd, 0, SEEK_SET); - - ret = load_elf(fd, len, lwp, ptr, aux); - if ((ret != RT_EOK) && (ret != 1)) - { - LOG_E("lwp load ret = %d", ret); - } - -out: - if (fd > 0) - { - close(fd); - } - return ret; -} /* lwp-thread clean up routine */ void lwp_cleanup(struct rt_thread *tid) @@ -1286,6 +397,34 @@ rt_err_t lwp_children_unregister(struct rt_lwp *parent, struct rt_lwp *child) return 0; } +struct process_aux *argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp) +{ + struct lwp_args_info ai; + rt_err_t error; + struct process_aux *ua; + const char **tail_argv[2] = {0}; + + error = lwp_args_init(&ai); + if (error) + { + return RT_NULL; + } + + if (argc > 0) + { + tail_argv[0] = (void *)argv[argc - 1]; + argv[argc - 1] = NULL; + lwp_args_put(&ai, (void *)argv, LWP_ARGS_TYPE_KARG); + lwp_args_put(&ai, (void *)tail_argv, LWP_ARGS_TYPE_KARG); + } + lwp_args_put(&ai, (void *)envp, LWP_ARGS_TYPE_KENVP); + + ua = lwp_argscopy(lwp, &ai); + lwp_args_detach(&ai); + + return ua; +} + pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) { int result; @@ -1327,7 +466,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) } #endif - if ((aux = lwp_argscopy(lwp, argc, argv, envp)) == RT_NULL) + if ((aux = argscopy(lwp, argc, argv, envp)) == RT_NULL) { lwp_tid_put(tid); lwp_ref_dec(lwp); @@ -1335,14 +474,6 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp) } result = lwp_load(filename, lwp, RT_NULL, 0, aux); -#ifdef ARCH_MM_MMU - if (result == 1) - { - /* dynmaic */ - lwp_unmap_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE)); - result = load_ldso(lwp, filename, argv, envp); - } -#endif /* ARCH_MM_MMU */ if (result == RT_EOK) { rt_thread_t thread = RT_NULL; diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index 060e9ff34c..e2cf2e8bd7 100644 --- a/components/lwp/lwp.h +++ b/components/lwp/lwp.h @@ -32,6 +32,7 @@ #include "lwp_signal.h" #include "lwp_syscall.h" #include "lwp_avl.h" +#include "lwp_args.h" #include "mm_aspace.h" #ifdef RT_USING_MUSLLIBC @@ -237,6 +238,8 @@ void lwp_tid_dec_ref(rt_thread_t thread); void lwp_tid_set_thread(int tid, rt_thread_t thread); int lwp_execve(char *filename, int debug, int argc, char **argv, char **envp); +int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux); +void lwp_user_obj_free(struct rt_lwp *lwp); /*create by lwp_setsid.c*/ int setsid(void); @@ -382,15 +385,6 @@ struct process_aux struct process_aux_item item[AUX_ARRAY_ITEMS_NR]; }; -struct lwp_args_info -{ - char **argv; - char **envp; - int argc; - int envc; - int size; -}; - struct dbg_ops_t { int (*dbg)(int argc, char **argv); diff --git a/components/lwp/lwp_args.c b/components/lwp/lwp_args.c new file mode 100644 index 0000000000..3c70f7ce91 --- /dev/null +++ b/components/lwp/lwp_args.c @@ -0,0 +1,781 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-01-12 Shell separate argv, envp, aux processing to lwp_args.c + * Bugs fix for script arguments processing. + * support args larger than 4k + */ +#include "lwp_args.h" +#include "lwp_internal.h" +#include "mm_page.h" + +static void _strvec_init(struct lwp_string_vector *sv) +{ + #define DEFAUTL_ARGV_BUFLEN 4 + sv->strvec = rt_malloc(DEFAUTL_ARGV_BUFLEN * sizeof(char *)); + sv->strvec_buflen = DEFAUTL_ARGV_BUFLEN; + sv->string_count = 0; +} + +static void _strvec_detach(struct lwp_string_vector *sv) +{ + if (sv->strvec) + { + rt_free(sv->strvec); + } +} + +static rt_err_t _strvec_append(struct lwp_string_vector *sv, const char *string) +{ + if (sv->string_count == sv->strvec_buflen) + { + void *newptr; + newptr = rt_realloc(sv->strvec, sv->strvec_buflen * 2 * sizeof(char *)); + if (!newptr) + return -RT_ENOMEM; + sv->strvec = newptr; + sv->strvec_buflen *= 2; + } + + sv->strvec[sv->string_count++] = string; + return RT_EOK; +} + +static rt_err_t args_append(struct lwp_args_info *ai, const char *str_addr, + size_t str_len, enum lwp_args_type atype) +{ + rt_err_t error; + char *str_bufaddr; + + if (ai->strings_length + str_len + 1 > ai->str_buf_size) + { + /* reallocate buffer for this */ + void *newptr; + newptr = rt_realloc(ai->str_buf, ai->str_buf_size * 2); + if (!newptr) + return -RT_ENOMEM; + ai->str_buf = newptr; + ai->str_buf_size *= 2; + } + + /* append new string to string buffer and update strings_length */ + str_bufaddr = &ai->str_buf[ai->strings_length]; + if (atype == LWP_ARGS_TYPE_KARG || atype == LWP_ARGS_TYPE_KENVP) + { + strcpy(str_bufaddr, str_addr); + ai->strings_length += str_len + 1; + } + else + { + lwp_get_from_user(str_bufaddr, (void *)str_addr, str_len); + ai->strings_length += str_len; + ai->str_buf[ai->strings_length++] = '\0'; + } + + /* append new argument or environment */ + switch (atype) + { + case LWP_ARGS_TYPE_ARG: + case LWP_ARGS_TYPE_KARG: + error = _strvec_append(&ai->argv, str_bufaddr); + if (!error && ai->argv.string_count == 1) + { + ai->argv0_strlen = str_len; + } + break; + case LWP_ARGS_TYPE_ENVP: + case LWP_ARGS_TYPE_KENVP: + error = _strvec_append(&ai->envp, str_bufaddr); + break; + default: + break; + } + return error; +} + + +/** + * @brief Override arguments 0 for script interpreter. + * + * Manual: interpreter will be invoked with the following arguments: + * {interpreter [optional-arg] pathname arg...} + * where pathname is the pathname of the file specified as the first + * argument of execve(), and arg... is the series of words pointed + * to by the argv argument of execve(), starting at argv[1]. Note + * that there is no way to get the argv[0] that was passed to the + * execve() call. + */ +static rt_err_t _args_override_argv0(struct lwp_args_info *ai, struct lwp_args_info *ow_ai) +{ + rt_err_t error = 0; + int i, new_argc, new_strbuf_size, ai_bytes_tobe_copied; + char **new_argv, *new_strbuf, *base; + rt_base_t off; + + if (ow_ai == 0 || ow_ai->argv.string_count == 0) + { + return -RT_EINVAL; + } + + /* for new argument vector */ + new_argc = ai->argv.string_count - 1 + ow_ai->argv.string_count; + new_argv = rt_malloc(new_argc * sizeof(char *)); + if (!new_argv) + { + return -RT_ENOMEM; + } + + /* for new string buffer */ + ai_bytes_tobe_copied = ai->strings_length - (ai->argv0_strlen + 1); + new_strbuf_size = ai_bytes_tobe_copied + ow_ai->strings_length; + new_strbuf = rt_malloc(new_strbuf_size); + if (!new_argv) + { + rt_free(new_argv); + return -RT_ENOMEM; + } + + base = new_strbuf; + off = base - ow_ai->str_buf; + /* copy overriding argument strings and argv */ + memcpy(base, ow_ai->str_buf, ow_ai->strings_length); + for (i = 0; i < ow_ai->argv.string_count; i++) + { + /* base + ow_ai->argv.strvec[i] - ow_ai->str_buf */ + new_argv[i] = (char *)ow_ai->argv.strvec[i] + off; + } + + base += ow_ai->strings_length; + off = base - (ai->str_buf + ai->argv0_strlen + 1); + /* copy old argument strings starting from argv[1] and setup new_argv */ + memcpy(base, ai->str_buf + ai->argv0_strlen + 1, ai_bytes_tobe_copied); + for (size_t j = 1; j < ai->argv.string_count; i++, j++) + { + /* base + ai->argv->strvec[j] - ai->str_buf */ + new_argv[i] = (char *)ai->argv.strvec[j] + off; + } + + /* setup envp for ai */ + for (i = 0; i < ai->envp.string_count; i++) + { + /* base + ai->envp->strvec[i] - ai->str_buf */ + ai->envp.strvec[i] += off; + } + + /* replace strings buffer and argv buffer */ + ai->str_buf = new_strbuf; + ai->strings_length = new_strbuf_size; + ai->str_buf_size = new_strbuf_size; + ai->argv.string_count = new_argc; + ai->argv.strvec = (void *)new_argv; + ai->argv.strvec_buflen = new_argc; + + ai->argv0_strlen = ow_ai->argv0_strlen; + return error; +} + +const char *lwp_args_get_argv_0(struct lwp_args_info *ai) +{ + return ai->str_buf; +} + +static rt_err_t args_init(struct lwp_args_info *ai, size_t str_buf_size) +{ + void *str_buf; + str_buf = rt_malloc(str_buf_size); + if (!str_buf) + return -RT_ENOMEM; + + memset(ai, 0, sizeof(*ai)); + + _strvec_init(&ai->argv); + if (!ai->argv.strvec) + { + rt_free(str_buf); + return -RT_ENOMEM; + } + _strvec_init(&ai->envp); + if (!ai->envp.strvec) + { + rt_free(str_buf); + _strvec_detach(&ai->argv); + return -RT_ENOMEM; + } + + ai->str_buf_size = str_buf_size; + ai->str_buf = str_buf; + return RT_EOK; +} + +#define STR_BUF_DEFAULT_SIZE 2048 +rt_err_t lwp_args_init(struct lwp_args_info *ai) +{ + return args_init(ai, STR_BUF_DEFAULT_SIZE); +} + +void lwp_args_detach(struct lwp_args_info *ai) +{ + _strvec_detach(&ai->argv); + _strvec_detach(&ai->envp); + rt_free(ai->str_buf); +} + +#ifdef ARCH_MM_MMU +struct process_aux *lwp_argscopy(struct rt_lwp *lwp, struct lwp_args_info *ai) +{ + int size = sizeof(rt_base_t) * 4; /* store argc, argv_NULL, envp_NULL, aux_NULL */ + char *str_ua; + const char **args_ua; + const char **iter; + rt_base_t off; + struct process_aux_item pa_item; + struct process_aux *aux_ua; + size_t prot = PROT_READ | PROT_WRITE; + size_t flags = MAP_FIXED | MAP_PRIVATE; + rt_base_t argc = ai->argv.string_count; + rt_base_t envc = ai->envp.string_count; + + /** + * counts the bytes to storage the args + */ + size += argc * sizeof(char *) + envc * sizeof(char *) + + ai->strings_length + sizeof(struct process_aux); + + args_ua = lwp_mmap2(lwp, (void *)(USER_STACK_VEND), size, prot, flags, -1, 0); + if (args_ua == RT_NULL) + { + return RT_NULL; + } + + /** + * @brief Put data from args info to user space + * argc, argv[], NULL, envp[], NULL, aux[], NULL, strings + */ + iter = args_ua; + + /* argc */ + lwp_data_put(lwp, iter++, &argc, sizeof(char *)); + + /* strings */ + str_ua = (char *)((rt_ubase_t)args_ua + + (1 + argc + 1 + envc + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(rt_base_t)); + lwp_data_put(lwp, str_ua, ai->str_buf, ai->strings_length); + + /* argv */ + off = str_ua - ai->str_buf; + for (size_t i = 0; i < argc; i++) + { + /* str_ua + ai->argv.strvec[i] - ai->str_buf */ + ai->argv.strvec[i] += off; + } + lwp_data_put(lwp, iter, ai->argv.strvec, sizeof(char *) * ai->argv.string_count); + iter += ai->argv.string_count; + + /* NULL */ + lwp_data_set(lwp, iter++, 0, sizeof(char *)); + + /* envp */ + for (size_t i = 0; i < envc; i++) + { + /* str_ua + ai->envp.strvec[i] - ai->str_buf */ + ai->envp.strvec[i] += off; + } + lwp_data_put(lwp, iter, ai->envp.strvec, sizeof(char *) * ai->envp.string_count); + iter += ai->envp.string_count; + + /* NULL */ + lwp_data_set(lwp, iter++, 0, sizeof(char *)); + + /* aux */ + aux_ua = (struct process_aux *)iter; + pa_item.key = AT_EXECFN; + pa_item.value = (size_t)str_ua; + lwp_data_put(lwp, iter, &pa_item, sizeof(pa_item)); + iter += AUX_ARRAY_ITEMS_NR * 2; + + /* NULL */ + lwp_data_set(lwp, iter++, 0, sizeof(char *)); + + lwp->args = args_ua; + + return aux_ua; +} +#else +static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp) +{ +#ifdef ARCH_MM_MMU + int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */ + struct process_aux *aux; +#else + int size = sizeof(int) * 4; /* store argc, argv, envp, NULL */ +#endif /* ARCH_MM_MMU */ + int *args; + char *str; + char **new_argve; + int i; + int len; + + for (i = 0; i < argc; i++) + { + size += (rt_strlen(argv[i]) + 1); + } + size += (sizeof(int) * argc); + + i = 0; + if (envp) + { + while (envp[i] != 0) + { + size += (rt_strlen(envp[i]) + 1); + size += sizeof(int); + i++; + } + } + +#ifdef ARCH_MM_MMU + /* for aux */ + size += sizeof(struct process_aux); + + args = (int *)rt_malloc(size); + if (args == RT_NULL) + { + return RT_NULL; + } + + /* argc, argv[], 0, envp[], 0 */ + str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int)); +#else + args = (int *)rt_malloc(size); + if (args == RT_NULL) + { + return RT_NULL; + } + str = (char*)((int)args + (argc + 2 + i + 1) * sizeof(int)); +#endif /* ARCH_MM_MMU */ + + new_argve = (char **)&args[1]; + args[0] = argc; + + for (i = 0; i < argc; i++) + { + len = rt_strlen(argv[i]) + 1; + new_argve[i] = str; + lwp_memcpy(str, argv[i], len); + str += len; + } + new_argve[i] = 0; + i++; + + new_argve[i] = 0; + if (envp) + { + int j; + for (j = 0; envp[j] != 0; j++) + { + len = rt_strlen(envp[j]) + 1; + new_argve[i] = str; + lwp_memcpy(str, envp[j], len); + str += len; + i++; + } + new_argve[i] = 0; + } +#ifdef ARCH_MM_MMU + /* aux */ + aux = (struct process_aux *)(new_argve + i); + aux->item[0].key = AT_EXECFN; + aux->item[0].value = (uint32_t)(size_t)new_argve[0]; + i += AUX_ARRAY_ITEMS_NR * 2; + new_argve[i] = 0; + + lwp->args = args; + + return aux; +#else + lwp->args = args; + lwp->args_length = size; + + return (struct process_aux *)(new_argve + i); +#endif /* ARCH_MM_MMU */ +} +#endif + +rt_err_t lwp_args_put(struct lwp_args_info *args, const char **strv_addr, enum lwp_args_type atype) +{ + rt_err_t error; + int iter = 0; + int len; + const char *arg_ptr; + + while (1) + { + if (atype == LWP_ARGS_TYPE_ARG || atype == LWP_ARGS_TYPE_ENVP) + { + len = lwp_get_from_user(&arg_ptr, strv_addr + iter++, sizeof(char *)); + if (len != sizeof(char *)) + { + return -EFAULT; + } + if (arg_ptr == NULL) + { + break; + } + len = lwp_user_strlen(arg_ptr); + if (len < 0) + { + return -EFAULT; + } + } + else + { + arg_ptr = strv_addr[iter++]; + if (arg_ptr == NULL) + { + break; + } + len = strlen(arg_ptr); + } + + error = args_append(args, arg_ptr, len, atype); + if (error) + { + return error; + } + } + return 0; +} + +/** + * @brief Put argument vector to args object + */ +rt_err_t lwp_args_put_argv(struct lwp_args_info *args, const char **argv_uaddr) +{ + return lwp_args_put(args, argv_uaddr, LWP_ARGS_TYPE_ARG); +} + +/** + * @brief Put argument vector to args object + */ +rt_err_t lwp_args_put_envp(struct lwp_args_info *args, const char **envp_uaddr) +{ + return lwp_args_put(args, envp_uaddr, LWP_ARGS_TYPE_ENVP); +} + +/** + * read words until reach nextline or EOF. + * words copied into buffer is never truncated. + */ +#define READFILE_STAT_EOF_REACHED 0 +#define READFILE_STAT_NEXTLINE_REACHED 0 +#define READFILE_STAT_TRUNCATED 1 +#define READFILE_STAT_CAN_READMORE(stat) (stat) +static int _readfile(int fd, size_t maxbytes, char *buffer, int *p_readlen) +{ + int readlen; + int stat; + char *nlp; + + readlen = read(fd, buffer, maxbytes - 1); + if (readlen <= 0) + { + /* eof, failed */ + stat = READFILE_STAT_EOF_REACHED; + buffer[0] = '\0'; + } + else + { + if ((nlp = strchr(buffer, '\n')) == NULL) + { + if (readlen == maxbytes - 1) + { + int tailing_wordlen = 0; + char *cp = buffer + readlen - 1; + for (; *cp && *cp != ' ' && *cp != '\t'; cp--, tailing_wordlen++) + ; + if (tailing_wordlen) + { + lseek(fd, -tailing_wordlen, SEEK_CUR); + readlen -= tailing_wordlen; + stat = READFILE_STAT_TRUNCATED; + } + else + { + stat = READFILE_STAT_EOF_REACHED; + } + } + else + { + stat = READFILE_STAT_EOF_REACHED; + } + } + else + { + stat = READFILE_STAT_NEXTLINE_REACHED; + readlen = nlp - buffer; + } + buffer[readlen] = '\0'; + } + + if (p_readlen) + *p_readlen = readlen; + return stat; +} + +static char *_find_word(char *cp) +{ + for (; (*cp == ' ') || (*cp == '\t'); cp++) + ; + return cp; +} + +static char *_seperate_and_get_nextword(char *cp) +{ + /* find next whitespace */ + for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++) + ; + /* seperate words */ + while ((*cp == ' ') || (*cp == '\t')) + { + *cp++ = '\0'; + } + return cp; +} + +#define INTERP_BUF_SIZE 128 +rt_err_t lwp_args_load_script(struct lwp_args_info *ai, const char *filename) +{ + rt_err_t error = -1; + int fd = -RT_ERROR; + int len; + int rf_stat; + char interp[INTERP_BUF_SIZE]; + char *cp, *nextword; + char script_magic[2]; + struct lwp_args_info ow_ai = {0}; + + fd = open(filename, O_BINARY | O_RDONLY, 0); + if (fd < 0) + { + goto quit; + } + + /** + * verify an interpreter script by matching script file magic + * eg: #!/bin/sh + */ + len = read(fd, script_magic, sizeof(script_magic)); + if (len != 2 || memcmp(script_magic, "#!", sizeof(script_magic))) + { + goto quit; + } + + /* setup a new args struct to save script arguments */ + if (args_init(&ow_ai, INTERP_BUF_SIZE)) + { + goto quit; + } + + while (1) + { + /* read file to buffer (avoid any truncated words in buffer) */ + rf_stat = _readfile(fd, INTERP_BUF_SIZE, interp, &len); + if (len <= 0) + { + goto quit; + } + + /* find first word until reaching nil */ + cp = _find_word(interp); + if (*cp == '\0') + { + if (READFILE_STAT_CAN_READMORE(rf_stat)) + continue; + else + break; + } + + do + { + nextword = _seperate_and_get_nextword(cp); + args_append(&ow_ai, cp, strlen(cp), LWP_ARGS_TYPE_KARG); + cp = nextword; + } + while (*cp); + + if (READFILE_STAT_CAN_READMORE(rf_stat)) + continue; + else + break; + } + + if (ow_ai.argv.string_count == 0) + { + goto quit; /* No interpreter name found */ + } + + args_append(&ow_ai, filename, strlen(filename), LWP_ARGS_TYPE_KARG); + error = _args_override_argv0(ai, &ow_ai); + if (error) + { + goto quit; + } + +quit: + lwp_args_detach(&ow_ai); + if (fd >= 0) + { + close(fd); + } + return error; +} + +char** lwp_get_command_line_args(struct rt_lwp *lwp) +{ + size_t argc = 0; + char** argv = NULL; + int ret; + size_t i; + size_t len; + + if (lwp) + { + ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc)); + if (ret == 0) + { + return RT_NULL; + } + argv = (char**)rt_malloc((argc + 1) * sizeof(char*)); + + if (argv) + { + for (i = 0; i < argc; i++) + { + char *argvp = NULL; + ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp)); + if (ret == 0) + { + lwp_free_command_line_args(argv); + return RT_NULL; + } + len = lwp_user_strlen_ext(lwp, argvp); + + if (len > 0) + { + argv[i] = (char*)rt_malloc(len + 1); + ret = lwp_data_get(lwp, argv[i], argvp, len); + if (ret == 0) + { + lwp_free_command_line_args(argv); + return RT_NULL; + } + argv[i][len] = '\0'; + } + else + { + argv[i] = NULL; + } + } + argv[argc] = NULL; + } + } + + return argv; +} + +void lwp_print_envp(struct rt_lwp *lwp) +{ + rt_size_t envp_counts; + char **kenvp_array = lwp_get_envp(lwp, &envp_counts); + if (kenvp_array) + { + rt_kprintf("envp_counts: %d\n", envp_counts); + for (size_t i = 0; i < envp_counts; i++) + { + rt_kprintf("envp[%d]: %s\n", i, kenvp_array[i]); + } + } + lwp_free_command_line_args(kenvp_array); + return ; +} + +char** lwp_get_envp(struct rt_lwp *lwp, rt_size_t *penvp_counts) +{ + int ret, len; + rt_base_t argc; + char **p_kenvp = RT_NULL; + char *envp, **p_envp; + size_t envp_counts = 0; + + if (lwp) + { + ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc)); + if (ret == 0) + { + return RT_NULL; + } + p_envp = (char **)lwp->args + 1 + argc + 1; + + /* counts envp */ + while (lwp_data_get(lwp, &envp, p_envp, sizeof(void *)) == sizeof(void *) + && envp != NULL) + { + p_envp++; + envp_counts++; + } + + p_kenvp = (char **)rt_malloc((envp_counts + 1) * sizeof(char *)); + if (p_kenvp) + { + /* copy env from envp array */ + p_envp = (char **)lwp->args + 1 + argc + 1; + for (size_t i = 0; i < envp_counts; i++) + { + ret = lwp_data_get(lwp, &envp, &p_envp[i], sizeof(char *)); + if (ret != sizeof(char **)) + { + lwp_free_command_line_args(p_kenvp); + return RT_NULL; + } + + len = lwp_user_strlen_ext(lwp, envp); + if (len > 0) + { + p_kenvp[i] = (char*)rt_malloc(len + 1); + ret = lwp_data_get(lwp, p_kenvp[i], envp, len + 1); + if (ret != len + 1) + { + lwp_free_command_line_args(p_kenvp); + return RT_NULL; + } + } + else + { + p_kenvp[i] = NULL; + } + } + if (penvp_counts) + *penvp_counts = envp_counts; + p_kenvp[envp_counts] = NULL; + } + } + + return p_kenvp; +} + +void lwp_free_command_line_args(char** argv) +{ + size_t i; + + if (argv) + { + for (i = 0; argv[i]; i++) + { + rt_free(argv[i]); + } + rt_free(argv); + } +} diff --git a/components/lwp/lwp_args.h b/components/lwp/lwp_args.h new file mode 100644 index 0000000000..fadf8e3863 --- /dev/null +++ b/components/lwp/lwp_args.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-01-12 Shell separate argv, envp, aux processing from execve(2). + * Bugs fix for script arguments processing. + */ +#ifndef __LWP_ARGV_H__ +#define __LWP_ARGV_H__ + +#include + +struct rt_lwp; + +enum lwp_args_type { + LWP_ARGS_TYPE_ARG, + LWP_ARGS_TYPE_KARG, + LWP_ARGS_TYPE_ENVP, + LWP_ARGS_TYPE_KENVP, + LWP_ARGS_TYPE_NULLPTR +}; + +struct lwp_string_vector +{ + const char **strvec; + rt_uint32_t strvec_buflen; + rt_uint32_t string_count; +}; + +struct lwp_args_info +{ + int argv0_strlen; + int strings_length; + int str_buf_size; + + char *str_buf; + struct lwp_string_vector argv; + struct lwp_string_vector envp; +}; + +rt_err_t lwp_args_init(struct lwp_args_info *ai); +void lwp_args_detach(struct lwp_args_info *ai); +struct process_aux *lwp_argscopy(struct rt_lwp *lwp, struct lwp_args_info *args_info);; +rt_err_t lwp_args_put(struct lwp_args_info *args, const char **strv_addr, enum lwp_args_type atype); +rt_err_t lwp_args_put_argv(struct lwp_args_info *args, const char **argv_uaddr); +rt_err_t lwp_args_put_envp(struct lwp_args_info *args, const char **envp_uaddr); +rt_err_t lwp_args_load_script(struct lwp_args_info *args, const char *filename); +const char *lwp_args_get_argv_0(struct lwp_args_info *ai); +char** lwp_get_envp(struct rt_lwp *lwp, rt_size_t *penvp_counts); +void lwp_print_envp(struct rt_lwp *lwp); + +char** lwp_get_command_line_args(struct rt_lwp *lwp); +void lwp_free_command_line_args(char** argv); + +#endif /* __LWP_ARGV_H__ */ diff --git a/components/lwp/lwp_elf.c b/components/lwp/lwp_elf.c index f654adc5b7..da698e3674 100644 --- a/components/lwp/lwp_elf.c +++ b/components/lwp/lwp_elf.c @@ -47,11 +47,13 @@ #define ELF_EXEC_LOAD_ADDR USER_VADDR_START #define ELF_INTERP_LOAD_ADDR LDSO_LOAD_VADDR -#define ELF_AUX_ENT(aux, id, val) \ - do \ - { \ - *aux++ = id; \ - *aux++ = val; \ +#define ELF_AUX_ENT(aux, id, val) \ + do \ + { \ + rt_base_t a = id; \ + lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \ + a = val; \ + lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \ } while (0) typedef struct @@ -571,6 +573,7 @@ static int elf_aux_fill(elf_load_info_t *load_info) uint32_t random_value = rt_tick_get(); size_t prot = PROT_READ | PROT_WRITE; size_t flags = MAP_PRIVATE; + rt_lwp_t lwp = load_info->lwp; void *va; if (!aux) @@ -581,7 +584,7 @@ static int elf_aux_fill(elf_load_info_t *load_info) aux_info = (elf_addr_t *)aux->item; ELF_AUX_ENT(aux_info, AT_PAGESZ, ARCH_PAGE_SIZE); - va = lwp_mmap2(load_info->lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), ARCH_PAGE_SIZE, prot, flags, -1, 0); + va = lwp_mmap2(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), ARCH_PAGE_SIZE, prot, flags, -1, 0); if (!va) { LOG_E("lwp map user failed!"); @@ -604,10 +607,6 @@ static int elf_aux_fill(elf_load_info_t *load_info) ELF_AUX_ENT(aux_info, AT_CLKTCK, 0); ELF_AUX_ENT(aux_info, AT_SECURE, 0); -#ifdef ARCH_MM_MMU - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, aux, sizeof(*aux)); -#endif - return 0; } @@ -757,7 +756,7 @@ OUT: } int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, - struct process_aux *aux) + struct process_aux *aux_ua) { elf_load_info_t load_info = { 0 }; int len; @@ -789,7 +788,7 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_ } load_info.lwp = lwp; - load_info.aux = aux; + load_info.aux = aux_ua; load_info.exec_info.fd = ELF_INVALID_FD; load_info.interp_info.fd = ELF_INVALID_FD; diff --git a/components/lwp/lwp_internal.h b/components/lwp/lwp_internal.h index c942be0136..96c7949d64 100644 --- a/components/lwp/lwp_internal.h +++ b/components/lwp/lwp_internal.h @@ -186,6 +186,4 @@ rt_err_t lwp_critical_exit(struct rt_lwp *lwp); #define LWP_RETURN(name) {RT_ASSERT(name != _LWP_UNINITIALIZED_RC);return name;} #endif /* LWP_DEBUG */ -int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[]); - #endif /* __LWP_INTERNAL_H__ */ diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index bac35f4397..e539e0452b 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -2162,10 +2162,6 @@ rt_weak sysret_t sys_vfork(void) return sys_fork(); } -struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp); -int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux); -void lwp_user_obj_free(struct rt_lwp *lwp); - #define _swap_lwp_data(lwp_used, lwp_new, type, member) \ do {\ type tmp;\ @@ -2174,339 +2170,17 @@ void lwp_user_obj_free(struct rt_lwp *lwp); lwp_new->member = tmp;\ } while (0) -static char *_insert_args(int new_argc, char *new_argv[], struct lwp_args_info *args) -{ - void *page = NULL; - int err = 0; - char **nargv; - char **nenvp; - char *p; - int i, len; - int nsize; - - if (new_argc == 0) - { - goto quit; - } - page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); /* 1 page */ - if (!page) - { - goto quit; - } - - nsize = new_argc * sizeof(char *); - for (i = 0; i < new_argc; i++) - { - nsize += lwp_strlen(lwp_self(), new_argv[i]) + 1; - } - if (nsize + args->size > ARCH_PAGE_SIZE) - { - err = 1; - goto quit; - } - nargv = (char **)page; - nenvp = nargv + args->argc + new_argc + 1; - p = (char *)(nenvp + args->envc + 1); - /* insert argv */ - for (i = 0; i < new_argc; i++) - { - nargv[i] = p; - len = lwp_strlen(lwp_self(), new_argv[i]) + 1; - lwp_memcpy(p, new_argv[i], len); - p += len; - } - /* copy argv */ - nargv += new_argc; - for (i = 0; i < args->argc; i++) - { - nargv[i] = p; - len = lwp_strlen(lwp_self(), args->argv[i]) + 1; - lwp_memcpy(p, args->argv[i], len); - p += len; - } - nargv[i] = NULL; - /* copy envp */ - for (i = 0; i < args->envc; i++) - { - nenvp[i] = p; - len = lwp_strlen(lwp_self(), args->envp[i]) + 1; - lwp_memcpy(p, args->envp[i], len); - p += len; - } - nenvp[i] = NULL; - - /* update args */ - args->argv = (char **)page; - args->argc = args->argc + new_argc; - args->envp = args->argv + args->argc + 1; - /* args->envc no change */ - args->size = args->size + nsize; - -quit: - if (err && page) - { - rt_pages_free(page, 0); - page = NULL; - } - return page; -} - -#define INTERP_BUF_SIZE 128 -static char *_load_script(const char *filename, void *old_page, struct lwp_args_info *args) -{ - char *new_page = NULL; - int fd = -RT_ERROR; - int len; - char interp[INTERP_BUF_SIZE]; - char *cp; - char *i_name; - char *i_arg; - - fd = open(filename, O_BINARY | O_RDONLY, 0); - if (fd < 0) - { - goto quit; - } - len = read(fd, interp, INTERP_BUF_SIZE); - if (len < 2) - { - goto quit; - } - /* - * match find file header the first line. - * eg: #!/bin/sh - */ - if ((interp[0] != '#') || (interp[1] != '!')) - { - goto quit; - } - - if (len == INTERP_BUF_SIZE) - { - len--; - } - interp[len] = '\0'; - - if ((cp = strchr(interp, '\n')) == NULL) - { - cp = interp + INTERP_BUF_SIZE - 1; - } - *cp = '\0'; - while (cp > interp) - { - cp--; - if ((*cp == ' ') || (*cp == '\t')) - { - *cp = '\0'; - } - else - { - break; - } - } - for (cp = interp + 2; (*cp == ' ') || (*cp == '\t'); cp++) - { - /* nothing */ - } - if (*cp == '\0') - { - goto quit; /* No interpreter name found */ - } - i_name = cp; - i_arg = NULL; - for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++) - { - /* nothing */ - } - while ((*cp == ' ') || (*cp == '\t')) - { - *cp++ = '\0'; - } - if (*cp) - { - i_arg = cp; - } - - if (i_arg) - { - new_page = _insert_args(1, &i_arg, args); - if (!new_page) - { - goto quit; - } - rt_pages_free(old_page, 0); - old_page = new_page; - } - new_page = _insert_args(1, &i_name, args); - if (!new_page) - { - goto quit; - } - rt_pages_free(old_page, 0); - -quit: - if (fd >= 0) - { - close(fd); - } - return new_page; -} - -int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[]) -{ - int ret = -1; - int i; - void *page; - void *new_page; - int argc = 0; - int envc = 0; - int size; - char **kargv; - char **kenvp; - size_t len; - char *p; - char *i_arg; - struct lwp_args_info args_info; - struct process_aux *aux; - - size = sizeof(char *); - if (argv) - { - while (1) - { - if (!argv[argc]) - { - break; - } - len = lwp_strlen(lwp, (const char *)argv[argc]); - size += sizeof(char *) + len + 1; - argc++; - } - } - if (envp) - { - while (1) - { - if (!envp[envc]) - { - break; - } - len = lwp_strlen(lwp, (const char *)envp[envc]); - size += sizeof(char *) + len + 1; - envc++; - } - } - - page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); /* 1 page */ - if (!page) - { - SET_ERRNO(ENOMEM); - goto quit; - } - kargv = (char **)page; - kenvp = kargv + argc + 1; - p = (char *)(kenvp + envc + 1); - /* copy argv */ - if (argv) - { - for (i = 0; i < argc; i++) - { - kargv[i] = p; - len = lwp_strlen(lwp, argv[i]) + 1; - lwp_memcpy(p, argv[i], len); - p += len; - } - kargv[i] = NULL; - } - /* copy envp */ - if (envp) - { - for (i = 0; i < envc; i++) - { - kenvp[i] = p; - len = lwp_strlen(lwp, envp[i]) + 1; - lwp_memcpy(p, envp[i], len); - p += len; - } - kenvp[i] = NULL; - } - - args_info.argc = argc; - args_info.argv = kargv; - args_info.envc = envc; - args_info.envp = kenvp; - args_info.size = size; - - new_page = _insert_args(1, &exec_name, &args_info); - if (!new_page) - { - SET_ERRNO(ENOMEM); - goto quit; - } - rt_pages_free(page, 0); - page = new_page; - - i_arg = "-e"; - new_page = _insert_args(1, &i_arg, &args_info); - if (!new_page) - { - SET_ERRNO(ENOMEM); - goto quit; - } - rt_pages_free(page, 0); - page = new_page; - - i_arg = "ld.so"; - new_page = _insert_args(1, &i_arg, &args_info); - if (!new_page) - { - SET_ERRNO(ENOMEM); - goto quit; - } - rt_pages_free(page, 0); - page = new_page; - - if ((aux = lwp_argscopy(lwp, args_info.argc, args_info.argv, args_info.envp)) == NULL) - { - SET_ERRNO(ENOMEM); - goto quit; - } - - ret = lwp_load("/lib/ld.so", lwp, RT_NULL, 0, aux); - - rt_strncpy(lwp->cmd, exec_name, RT_NAME_MAX - 1); -quit: - if (page) - { - rt_pages_free(page, 0); - } - return (ret < 0 ? GET_ERRNO() : ret); -} - sysret_t sys_execve(const char *path, char *const argv[], char *const envp[]) { - int ret = -1; - int argc = 0; - int envc = 0; - void *page = NULL; - void *new_page; - int size = 0; + int error = -1; size_t len; - char **kargv; - char **kenvp; - char *p; struct rt_lwp *new_lwp = NULL; struct rt_lwp *lwp; int uni_thread; rt_thread_t thread; struct process_aux *aux; - int i; struct lwp_args_info args_info; - - if (access(path, X_OK) != 0) - { - return -EACCES; - } + char *kpath = RT_NULL; lwp = lwp_self(); thread = rt_thread_self(); @@ -2525,163 +2199,108 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[]) if (!uni_thread) { - SET_ERRNO(EINVAL); - goto quit; + return -EINVAL; } len = lwp_user_strlen(path); if (len <= 0) { - SET_ERRNO(EFAULT); - goto quit; + return -EFAULT; } - size += sizeof(char *); - if (argv) + kpath = rt_malloc(len + 1); + if (!kpath) { - while (1) - { - if (!lwp_user_accessable((void *)(argv + argc), sizeof(char *))) - { - SET_ERRNO(EFAULT); - goto quit; - } - if (!argv[argc]) - { - break; - } - len = lwp_user_strlen((const char *)argv[argc]); - if (len < 0) - { - SET_ERRNO(EFAULT); - goto quit; - } - size += sizeof(char *) + len + 1; - argc++; - } - } - size += sizeof(char *); - if (envp) - { - while (1) - { - if (!lwp_user_accessable((void *)(envp + envc), sizeof(char *))) - { - SET_ERRNO(EFAULT); - goto quit; - } - if (!envp[envc]) - { - break; - } - len = lwp_user_strlen((const char *)envp[envc]); - if (len < 0) - { - SET_ERRNO(EFAULT); - goto quit; - } - size += sizeof(char *) + len + 1; - envc++; - } - } - if (size > ARCH_PAGE_SIZE) - { - SET_ERRNO(EINVAL); - goto quit; - } - page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); /* 1 page */ - if (!page) - { - SET_ERRNO(ENOMEM); - goto quit; + return -ENOMEM; + } + + if (lwp_get_from_user(kpath, (void *)path, len) != len) + { + rt_free(kpath); + return -EFAULT; + } + kpath[len] = '\0'; + + if (access(kpath, X_OK) != 0) + { + rt_free(kpath); + return -EACCES; + } + + /* setup args */ + error = lwp_args_init(&args_info); + if (error) + { + rt_free(kpath); + return -ENOMEM; } - kargv = (char **)page; - kenvp = kargv + argc + 1; - p = (char *)(kenvp + envc + 1); - /* copy argv */ if (argv) { - for (i = 0; i < argc; i++) + error = lwp_args_put_argv(&args_info, (void *)argv); + if (error) { - kargv[i] = p; - len = lwp_user_strlen(argv[i]) + 1; - lwp_memcpy(p, argv[i], len); - p += len; + error = -EFAULT; + goto quit; } - kargv[i] = NULL; } - /* copy envp */ + if (envp) { - for (i = 0; i < envc; i++) + error = lwp_args_put_envp(&args_info, (void *)envp); + if (error) { - kenvp[i] = p; - len = lwp_user_strlen(envp[i]) + 1; - lwp_memcpy(p, envp[i], len); - p += len; + error = -EFAULT; + goto quit; } - kenvp[i] = NULL; } /* alloc new lwp to operation */ new_lwp = lwp_create(LWP_CREATE_FLAG_NONE); if (!new_lwp) { - SET_ERRNO(ENOMEM); + error = -ENOMEM; goto quit; } - ret = lwp_user_space_init(new_lwp, 0); - if (ret != 0) + error = lwp_user_space_init(new_lwp, 0); + if (error != 0) { - SET_ERRNO(ENOMEM); + error = -ENOMEM; goto quit; } + /* file is a script ? */ - args_info.argc = argc; - args_info.argv = kargv; - args_info.envc = envc; - args_info.envp = kenvp; - args_info.size = size; + path = kpath; while (1) { - new_page = _load_script(path, page, &args_info); - if (!new_page) + error = lwp_args_load_script(&args_info, path); + if (error != 0) { break; } - - page = new_page; - path = args_info.argv[0]; + path = lwp_args_get_argv_0(&args_info); } /* now load elf */ - if ((aux = lwp_argscopy(new_lwp, args_info.argc, args_info.argv, args_info.envp)) == NULL) + if ((aux = lwp_argscopy(new_lwp, &args_info)) == NULL) { - SET_ERRNO(ENOMEM); + error = -ENOMEM; goto quit; } - ret = lwp_load(path, new_lwp, RT_NULL, 0, aux); - if (ret == 1) - { - /* dynamic */ - lwp_unmap_user(new_lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE)); - ret = load_ldso(new_lwp, (char *)path, args_info.argv, args_info.envp); - } - if (ret == RT_EOK) + error = lwp_load(path, new_lwp, RT_NULL, 0, aux); + if (error == RT_EOK) { int off = 0; int last_backslash = 0; - char *run_name = args_info.argv[0]; /* clear all user objects */ lwp_user_object_clear(lwp); - /* find last \ or / */ + /* find last \ or / to get base name */ while (1) { - char c = run_name[off++]; + char c = path[off++]; if (c == '\0') { @@ -2700,13 +2319,11 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[]) */ RT_ASSERT(rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling) == thread); - strncpy(thread->parent.name, run_name + last_backslash, RT_NAME_MAX - 1); + strncpy(thread->parent.name, path + last_backslash, RT_NAME_MAX - 1); strncpy(lwp->cmd, new_lwp->cmd, RT_NAME_MAX); rt_free(lwp->exe_file); lwp->exe_file = strndup(new_lwp->exe_file, DFS_PATH_MAX); - rt_pages_free(page, 0); - #ifdef ARCH_MM_MMU _swap_lwp_data(lwp, new_lwp, struct rt_aspace *, aspace); @@ -2737,17 +2354,18 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[]) (char *)thread->stack_addr + thread->stack_size); /* never reach here */ } - return -EINVAL; + error = -EINVAL; quit: - if (page) + if (kpath) { - rt_pages_free(page, 0); + rt_free(kpath); } + lwp_args_detach(&args_info); if (new_lwp) { lwp_ref_dec(new_lwp); } - return (ret < 0 ? GET_ERRNO() : ret); + return error; } #endif /* ARCH_MM_MMU */ diff --git a/components/lwp/lwp_user_mm.c b/components/lwp/lwp_user_mm.c index d9a46e77fd..01640d5a07 100644 --- a/components/lwp/lwp_user_mm.c +++ b/components/lwp/lwp_user_mm.c @@ -991,71 +991,4 @@ size_t lwp_strlen(struct rt_lwp *lwp, const char *s) return strlen(s); } -char** lwp_get_command_line_args(struct rt_lwp *lwp) -{ - size_t argc = 0; - char** argv = NULL; - int ret; - size_t i; - size_t len; - - if (lwp) - { - ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc)); - if (ret == 0) - { - return RT_NULL; - } - argv = (char**)rt_malloc((argc + 1) * sizeof(char*)); - - if (argv) - { - for (i = 0; i < argc; i++) - { - char *argvp = NULL; - ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp)); - if (ret == 0) - { - lwp_free_command_line_args(argv); - return RT_NULL; - } - len = lwp_user_strlen_ext(lwp, argvp); - - if (len > 0) - { - argv[i] = (char*)rt_malloc(len + 1); - ret = lwp_data_get(lwp, argv[i], argvp, len); - if (ret == 0) - { - lwp_free_command_line_args(argv); - return RT_NULL; - } - argv[i][len] = '\0'; - } - else - { - argv[i] = NULL; - } - } - argv[argc] = NULL; - } - } - - return argv; -} - -void lwp_free_command_line_args(char** argv) -{ - size_t i; - - if (argv) - { - for (i = 0; argv[i]; i++) - { - rt_free(argv[i]); - } - rt_free(argv); - } -} - #endif diff --git a/components/lwp/lwp_user_mm.h b/components/lwp/lwp_user_mm.h index 232038c914..7155804a44 100644 --- a/components/lwp/lwp_user_mm.h +++ b/components/lwp/lwp_user_mm.h @@ -151,9 +151,6 @@ void lwp_unmap_user_space(struct rt_lwp *lwp); int lwp_unmap_user(struct rt_lwp *lwp, void *va); void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, rt_bool_t text); -void lwp_free_command_line_args(char** argv); -char** lwp_get_command_line_args(struct rt_lwp *lwp); - rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size); /* check LWP_MAP_FLAG_* */