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 <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2019-12-10 16:49:55 +01:00
parent 77ad0de092
commit aaa08366e6

28
file.c
View file

@ -43,6 +43,9 @@
/* limit of regular files and command output data */ /* limit of regular files and command output data */
#define RPC_FILE_MAX_SIZE (4096 * 64) #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) \ #define ustream_for_each_read_buffer(stream, ptr, len) \
for (ptr = ustream_get_read_buf(stream, &len); \ for (ptr = ustream_get_read_buf(stream, &len); \
ptr != NULL && len > 0; \ ptr != NULL && len > 0; \
@ -71,6 +74,7 @@ struct rpc_file_exec_context {
static struct blob_buf buf; static struct blob_buf buf;
static char *canonpath; static char *canonpath;
static char cmdstr[RPC_CMDLINE_MAX_SIZE];
enum { enum {
RPC_F_R_PATH, RPC_F_R_PATH,
@ -801,7 +805,7 @@ rpc_file_exec_run(const char *cmd, const struct blob_attr *sid,
struct blob_attr *cur; struct blob_attr *cur;
uint8_t arglen; uint8_t arglen;
char *executable, **args, **tmp; char *executable, **args, **tmp, *p;
struct rpc_file_exec_context *c; struct rpc_file_exec_context *c;
@ -816,8 +820,30 @@ rpc_file_exec_run(const char *cmd, const struct blob_attr *sid,
return UBUS_STATUS_UNKNOWN_ERROR; return UBUS_STATUS_UNKNOWN_ERROR;
if (!rpc_file_access(sid, executable, "exec")) if (!rpc_file_access(sid, executable, "exec"))
{
if (arg == NULL || strlen(executable) >= sizeof(cmdstr))
return UBUS_STATUS_PERMISSION_DENIED; 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)); c = malloc(sizeof(*c));
if (!c) if (!c)