]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/priv-seccomp.c
v0.9.5: seccomp - add socket ops
[thirdparty/lldpd.git] / src / daemon / priv-seccomp.c
CommitLineData
00e40dba
VB
1/* -*- mode: c; c-file-style: "openbsd" -*- */
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "lldpd.h"
19#include <stdlib.h>
20#include <unistd.h>
21#include <errno.h>
22#include <signal.h>
23
24#include "syscall-names.h"
25#include <seccomp.h>
26
27#ifndef SYS_SECCOMP
28# define SYS_SECCOMP 1
29#endif
30
31#if defined(__i386__)
32# define REG_SYSCALL REG_EAX
33# define ARCH_NR AUDIT_ARCH_I386
34#elif defined(__x86_64__)
35# define REG_SYSCALL REG_RAX
36# define ARCH_NR AUDIT_ARCH_X86_64
37#else
38# error "Platform does not support seccomp filter yet"
39# define REG_SYSCALL 0
40# define ARCH_NR 0
41#endif
42
71a7dbb3
VB
43/* If there is no privilege separation, seccomp is currently useless */
44#ifdef ENABLE_PRIVSEP
00e40dba
VB
45static int monitored = -1;
46static int trapped = 0;
47/**
48 * SIGSYS signal handler
49 * @param nr the signal number
50 * @param info siginfo_t pointer
51 * @param void_context handler context
52 *
53 * Simple signal handler for SIGSYS displaying the error, killing the child and
54 * exiting.
55 *
56 */
57static void
58priv_seccomp_trap_handler(int signal, siginfo_t *info, void *vctx)
59{
60 ucontext_t *ctx = (ucontext_t *)(vctx);
61 unsigned int syscall;
62
63 if (trapped)
64 _exit(161); /* Avoid loops */
65
66 /* Get details */
67 if (info->si_code != SYS_SECCOMP)
68 return;
69 if (!ctx)
70 _exit(161);
71 syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
72 trapped = 1;
73
74 /* Log them. Technically, `log_warnx()` is not signal safe, but we are
75 * unlikely to reenter here. */
76 log_warnx("seccomp", "invalid syscall attempted: %s(%d)",
77 (syscall < sizeof(syscall_names))?syscall_names[syscall]:"unknown",
78 syscall);
79
80 /* Kill children and exit */
81 kill(monitored, SIGTERM);
a87db231 82 fatalx("seccomp", "invalid syscall not allowed: stop here");
00e40dba
VB
83 _exit(161);
84}
85
86/**
87 * Install a TRAP action signal handler
88 *
89 * This function installs the TRAP action signal handler and is based on
90 * examples from Will Drewry and Kees Cook. Returns zero on success, negative
91 * values on failure.
92 *
93 */
94static int
95priv_seccomp_trap_install()
96{
97 struct sigaction signal_handler = {};
98 sigset_t signal_mask;
99
100 sigemptyset(&signal_mask);
101 sigaddset(&signal_mask, SIGSYS);
102
103 signal_handler.sa_sigaction = &priv_seccomp_trap_handler;
104 signal_handler.sa_flags = SA_SIGINFO;
105 if (sigaction(SIGSYS, &signal_handler, NULL) < 0)
106 return -errno;
107 if (sigprocmask(SIG_UNBLOCK, &signal_mask, NULL))
108 return -errno;
109
110 return 0;
111}
112
113/**
114 * Initialize seccomp.
115 *
116 * @param remote file descriptor to talk with the unprivileged process
117 * @param monitored monitored child
118 * @return negative on failures or 0 if everything was setup
119 */
120int
121priv_seccomp_init(int remote, int child)
122{
123 int rc = -1;
3f4c0a5f 124 scmp_filter_ctx ctx = NULL;
00e40dba
VB
125
126 log_debug("seccomp", "initialize libseccomp filter");
127 monitored = child;
128 if (priv_seccomp_trap_install() < 0) {
129 log_warn("seccomp", "unable to install SIGSYS handler");
130 goto failure_scmp;
131 }
132
133 if ((ctx = seccomp_init(SCMP_ACT_TRAP)) == NULL) {
134 log_warnx("seccomp", "unable to initialize libseccomp subsystem");
135 goto failure_scmp;
136 }
137
138 if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
139 SCMP_SYS(read), 1, SCMP_CMP(0, SCMP_CMP_EQ, remote))) < 0 ||
140 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
141 SCMP_SYS(write), 1, SCMP_CMP(0, SCMP_CMP_EQ, remote))) < 0) {
142 errno = -rc;
143 log_warn("seccomp", "unable to allow read/write on remote socket");
144 goto failure_scmp;
145 }
146
147 /* We are far more generic from here. */
148 if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0)) < 0 ||
149 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0)) < 0 || /* write needed for */
150 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0)) < 0 ||
2f8f95aa 151 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0)) < 0 ||
cd752e02 152 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0)) < 0 ||
e15216c7 153 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0)) < 0 ||
00e40dba
VB
154 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(kill), 0)) < 0 ||
155 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0)) < 0 ||
156 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(bind), 0)) < 0 ||
157 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 0)) < 0 ||
e15216c7 158 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockname), 0)) < 0 ||
00e40dba
VB
159 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(uname), 0)) < 0 ||
160 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(unlink), 0)) < 0 ||
161 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 0)) < 0 ||
162 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0)) < 0 ||
7aa98f11 163 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmmsg), 0)) < 0 ||
00e40dba
VB
164 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(wait4), 0)) < 0 ||
165 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat), 0)) < 0 ||
37a293d3 166 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0)) < 0 ||
00e40dba
VB
167 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0)) < 0 ||
168 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0)) < 0 ||
285b33af
PM
169 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0)) < 0 ||
170 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll), 0)) < 0 ||
171 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvmsg), 0)) < 0 ||
7aa98f11 172 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0)) < 0 ||
285b33af 173 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(readv), 0)) < 0 ||
cc74ca8d 174 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0)) < 0 ||
3ab8ebbc 175 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmmsg), 0)) < 0 ||
00e40dba
VB
176 /* The following are for resolving addresses */
177 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0)) < 0 ||
178 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0)) < 0 ||
179 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0)) < 0 ||
180 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0)) < 0 ||
181 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0)) < 0 ||
182
183 (rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0)) < 0) {
184 errno = -rc;
185 log_warn("seccomp", "unable to build seccomp rules");
186 goto failure_scmp;
187 }
188
189 if ((rc = seccomp_load(ctx)) < 0) {
190 errno = -rc;
191 log_warn("seccomp", "unable to load libseccomp filter");
192 goto failure_scmp;
193 }
194
195failure_scmp:
196 seccomp_release(ctx);
197 return rc;
198}
71a7dbb3 199#endif