From 381f9ff1ee4211ce1992d16d790674a98079f13f Mon Sep 17 00:00:00 2001 From: Michalis Pappas Date: Mon, 14 Apr 2025 17:05:19 +0200 Subject: [PATCH] lib/posix-process: Add uk_posix_process_run() This function spanws a process that jumps to main-like function passed as an argument. It is intended to be used by the init process when multiprocess is enabled, to spawn the application process and call main(). As in native mode there is no path to pass to execve(), this function allows spawning the application process in both native and bincompat mode. Signed-off-by: Michalis Pappas Approved-by: Andrei Tatar Reviewed-by: Andrei Tatar GitHub-Closes: #1633 --- lib/posix-process/clone.c | 21 +++--- lib/posix-process/execve.c | 7 +- lib/posix-process/exportsyms.uk | 1 + lib/posix-process/include/uk/process.h | 20 +++++- lib/posix-process/process.c | 88 ++++++++++++++++++++++++++ lib/posix-process/process.h | 12 ++++ 6 files changed, 137 insertions(+), 12 deletions(-) diff --git a/lib/posix-process/clone.c b/lib/posix-process/clone.c index de9a5388f..4949b02b8 100644 --- a/lib/posix-process/clone.c +++ b/lib/posix-process/clone.c @@ -122,11 +122,11 @@ static int _clonetab_term_call(void *argp) return 0; } /** Iterates over registered thread initialization functions */ -static int _uk_posix_clonetab_init(const struct clone_args *cl_args, - size_t cl_args_len, - __u64 cl_flags_optional, - struct uk_thread *child, - struct uk_thread *parent) +int pprocess_clonetab_init(const struct clone_args *cl_args, + size_t cl_args_len, + __u64 cl_flags_optional, + struct uk_thread *child, + struct uk_thread *parent) { struct uk_posix_clonetab_entry *itr; struct _clonetab_init_call_args init_args; @@ -227,7 +227,7 @@ out: * were created with clone * NOTE: This function is called from child TLS context */ -static void uk_posix_clonetab_term(struct uk_thread *child) +void pprocess_clonetab_term(struct uk_thread *child) { struct uk_posix_clonetab_entry *itr; @@ -258,7 +258,8 @@ static void uk_posix_clonetab_term(struct uk_thread *child) cl_status.is_cloned = false; cl_status.cl_flags = 0x0; } -UK_THREAD_INIT_PRIO(0x0, uk_posix_clonetab_term, UK_PRIO_LATEST); + +UK_THREAD_INIT_PRIO(0x0, pprocess_clonetab_term, UK_PRIO_LATEST); /* * NOTE: From man pages about clone(2) @@ -545,9 +546,9 @@ int uk_clone(struct clone_args *cl_args, size_t cl_args_len, } /* Call clone handler table but treat CLONE_SETTLS as handled */ - ret = _uk_posix_clonetab_init(cl_args, cl_args_len, - CLONE_SETTLS, - child, t); + ret = pprocess_clonetab_init(cl_args, cl_args_len, + CLONE_SETTLS, + child, t); if (ret < 0) goto err_free_child; uk_pr_debug("Thread cloned %p (%s) -> %p (%s): %d\n", diff --git a/lib/posix-process/execve.c b/lib/posix-process/execve.c index 0ee8eb51e..52bc7fa80 100644 --- a/lib/posix-process/execve.c +++ b/lib/posix-process/execve.c @@ -83,6 +83,11 @@ static int pprocess_cleanup(struct posix_process *pprocess) return 0; } +int pprocess_raise_execve_event(struct posix_process_execve_event_data *data) +{ + return uk_raise_event(POSIX_PROCESS_EXECVE_EVENT, data); +} + UK_SYSCALL_R_E_DEFINE(int, execve, const char *, pathname, char *const *, argv, char *const *, envp) @@ -170,7 +175,7 @@ UK_SYSCALL_R_E_DEFINE(int, execve, const char *, pathname, * internal cleanup. */ event_data.thread = this_thread; - rc = uk_raise_event(POSIX_PROCESS_EXECVE_EVENT, &event_data); + rc = pprocess_raise_execve_event(&event_data); if (unlikely(rc < 0)) { uk_pr_err("execve event error (%d)\n", rc); goto err_free_stack_new; diff --git a/lib/posix-process/exportsyms.uk b/lib/posix-process/exportsyms.uk index d4d6f6fc9..034aa0c3a 100644 --- a/lib/posix-process/exportsyms.uk +++ b/lib/posix-process/exportsyms.uk @@ -53,3 +53,4 @@ sigprocmask tgkill signalfd uk_posix_process_create_pthread +uk_posix_process_run diff --git a/lib/posix-process/include/uk/process.h b/lib/posix-process/include/uk/process.h index dd48bf500..3faa9ac2e 100644 --- a/lib/posix-process/include/uk/process.h +++ b/lib/posix-process/include/uk/process.h @@ -226,8 +226,26 @@ int uk_posix_process_create_pthread(struct uk_thread *thread); #endif /* CONFIG_LIBPOSIX_PROCESS_MULTITHREADING */ -#if CONFIG_LIBPOSIX_PROCESS_EXECVE +#if CONFIG_LIBPOSIX_PROCESS_MULTIPROCESS + +typedef int (*uk_posix_process_mainlike_func)(int argc, char *argv[]); + +/** + * Spawn a process that jumps into function. + * + * DO NOT USE. This is only necessary when we create a new process + * for main() in multiprocess. + * + * @param fn Function to jump to. + * @param argc Arg count + * @param argv Arg vector + * @return Child pid to parent, or negative value on failure. + */ +pid_t uk_posix_process_run(uk_posix_process_mainlike_func fn, + int argc, const char **argv); +#endif /* CONFIG_LIBPOSIX_PROCESS_MULTIPROCESS */ +#if CONFIG_LIBPOSIX_PROCESS_EXECVE /* Data delivered to the handlers of the POSIX_PROCESS_EXECVE_EVENT */ struct posix_process_execve_event_data { struct uk_thread *thread; diff --git a/lib/posix-process/process.c b/lib/posix-process/process.c index dcd811e98..c535f5d5c 100644 --- a/lib/posix-process/process.c +++ b/lib/posix-process/process.c @@ -18,6 +18,8 @@ struct uk_thread *pprocess_thread_main; #if CONFIG_LIBPOSIX_PROCESS_MULTITHREADING +#include /* SIGCHLD */ + #include #include #include @@ -26,6 +28,7 @@ struct uk_thread *pprocess_thread_main; #include #include #include +#include #include #if CONFIG_LIBPOSIX_PROCESS_SIGNAL @@ -343,6 +346,91 @@ err_out: return ret; } +#if CONFIG_LIBPOSIX_PROCESS_MULTIPROCESS +pid_t uk_posix_process_run(uk_posix_process_mainlike_func fn, + int argc, const char *argv[]) +{ + struct posix_process_execve_event_data event_data; + struct uk_sched *s = uk_sched_current(); + struct clone_args cl_args; + struct uk_thread *thread; + struct uk_thread *parent; + pid_t parent_tid; + pid_t tid; + int ret; + + UK_ASSERT(s); + + parent = uk_thread_current(); + parent_tid = ukthread2tid(parent); + UK_ASSERT(parent_tid > 0); + + /* Create container thread */ + thread = uk_thread_create_container(uk_alloc_get_default(), + s->a_stack, + STACK_SIZE, + s->a_auxstack, 0, s->a_uktls, + false, "application", NULL, NULL); + if (unlikely(!thread)) { + uk_pr_err("Could not create thread\n"); + return -ENOMEM; + } + + /* Create new process */ + ret = pprocess_create(uk_alloc_get_default(), thread, parent); + if (unlikely(ret)) { + uk_pr_err("Could not create process (%d)\n", ret); + goto err_free_thread; + } + + tid = ukthread2tid(thread); + + /* Iterate clonetab. We pass the flags used when creating + * a new process, i.e. CLONE_VM | CLONE_VFORK | SIGCHLD. + */ + cl_args = (struct clone_args) { + .flags = CLONE_VM | CLONE_VFORK, + .child_tid = tid, + .parent_tid = parent_tid, + .exit_signal = SIGCHLD, + }; + ret = pprocess_clonetab_init(&cl_args, sizeof(cl_args), 0, + thread, parent); + if (unlikely(ret)) { + uk_pr_err("clonetab execution error (%d)\n", ret); + goto err_free_process; + } + + /* Raise the execve event */ + event_data.thread = thread; + ret = pprocess_raise_execve_event(&event_data); + if (unlikely(ret < 0)) { + uk_pr_err("exeve event error (%d)\n", ret); + goto err_term_clonetab; + } + + /* Schedule the process */ + uk_thread_container_init_fn2(thread, + (uk_thread_fn2_t)fn, + (void *)(unsigned long)argc, + (void *)argv); + uk_sched_thread_add(s, thread); + + return ukthread2pid(thread); + +err_term_clonetab: + pprocess_clonetab_term(thread); + +err_free_process: + pprocess_release(tid2pprocess(tid)); + +err_free_thread: + uk_thread_release(thread); + + return ret; +} +#endif /* CONFIG_LIBPOSIX_PROCESS_MULTIPROCESS */ + /* Releases pprocess memory and other resources. * NOTE: All pthreads must be removed already * from this pprocess. All chilren must diff --git a/lib/posix-process/process.h b/lib/posix-process/process.h index 7505b7b70..c023be93c 100644 --- a/lib/posix-process/process.h +++ b/lib/posix-process/process.h @@ -14,6 +14,7 @@ #if CONFIG_LIBPOSIX_PROCESS_MULTITHREADING #include #include +#include #include #include #endif /* CONFIG_LIBPOSIX_PROCESS_MULTITHREADING */ @@ -194,6 +195,17 @@ int pprocess_create(struct uk_alloc *a, struct uk_thread *thread, int uk_clone(struct clone_args *cl_args, size_t cl_args_len, struct ukarch_execenv *execenv); + +int pprocess_clonetab_init(const struct clone_args *cl_args, size_t cl_args_len, + __u64 cl_flags_optional, struct uk_thread *child, + struct uk_thread *parent); + +void pprocess_clonetab_term(struct uk_thread *child); + +#if CONFIG_LIBPOSIX_PROCESS_EXECVE +int pprocess_raise_execve_event(struct posix_process_execve_event_data *data); +#endif /* CONFIG_LIBPOSIX_PROCESS_EXECVE */ + #endif /* CONFIG_LIBPOSIX_PROCESS_MULTITHREADING */ #endif /* __PROCESS_H_INTERNAL__ */ -- 2.39.5