static int copy_kargv(struct mm_struct *mm, char **kargv, const char **argv, int max_argc, int *argc_store) { int i, ret = -E_INVAL; if (!argv) { *argc_store = 0; return 0; } char *argv_k; for (i = 0; i < max_argc; i++) { if (!copy_from_user(mm, &argv_k, argv + i, sizeof(char *), 0)) goto failed_cleanup; if (!argv_k) break; char *buffer; if ((buffer = kmalloc(EXEC_MAX_ARG_LEN + 1)) == NULL) { goto failed_nomem; } #if 0 if (!copy_from_user(mm, &argv_k, argv + i, sizeof(char *), 0) || !copy_string(mm, buffer, argv_k, EXEC_MAX_ARG_LEN + 1)) { kfree(buffer); goto failed_cleanup; } #endif if (!copy_string(mm, buffer, argv_k, EXEC_MAX_ARG_LEN + 1)) { kfree(buffer); goto failed_cleanup; } kargv[i] = buffer; } *argc_store = i; return 0; failed_nomem: ret = -E_NO_MEM; failed_cleanup: put_kargv(i, kargv); return ret; }
int do_execve(const char *filename, const char **argv, const char **envp) { static_assert(EXEC_MAX_ARG_LEN >= FS_MAX_FPATH_LEN); struct mm_struct *mm = current->mm; char local_name[PROC_NAME_LEN + 1]; memset(local_name, 0, sizeof(local_name)); char *kargv[EXEC_MAX_ARG_NUM], *kenvp[EXEC_MAX_ENV_NUM]; const char *path; int ret = -E_INVAL; lock_mm(mm); #if 0 if (name == NULL) { snprintf(local_name, sizeof(local_name), "<null> %d", current->pid); } else { if (!copy_string(mm, local_name, name, sizeof(local_name))) { unlock_mm(mm); return ret; } } #endif snprintf(local_name, sizeof(local_name), "<null> %d", current->pid); int argc = 0, envc = 0; if ((ret = copy_kargv(mm, kargv, argv, EXEC_MAX_ARG_NUM, &argc)) != 0) { unlock_mm(mm); return ret; } if ((ret = copy_kargv(mm, kenvp, envp, EXEC_MAX_ENV_NUM, &envc)) != 0) { unlock_mm(mm); put_kargv(argc, kargv); return ret; } #if 0 int i; kprintf("## fn %s\n", filename); kprintf("## argc %d\n", argc); for(i=0;i<argc;i++) kprintf("## %08x %s\n", kargv[i], kargv[i]); kprintf("## envc %d\n", envc); for(i=0;i<envc;i++) kprintf("## %08x %s\n", kenvp[i], kenvp[i]); #endif //path = argv[0]; //copy_from_user (mm, &path, argv, sizeof (char*), 0); path = filename; unlock_mm(mm); /* linux never do this */ //fs_closeall(current->fs_struct); /* sysfile_open will check the first argument path, thus we have to use a user-space pointer, and argv[0] may be incorrect */ int fd; if ((ret = fd = sysfile_open(path, O_RDONLY)) < 0) { goto execve_exit; } if (mm != NULL) { mm->lapic = -1; mp_set_mm_pagetable(NULL); if (mm_count_dec(mm) == 0) { exit_mmap(mm); put_pgdir(mm); bool intr_flag; local_intr_save(intr_flag); { list_del(&(mm->proc_mm_link)); } local_intr_restore(intr_flag); mm_destroy(mm); } current->mm = NULL; } put_sem_queue(current); ret = -E_NO_MEM; /* init signal */ put_sighand(current); if ((current->signal_info.sighand = sighand_create()) == NULL) { goto execve_exit; } sighand_count_inc(current->signal_info.sighand); put_signal(current); if ((current->signal_info.signal = signal_create()) == NULL) { goto execve_exit; } signal_count_inc(current->signal_info.signal); if ((current->sem_queue = sem_queue_create()) == NULL) { goto execve_exit; } sem_queue_count_inc(current->sem_queue); if ((ret = load_icode(fd, argc, kargv, envc, kenvp)) != 0) { goto execve_exit; } set_proc_name(current, local_name); if (do_execve_arch_hook (argc, kargv) < 0) goto execve_exit; put_kargv(argc, kargv); return 0; execve_exit: put_kargv(argc, kargv); put_kargv(envc, kenvp); /* exec should return -1 if failed */ //return ret; do_exit(ret); panic("already exit: %e.\n", ret); }