Browse Source

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>
Jo-Philipp Wich 4 years ago
parent
commit
aaa08366e6
1 changed files with 28 additions and 2 deletions
  1. 28 2
      file.c

+ 28 - 2
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));