From aaa08366e6384d9933a405d1218b03c1b167f9e5 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Tue, 10 Dec 2019 16:49:55 +0100 Subject: [PATCH] file: extend exec acl checks to commands with arguments When the initial exec permission check on the executable path fails, concatenate the command line with spaces and use the resulting string as lookup path for a second exec permission check. This allows for exec acls similar to this example: "file": { "/usr/bin/program --flag --option=1 arg *": [ "exec" ] } The example above would allow executing `/usr/bin/program` with the arguments `--flag`, `--option=1` and `arg` in exactly this order, followed by any number of optional arguments as denoted by the asterisk. Signed-off-by: Jo-Philipp Wich --- file.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/file.c b/file.c index 4ed2e5c..bd7af56 100644 --- a/file.c +++ b/file.c @@ -43,6 +43,9 @@ /* limit of regular files and command output data */ #define RPC_FILE_MAX_SIZE (4096 * 64) +/* limit of command line length for exec acl checks */ +#define RPC_CMDLINE_MAX_SIZE (1024) + #define ustream_for_each_read_buffer(stream, ptr, len) \ for (ptr = ustream_get_read_buf(stream, &len); \ ptr != NULL && len > 0; \ @@ -71,6 +74,7 @@ struct rpc_file_exec_context { static struct blob_buf buf; static char *canonpath; +static char cmdstr[RPC_CMDLINE_MAX_SIZE]; enum { RPC_F_R_PATH, @@ -801,7 +805,7 @@ rpc_file_exec_run(const char *cmd, const struct blob_attr *sid, struct blob_attr *cur; uint8_t arglen; - char *executable, **args, **tmp; + char *executable, **args, **tmp, *p; struct rpc_file_exec_context *c; @@ -816,7 +820,29 @@ rpc_file_exec_run(const char *cmd, const struct blob_attr *sid, return UBUS_STATUS_UNKNOWN_ERROR; if (!rpc_file_access(sid, executable, "exec")) - return UBUS_STATUS_PERMISSION_DENIED; + { + if (arg == NULL || strlen(executable) >= sizeof(cmdstr)) + return UBUS_STATUS_PERMISSION_DENIED; + + arglen = 0; + p = cmdstr + sprintf(cmdstr, "%s", executable); + + blobmsg_for_each_attr(cur, arg, rem) + { + if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) + continue; + + if (arglen == 255 || + p + blobmsg_data_len(cur) >= cmdstr + sizeof(cmdstr)) + break; + + p += sprintf(p, " %s", blobmsg_get_string(cur)); + arglen++; + } + + if (!rpc_file_access(sid, cmdstr, "exec")) + return UBUS_STATUS_PERMISSION_DENIED; + } c = malloc(sizeof(*c));