Created
February 22, 2024 16:07
-
-
Save oskarirauta/19b43709147d39d8d2d4231a94bc212a to your computer and use it in GitHub Desktop.
add exec function to openwrt's uxc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- a/uxc.c | |
+++ b/uxc.c | |
@@ -27,6 +27,7 @@ | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
+#include <sched.h> | |
#include <libubus.h> | |
#include <libubox/avl-cmp.h> | |
@@ -71,6 +72,7 @@ struct settings { | |
enum uxc_cmd { | |
CMD_ATTACH, | |
+ CMD_EXEC, | |
CMD_LIST, | |
CMD_BOOT, | |
CMD_START, | |
@@ -112,6 +114,7 @@ static int usage(void) { | |
printf("commands:\n"); | |
printf("\tlist [--json]\t\t\t\tlist all configured containers\n"); | |
printf("\tattach <conf>\t\t\t\tattach to container console\n"); | |
+ printf("\texec <conf> [cmd]\t\t\texecute command or shell in container\n"); | |
printf("\tcreate <conf>\t\t\t\t(re-)create <conf>\n"); | |
printf("\t\t[--bundle <path>]\t\t\tOCI bundle at <path>\n"); | |
printf("\t\t[--autostart]\t\t\t\tstart on boot\n"); | |
@@ -150,6 +153,29 @@ static const struct blobmsg_policy conf_ | |
[CONF_VOLUMES] = { .name = "volumes", .type = BLOBMSG_TYPE_ARRAY }, | |
}; | |
+static int open_ns(int pid, char *name) { | |
+ | |
+ char *path; | |
+ | |
+ if (asprintf(&path, "/proc/%d/%s", pid, name) == -1 ) { | |
+ fprintf(stderr, "cannot allocate path /proc/%d/%s\n", pid, name); | |
+ return -1; | |
+ } | |
+ | |
+ struct stat st; | |
+ if (stat(path, &st) == 0 && S_ISLNK(st.st_mode)) { | |
+ fprintf(stderr, "file /proc/%d/%s does not exists or is not a symbolic link\n", pid, name); | |
+ return -1; | |
+ } | |
+ | |
+ int fd = open(path, O_RDONLY); | |
+ if ( fd < 0 ) { | |
+ fprintf(stderr, "cannot open /proc/%d/%s\n", pid, name); | |
+ return fd; | |
+ } | |
+ return fd; | |
+} | |
+ | |
static int conf_load(bool load_settings) | |
{ | |
int gl_flags = GLOB_NOESCAPE | GLOB_MARK; | |
@@ -613,6 +639,94 @@ static int uxc_attach(const char *contai | |
return 0; | |
} | |
+static int uxc_exec(const char *container_name, char **args) | |
+{ | |
+ struct blob_attr *cur, *tb[__CONF_MAX], *ts[__STATE_MAX]; | |
+ struct runtime_state *rsstate = NULL; | |
+ int rem, container_pid; | |
+ bool found = false; | |
+ | |
+ blobmsg_for_each_attr(cur, blob_data(conf.head), rem) { | |
+ blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur)); | |
+ if (!tb[CONF_NAME] || !tb[CONF_PATH]) | |
+ continue; | |
+ | |
+ if (strcmp(container_name, blobmsg_get_string(tb[CONF_NAME]))) | |
+ continue; | |
+ | |
+ found = true; | |
+ break; | |
+ } | |
+ | |
+ if (!found) | |
+ return -ENOENT; | |
+ | |
+ rsstate = avl_find_element(&runtime, container_name, rsstate, avl); | |
+ container_pid = 0; | |
+ | |
+ if (rsstate && rsstate->ocistate) { | |
+ blobmsg_parse(state_policy, __STATE_MAX, ts, blobmsg_data(rsstate->ocistate), blobmsg_len(rsstate->ocistate)); | |
+ container_pid = blobmsg_get_u32(ts[STATE_PID]); | |
+ } | |
+ | |
+ if (container_pid < 2) { | |
+ fprintf(stderr, "failed to container pid for %s\n", container_name); | |
+ return -ENOENT; | |
+ } | |
+ | |
+ int ns_ipc = open_ns(container_pid, "ns/ipc"); | |
+ int ns_mnt = open_ns(container_pid, "ns/mnt"); | |
+ int ns_net = open_ns(container_pid, "ns/net"); | |
+ int ns_uts = open_ns(container_pid, "ns/uts"); | |
+ int ns_pid = open_ns(container_pid, "ns/pid"); | |
+ int ns_root = open_ns(container_pid, "root"); | |
+ | |
+ if (ns_ipc == -1 || ns_mnt == -1 || ns_net == -1 || ns_uts == -1 || ns_pid == -1 || ns_root == -1) | |
+ return -ENXIO; | |
+ | |
+ if (setns(ns_ipc, 0) == -1) { | |
+ fprintf(stderr, "failed to enter ipc namespace\n"); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ if (setns(ns_mnt, 0) == -1) { | |
+ fprintf(stderr, "failed to enter mnt namespace\n"); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ if (setns(ns_net, 0) == -1) { | |
+ fprintf(stderr, "failed to enter net namespace\n"); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ if (setns(ns_uts, 0) == -1) { | |
+ fprintf(stderr, "failed to enter uts namespace\n"); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ if (setns(ns_pid, 0) == -1) { | |
+ fprintf(stderr, "failed to enter pid namespace\n"); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ if (fchdir(ns_root) == -1) { | |
+ fprintf(stderr, "failed to change working directory\n"); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ if (chroot(".") == -1) { | |
+ fprintf(stderr, "failed to chroot\n"); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ if (execv(args[0], args) == -1) { | |
+ fprintf(stderr, "failed to execute %s in container %s\n", args[0], container_name); | |
+ return -ENXIO; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
static int uxc_state(char *name) | |
{ | |
struct runtime_state *rsstate = avl_find_element(&runtime, name, rsstate, avl); | |
@@ -1413,7 +1527,10 @@ int main(int argc, char **argv) | |
if (ret) | |
goto settings_avl_out; | |
- while (true) { | |
+ if ( argc > 1 && !strcmp("exec", argv[1])) | |
+ cmd = CMD_EXEC; | |
+ | |
+ while (cmd != CMD_EXEC) { | |
int option_index = 0; | |
c = getopt_long(argc, argv, OPT_ARGS, long_options, &option_index); | |
if (c == -1) | |
@@ -1466,13 +1583,15 @@ int main(int argc, char **argv) | |
} | |
} | |
- if (optind == argc) | |
+ if (optind == argc && cmd != CMD_EXEC) | |
goto usage_out; | |
if (!strcmp("list", argv[optind])) | |
cmd = CMD_LIST; | |
else if (!strcmp("attach", argv[optind])) | |
cmd = CMD_ATTACH; | |
+ else if (!strcmp("exec", argv[optind])) | |
+ cmd = CMD_EXEC; | |
else if (!strcmp("boot", argv[optind])) | |
cmd = CMD_BOOT; | |
else if(!strcmp("start", argv[optind])) | |
@@ -1498,6 +1617,24 @@ int main(int argc, char **argv) | |
ret = uxc_attach(argv[optind + 1]); | |
break; | |
+ case CMD_EXEC: | |
+ if (argc < 3) | |
+ goto usage_out; | |
+ | |
+ int i; | |
+ char *cmd = argc < 4 ? "/bin/sh" : argv[3]; | |
+ int cnt = argc < 5 ? 2 : ( argc - 2 ); | |
+ char **args = (char **)malloc(cnt * sizeof(char*)); | |
+ | |
+ if (argc > 3) { | |
+ for (i = 0; i < cnt - 1; i++ ) | |
+ args[i] = argv[i + 3]; | |
+ } else args[0] = cmd; | |
+ | |
+ args[cnt - 1] = NULL; | |
+ ret = uxc_exec(argv[optind + 1], args); | |
+ break; | |
+ | |
case CMD_LIST: | |
ret = uxc_list(); | |
break; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment