]>
Commit | Line | Data |
---|---|---|
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 |
45 | static int monitored = -1; |
46 | static 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 | */ | |
57 | static void | |
58 | priv_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 | */ | |
94 | static int | |
95 | priv_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 | */ | |
120 | int | |
121 | priv_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 | ||
195 | failure_scmp: | |
196 | seccomp_release(ctx); | |
197 | return rc; | |
198 | } | |
71a7dbb3 | 199 | #endif |