diff --git a/configure.ac b/configure.ac index 7b3a5a3..83e60b1 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,11 @@ AS_IF([test "x$enable_dl" != "xno"], [ dnl include support for libkrun (EXPERIMENTAL) AC_ARG_WITH([libkrun], AS_HELP_STRING([--with-libkrun], [build with libkrun support])) AS_IF([test "x$with_libkrun" = "xyes"], AC_CHECK_HEADERS([libkrun.h], AC_DEFINE([HAVE_LIBKRUN], 1, [Define if libkrun is available]), [AC_MSG_ERROR([*** Missing libkrun headers])])) + +dnl include support for wasmedge (EXPERIMENTAL) +AC_ARG_WITH([wasmedge], AS_HELP_STRING([--with-wasmedge], [build with WasmEdge support])) +AS_IF([test "x$with_wasmedge" = "xyes"], AC_CHECK_HEADERS([wasmedge.h], AC_DEFINE([HAVE_WASMEDGE], 1, [Define if WasmEdge is available]), [AC_MSG_ERROR([*** Missing wasmedge headers])])) + dnl libseccomp AC_ARG_ENABLE([seccomp], AS_HELP_STRING([--disable-seccomp], [Ignore libseccomp and disable support])) diff --git a/src/libcrun/container.c b/src/libcrun/container.c index 63ef75d..3b04e15 100644 --- a/src/libcrun/container.c +++ b/src/libcrun/container.c @@ -51,6 +51,10 @@ # include #endif +#ifdef HAVE_WASMEDGE +# include +#endif + #ifdef HAVE_SYSTEMD # include #endif @@ -88,6 +92,11 @@ struct container_entrypoint_s execve. */ int (*exec_func) (void *container, void *arg, const char *pathname, char *const argv[]); void *exec_func_arg; + +#if HAVE_DLOPEN && HAVE_WASMEDGE + /* wasmedge library */ + void *wasmedge_handle; +#endif }; struct sync_socket_message_s @@ -813,6 +822,102 @@ libkrun_do_exec (void *container, void *arg, const char *pathname, char *const a } #endif +#if HAVE_DLOPEN && HAVE_WASMEDGE +static int +libwasmedge_do_exec (void *container, void *handle, const char *pathname, char *const argv[]) +{ + runtime_spec_schema_config_schema *def = ((libcrun_container_t *) container)->container_def; + WasmEdge_ConfigureContext *(*WasmEdge_ConfigureCreate) (void); + void (*WasmEdge_ConfigureDelete) (WasmEdge_ConfigureContext * Cxt); + void (*WasmEdge_ConfigureAddProposal) (WasmEdge_ConfigureContext * Cxt, const enum WasmEdge_Proposal Prop); + void (*WasmEdge_ConfigureAddHostRegistration) (WasmEdge_ConfigureContext * Cxt, enum WasmEdge_HostRegistration Host); + WasmEdge_VMContext *(*WasmEdge_VMCreate) (const WasmEdge_ConfigureContext *ConfCxt, WasmEdge_StoreContext *StoreCxt); + void (*WasmEdge_VMDelete) (WasmEdge_VMContext * Cxt); + WasmEdge_Result (*WasmEdge_VMRegisterModuleFromFile) (WasmEdge_VMContext * Cxt, WasmEdge_String ModuleName, const char *Path); + WasmEdge_ImportObjectContext *(*WasmEdge_VMGetImportModuleContext) (WasmEdge_VMContext * Cxt, const enum WasmEdge_HostRegistration Reg); + void (*WasmEdge_ImportObjectInitWASI) (WasmEdge_ImportObjectContext * Cxt, const char *const *Args, const uint32_t ArgLen, const char *const *Envs, const uint32_t EnvLen, const char *const *Dirs, const uint32_t DirLen, const char *const *Preopens, const uint32_t PreopenLen); + void (*WasmEdge_ImportObjectInitWasmEdgeProcess) (WasmEdge_ImportObjectContext * Cxt, const char *const *AllowedCmds, const uint32_t CmdsLen, const bool AllowAll); + WasmEdge_Result (*WasmEdge_VMRunWasmFromFile) (WasmEdge_VMContext * Cxt, const char *Path, const WasmEdge_String FuncName, const WasmEdge_Value *Params, const uint32_t ParamLen, WasmEdge_Value *Returns, const uint32_t ReturnLen); + bool (*WasmEdge_ResultOK) (const WasmEdge_Result Res); + WasmEdge_String (*WasmEdge_StringCreateByCString) (const char *Str); + + WasmEdge_ConfigureCreate = dlsym (handle, "WasmEdge_ConfigureCreate"); + WasmEdge_ConfigureDelete = dlsym (handle, "WasmEdge_ConfigureDelete"); + WasmEdge_ConfigureAddProposal = dlsym (handle, "WasmEdge_ConfigureAddProposal"); + WasmEdge_ConfigureAddHostRegistration = dlsym (handle, "WasmEdge_ConfigureAddHostRegistration"); + WasmEdge_VMCreate = dlsym (handle, "WasmEdge_VMCreate"); + WasmEdge_VMDelete = dlsym (handle, "WasmEdge_VMDelete"); + WasmEdge_VMRegisterModuleFromFile = dlsym (handle, "WasmEdge_VMRegisterModuleFromFile"); + WasmEdge_VMGetImportModuleContext = dlsym (handle, "WasmEdge_VMGetImportModuleContext"); + WasmEdge_ImportObjectInitWASI = dlsym (handle, "WasmEdge_ImportObjectInitWASI"); + WasmEdge_ImportObjectInitWasmEdgeProcess = dlsym (handle, "WasmEdge_ImportObjectInitWasmEdgeProcess"); + WasmEdge_VMRunWasmFromFile = dlsym (handle, "WasmEdge_VMRunWasmFromFile"); + WasmEdge_ResultOK = dlsym (handle, "WasmEdge_ResultOK"); + WasmEdge_StringCreateByCString = dlsym (handle, "WasmEdge_StringCreateByCString"); + if (WasmEdge_ConfigureCreate == NULL || WasmEdge_ConfigureDelete == NULL || WasmEdge_ConfigureAddProposal == NULL || WasmEdge_ConfigureAddHostRegistration == NULL || WasmEdge_VMCreate == NULL || WasmEdge_VMDelete == NULL || WasmEdge_VMRegisterModuleFromFile == NULL || WasmEdge_VMGetImportModuleContext == NULL || WasmEdge_ImportObjectInitWASI == NULL || WasmEdge_ImportObjectInitWasmEdgeProcess == NULL || WasmEdge_VMRunWasmFromFile == NULL || WasmEdge_ResultOK == NULL || WasmEdge_StringCreateByCString == NULL) + { + fprintf (stderr, "could not find symbol in `libwasmedge.so`"); + dlclose (handle); + return -1; + } + + WasmEdge_ConfigureContext *configure = WasmEdge_ConfigureCreate (); + if (UNLIKELY (configure == NULL)) + error (EXIT_FAILURE, 0, "could not create wasmedge configure"); + + WasmEdge_ConfigureAddProposal (configure, WasmEdge_Proposal_BulkMemoryOperations); + WasmEdge_ConfigureAddProposal (configure, WasmEdge_Proposal_ReferenceTypes); + WasmEdge_ConfigureAddProposal (configure, WasmEdge_Proposal_SIMD); + WasmEdge_ConfigureAddHostRegistration (configure, WasmEdge_HostRegistration_Wasi); + WasmEdge_ConfigureAddHostRegistration (configure, WasmEdge_HostRegistration_WasmEdge_Process); + + WasmEdge_VMContext *vm = WasmEdge_VMCreate (configure, NULL); + if (UNLIKELY (vm == NULL)) + { + WasmEdge_ConfigureDelete (configure); + error (EXIT_FAILURE, 0, "could not create wasmedge vm"); + } + + WasmEdge_ImportObjectContext *wasi_module = WasmEdge_VMGetImportModuleContext (vm, WasmEdge_HostRegistration_Wasi); + if (UNLIKELY (wasi_module == NULL)) + { + WasmEdge_VMDelete (vm); + WasmEdge_ConfigureDelete (configure); + error (EXIT_FAILURE, 0, "could not get wasmedge wasi module context"); + } + + WasmEdge_ImportObjectContext *proc_module = WasmEdge_VMGetImportModuleContext (vm, WasmEdge_HostRegistration_WasmEdge_Process); + if (UNLIKELY (proc_module == NULL)) + { + WasmEdge_VMDelete (vm); + WasmEdge_ConfigureDelete (configure); + error (EXIT_FAILURE, 0, "could not get wasmedge process module context"); + } + + uint32_t argn = 0; + for (char *const *arg = argv; *arg != NULL; ++arg, ++argn) + ; + + const char *dirs[1] = { "/:/" }; + WasmEdge_ImportObjectInitWASI (wasi_module, (const char *const *) &argv[0], argn, NULL, 0, dirs, 1, NULL, 0); + + WasmEdge_ImportObjectInitWasmEdgeProcess (proc_module, NULL, 0, true); + + WasmEdge_Result result = WasmEdge_VMRunWasmFromFile (vm, pathname, WasmEdge_StringCreateByCString ("_start"), NULL, 0, NULL, 0); + + if (UNLIKELY (! WasmEdge_ResultOK (result))) + { + WasmEdge_VMDelete (vm); + WasmEdge_ConfigureDelete (configure); + error (EXIT_FAILURE, 0, "could not set krun executable"); + } + + WasmEdge_VMDelete (vm); + WasmEdge_ConfigureDelete (configure); + return 0; +} +#endif + static int libcrun_configure_libkrun (struct container_entrypoint_s *args, libcrun_error_t *err) { @@ -835,9 +940,33 @@ libcrun_configure_libkrun (struct container_entrypoint_s *args, libcrun_error_t #endif } +#if HAVE_DLOPEN && HAVE_WASMEDGE +static int +libcrun_configure_libwasmedge (struct container_entrypoint_s *args, libcrun_error_t *err) +{ + void *handle; + + handle = dlopen ("libwasmedge_c.so", RTLD_NOW); + if (handle == NULL) + return crun_make_error (err, 0, "could not load `libwasmedge_c.so`: %s", dlerror ()); + + args->wasmedge_handle = handle; + + return 0; +} +#endif + static int libcrun_configure_handler (struct container_entrypoint_s *args, libcrun_error_t *err) { +#if HAVE_DLOPEN && HAVE_WASMEDGE + int ret = libcrun_configure_libwasmedge (args, err); + if (UNLIKELY (ret < 0)) + { + return ret; + } +#endif + const char *annotation; annotation = find_annotation (args->container, "run.oci.handler"); @@ -1469,6 +1598,14 @@ container_init (void *args, char *notify_socket, int sync_socket, libcrun_error_ (void) lseek (2, 0, SEEK_END); } +#if HAVE_DLOPEN && HAVE_WASMEDGE + if (has_postfix (exec_path, ".wasm")) + { + ret = libwasmedge_do_exec (entrypoint_args->container, entrypoint_args->wasmedge_handle, exec_path, def->process->args); + _exit (ret); + } +#endif + if (entrypoint_args->exec_func) { ret = entrypoint_args->exec_func (entrypoint_args->container, entrypoint_args->exec_func_arg, exec_path, diff --git a/src/libcrun/utils.c b/src/libcrun/utils.c index e5db288..8ca93c9 100644 --- a/src/libcrun/utils.c +++ b/src/libcrun/utils.c @@ -1594,6 +1594,14 @@ has_prefix (const char *str, const char *prefix) return strlen (str) >= prefix_len && memcmp (str, prefix, prefix_len) == 0; } +int +has_postfix (const char *str, const char *postfix) +{ + size_t postfix_len = strlen (postfix); + size_t str_len = strlen (str); + return str_len >= postfix_len && memcmp (str + (str_len - postfix_len), postfix, postfix_len) == 0; +} + static int check_access (const char *path) { diff --git a/src/libcrun/utils.h b/src/libcrun/utils.h index 5e0792c..1ba4b36 100644 --- a/src/libcrun/utils.h +++ b/src/libcrun/utils.h @@ -250,6 +250,8 @@ int parse_json_file (yajl_val *out, const char *jsondata, struct parser_context int has_prefix (const char *str, const char *prefix); +int has_postfix (const char *str, const char *postfix); + const char *find_executable (const char *executable_path, const char *cwd); int copy_recursive_fd_to_fd (int srcfd, int destfd, const char *srcname, const char *destname, libcrun_error_t *err);