Re-add seccomp policy tracking.
This makes it easier to attribute a policy violation to the policy and
makes it possible for crash reporter to grab the environment
variable and include it in the crash report.
This reverts:
https://android-review.googlesource.com/c/platform/external/minijail/+/1839493
Relanding:
https://android-review.googlesource.com/c/platform/external/minijail/+/1824233
https://android-review.googlesource.com/c/platform/external/minijail/+/1824238
Bug: 199444797
Test: initctl restart ui # and check /var/log/messages for arc++ crash
Test: tast run <host> crash.Seccomp
Change-Id: I1cfdc30a734ff98bf8777ebc8997011b922f0b3c
diff --git a/libminijail.c b/libminijail.c
index 13df237..265c5f2 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -189,6 +189,7 @@
struct hook *hooks_tail;
struct preserved_fd preserved_fds[MAX_PRESERVED_FDS];
size_t preserved_fd_count;
+ char *seccomp_policy_path;
};
static void run_hooks_or_die(const struct minijail *j,
@@ -984,6 +985,10 @@
j->filter_len = 0;
j->filter_prog = NULL;
j->flags.no_new_privs = 0;
+ if (j->seccomp_policy_path) {
+ free(j->seccomp_policy_path);
+ }
+ j->seccomp_policy_path = NULL;
}
static int seccomp_should_use_filters(struct minijail *j)
@@ -1145,6 +1150,10 @@
die("failed to compile seccomp filter BPF program in '%s'",
path);
}
+ if (j->seccomp_policy_path) {
+ free(j->seccomp_policy_path);
+ }
+ j->seccomp_policy_path = strdup(path);
}
void API minijail_parse_seccomp_filters_from_fd(struct minijail *j, int fd)
@@ -1171,7 +1180,10 @@
die("failed to compile seccomp filter BPF program from fd %d",
fd);
}
- free(path);
+ if (j->seccomp_policy_path) {
+ free(j->seccomp_policy_path);
+ }
+ j->seccomp_policy_path = path;
}
void API minijail_set_seccomp_filters(struct minijail *j,
@@ -1281,6 +1293,8 @@
}
for (i = 0; i < j->cgroup_count; ++i)
marshal_append_string(state, j->cgroups[i]);
+ if (j->seccomp_policy_path)
+ marshal_append_string(state, j->seccomp_policy_path);
}
size_t API minijail_size(const struct minijail *j)
@@ -1445,8 +1459,23 @@
++j->cgroup_count;
}
+ if (j->seccomp_policy_path) { /* stale pointer */
+ char *seccomp_policy_path = consumestr(&serialized, &length);
+ if (!seccomp_policy_path)
+ goto bad_cgroups;
+ j->seccomp_policy_path = strdup(seccomp_policy_path);
+ if (!j->seccomp_policy_path)
+ goto bad_cgroups;
+ }
+
return 0;
+ /*
+ * If more is added after j->seccomp_policy_path, then this is needed:
+ * if (j->seccomp_policy_path)
+ * free(j->seccomp_policy_path);
+ */
+
bad_cgroups:
free_mounts_list(j);
free_remounts_list(j);
@@ -1480,6 +1509,7 @@
j->hostname = NULL;
j->alt_syscall_table = NULL;
j->cgroup_count = 0;
+ j->seccomp_policy_path = NULL;
out:
return ret;
}
@@ -2587,6 +2617,19 @@
#endif
}
+/*
+ * This is for logging purposes and does not change the enforced seccomp
+ * filter.
+ */
+static int setup_seccomp_policy_path(const struct minijail *j,
+ char ***child_env)
+{
+ return minijail_setenv(child_env, kSeccompPolicyPathEnvVar,
+ j->seccomp_policy_path ? j->seccomp_policy_path
+ : "NO-LABEL",
+ 1 /* overwrite */);
+}
+
static int setup_pipe(char ***child_env, int fds[2])
{
int r = pipe(fds);
@@ -3079,6 +3122,21 @@
die("filename and elf_fd cannot be set at the same time");
}
+ /*
+ * Only copy the environment if we need to modify it. If this is done
+ * unconditionally, it triggers odd behavior in the ARC container.
+ */
+ if (use_preload || j->seccomp_policy_path) {
+ state_out->child_env =
+ minijail_copy_env(config->envp ? config->envp : environ);
+ if (!state_out->child_env)
+ return ENOMEM;
+ }
+
+ if (j->seccomp_policy_path &&
+ setup_seccomp_policy_path(j, &state_out->child_env))
+ return -EFAULT;
+
if (use_preload) {
if (j->hooks_head != NULL)
die("Minijail hooks are not supported with LD_PRELOAD");
@@ -3089,10 +3147,6 @@
* Before we fork(2) and execve(2) the child process, we need
* to open a pipe(2) to send the minijail configuration over.
*/
- state_out->child_env =
- minijail_copy_env(config->envp ? config->envp : environ);
- if (!state_out->child_env)
- return ENOMEM;
if (setup_preload(j, &state_out->child_env) ||
setup_pipe(&state_out->child_env, state_out->pipe_fds))
return -EFAULT;
@@ -3527,24 +3581,30 @@
if (!WIFEXITED(st)) {
int error_status = st;
- if (WIFSIGNALED(st)) {
- int signum = WTERMSIG(st);
+ if (!WIFSIGNALED(st)) {
+ return error_status;
+ }
+
+ int signum = WTERMSIG(st);
+ /*
+ * We return MINIJAIL_ERR_JAIL if the process received
+ * SIGSYS, which happens when a syscall is blocked by
+ * seccomp filters.
+ * If not, we do what bash(1) does:
+ * $? = 128 + signum
+ */
+ if (signum == SIGSYS) {
+ warn("child process %d had a policy violation (%s)",
+ j->initpid,
+ j->seccomp_policy_path ? j->seccomp_policy_path
+ : "NO-LABEL");
+ error_status = MINIJAIL_ERR_JAIL;
+ } else {
if (signum != expected_signal) {
warn("child process %d received signal %d",
j->initpid, signum);
}
- /*
- * We return MINIJAIL_ERR_JAIL if the process received
- * SIGSYS, which happens when a syscall is blocked by
- * seccomp filters.
- * If not, we do what bash(1) does:
- * $? = 128 + signum
- */
- if (signum == SIGSYS) {
- error_status = MINIJAIL_ERR_JAIL;
- } else {
- error_status = MINIJAIL_ERR_SIG_BASE + signum;
- }
+ error_status = MINIJAIL_ERR_SIG_BASE + signum;
}
return error_status;
}
@@ -3609,6 +3669,8 @@
free(j->alt_syscall_table);
for (i = 0; i < j->cgroup_count; ++i)
free(j->cgroups[i]);
+ if (j->seccomp_policy_path)
+ free(j->seccomp_policy_path);
free(j);
}