From: Jann Horn via Containers <containers@lists.linux-foundation.org>
To: Kees Cook <keescook@chromium.org>
Cc: Giuseppe Scrivano <giuseppe@scrivano.org>,
Will Drewry <wad@chromium.org>, Paul Moore <paul@paul-moore.com>,
Linux Containers <containers@lists.linux-foundation.org>,
linux-kernel@vger.kernel.org,
Andy Lutomirski <luto@amacapital.net>,
Christian Brauner <christian.brauner@canonical.com>,
"Michael Kerrisk \(man-pages\)" <mtk.manpages@gmail.com>
Subject: [PATCH 2/3] samples: seccomp: simplify user-trap sample
Date: Mon, 2 Nov 2020 21:37:05 +0100 [thread overview]
Message-ID: <20201102203706.827510-2-jannh@google.com> (raw)
In-Reply-To: <20201102203706.827510-1-jannh@google.com>
Now that the blocking unotify API returns when all users of the filter are
gone, get rid of the helper task that kills the blocked task.
Note that since seccomp only tracks whether tasks are completely gone, not
whether they have exited, we need to handle SIGCHLD while blocked on
SECCOMP_IOCTL_NOTIF_RECV. Alternatively we could also set SIGCHLD to
SIG_IGN and let the kernel autoreap exiting children.
Signed-off-by: Jann Horn <jannh@google.com>
---
samples/seccomp/user-trap.c | 163 +++++++++++++++++++-----------------
1 file changed, 87 insertions(+), 76 deletions(-)
diff --git a/samples/seccomp/user-trap.c b/samples/seccomp/user-trap.c
index b9e666f15998..92d0f9ba58b6 100644
--- a/samples/seccomp/user-trap.c
+++ b/samples/seccomp/user-trap.c
@@ -15,6 +15,7 @@
#include <sys/syscall.h>
#include <sys/user.h>
#include <sys/ioctl.h>
+#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/mount.h>
#include <linux/limits.h>
@@ -198,6 +199,21 @@ static int handle_req(struct seccomp_notif *req,
return ret;
}
+static pid_t worker;
+static int worker_status;
+
+static void sigchld_handler(int sig, siginfo_t *info, void *ctx)
+{
+ if (info->si_pid != worker) {
+ fprintf(stderr, "SIGCHLD from unknown process\n");
+ return;
+ }
+ if (waitpid(worker, &worker_status, 0) != worker) {
+ perror("waitpid");
+ exit(1);
+ }
+}
+
static void set_blocking(int fd)
{
int file_status_flags = fcntl(fd, F_GETFL);
@@ -211,14 +227,26 @@ static void set_blocking(int fd)
int main(void)
{
- int sk_pair[2], ret = 1, status, listener;
- pid_t worker = 0 , tracer = 0;
+ int sk_pair[2], ret = 1, listener;
+ struct seccomp_notif *req;
+ struct seccomp_notif_resp *resp;
+ struct seccomp_notif_sizes sizes;
+ pid_t parent = getpid();
if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair) < 0) {
perror("socketpair");
return 1;
}
+ struct sigaction sigchld_act = {
+ .sa_sigaction = sigchld_handler,
+ .sa_flags = SA_SIGINFO
+ };
+ if (sigaction(SIGCHLD, &sigchld_act, NULL)) {
+ perror("sigaction");
+ return 1;
+ }
+
worker = fork();
if (worker < 0) {
perror("fork");
@@ -226,6 +254,14 @@ int main(void)
}
if (worker == 0) {
+ /* quit if the parent dies */
+ if (prctl(PR_SET_PDEATHSIG, SIGKILL)) {
+ perror("PR_SET_PDEATHSIG");
+ exit(1);
+ }
+ if (getppid() != parent)
+ exit(1);
+
listener = user_trap_syscall(__NR_mount,
SECCOMP_FILTER_FLAG_NEW_LISTENER);
if (listener < 0) {
@@ -283,87 +319,69 @@ int main(void)
*/
listener = recv_fd(sk_pair[0]);
if (listener < 0)
- goto out_kill;
+ goto close_pair;
set_blocking(listener);
- /*
- * Fork a task to handle the requests. This isn't strictly necessary,
- * but it makes the particular writing of this sample easier, since we
- * can just wait ofr the tracee to exit and kill the tracer.
- */
- tracer = fork();
- if (tracer < 0) {
- perror("fork");
- goto out_kill;
+ if (seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes) < 0) {
+ perror("seccomp(GET_NOTIF_SIZES)");
+ goto out_close;
}
- if (tracer == 0) {
- struct seccomp_notif *req;
- struct seccomp_notif_resp *resp;
- struct seccomp_notif_sizes sizes;
+ req = malloc(sizes.seccomp_notif);
+ if (!req)
+ goto out_close;
+
+ resp = malloc(sizes.seccomp_notif_resp);
+ if (!resp)
+ goto out_req;
+ memset(resp, 0, sizes.seccomp_notif_resp);
+
+ while (1) {
+ memset(req, 0, sizes.seccomp_notif);
+ if (ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, req)) {
+ if (errno == ENOTCONN) {
+ /* The child process went away. */
+ break;
+ } else if (errno == EINTR) {
+ continue;
+ }
- if (seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes) < 0) {
- perror("seccomp(GET_NOTIF_SIZES)");
- goto out_close;
+ perror("ioctl recv");
+ goto out_resp;
}
- req = malloc(sizes.seccomp_notif);
- if (!req)
- goto out_close;
-
- resp = malloc(sizes.seccomp_notif_resp);
- if (!resp)
- goto out_req;
- memset(resp, 0, sizes.seccomp_notif_resp);
+ if (handle_req(req, resp, listener) < 0)
+ goto out_resp;
- while (1) {
- memset(req, 0, sizes.seccomp_notif);
- if (ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, req)) {
- if (errno == ENOTCONN)
- exit(0);
-
- perror("ioctl recv");
- goto out_resp;
- }
-
- if (handle_req(req, resp, listener) < 0)
- goto out_resp;
-
- /*
- * ENOENT here means that the task may have gotten a
- * signal and restarted the syscall. It's up to the
- * handler to decide what to do in this case, but for
- * the sample code, we just ignore it. Probably
- * something better should happen, like undoing the
- * mount, or keeping track of the args to make sure we
- * don't do it again.
- */
- if (ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0 &&
- errno != ENOENT) {
- perror("ioctl send");
- goto out_resp;
- }
+ /*
+ * ENOENT here means that the task may have gotten a
+ * signal and restarted the syscall. It's up to the
+ * handler to decide what to do in this case, but for
+ * the sample code, we just ignore it. Probably
+ * something better should happen, like undoing the
+ * mount, or keeping track of the args to make sure we
+ * don't do it again.
+ */
+ if (ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0 &&
+ errno != ENOENT) {
+ perror("ioctl send");
+ goto out_resp;
}
+ }
+ ret = 0;
+
out_resp:
- free(resp);
+ free(resp);
out_req:
- free(req);
+ free(req);
out_close:
- close(listener);
- exit(1);
- }
-
close(listener);
- if (waitpid(worker, &status, 0) != worker) {
- perror("waitpid");
- goto out_kill;
- }
-
if (umount2("/tmp/foo", MNT_DETACH) < 0 && errno != EINVAL) {
perror("umount2");
- goto out_kill;
+ ret = 1;
+ goto close_pair;
}
if (remove("/tmp/foo") < 0 && errno != ENOENT) {
@@ -371,19 +389,12 @@ int main(void)
exit(1);
}
- if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+ if (!WIFEXITED(worker_status) || WEXITSTATUS(worker_status)) {
fprintf(stderr, "worker exited nonzero\n");
- goto out_kill;
+ ret = 1;
+ goto close_pair;
}
- ret = 0;
-
-out_kill:
- if (tracer > 0)
- kill(tracer, SIGKILL);
- if (worker > 0)
- kill(worker, SIGKILL);
-
close_pair:
close(sk_pair[0]);
close(sk_pair[1]);
--
2.29.1.341.ge80a0c044ae-goog
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
next prev parent reply other threads:[~2020-11-02 20:37 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-02 20:37 [PATCH 1/3] seccomp: Return from SECCOMP_IOCTL_NOTIF_RECV when children are gone Jann Horn via Containers
2020-11-02 20:37 ` Jann Horn via Containers [this message]
2020-11-02 20:37 ` [PATCH 3/3] selftests/seccomp: Test NOTIF_RECV empty/dead errors Jann Horn via Containers
2020-11-03 9:44 ` [PATCH 1/3] seccomp: Return from SECCOMP_IOCTL_NOTIF_RECV when children are gone Christian Brauner
2020-11-04 11:18 ` Sargun Dhillon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201102203706.827510-2-jannh@google.com \
--to=containers@lists.linux-foundation.org \
--cc=christian.brauner@canonical.com \
--cc=giuseppe@scrivano.org \
--cc=jannh@google.com \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=mtk.manpages@gmail.com \
--cc=paul@paul-moore.com \
--cc=wad@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox