1 /*
2 * Copyright (C) 2013-2019 Nikos Mavrogiannopoulos
3 *
4 * This file is part of ocserv.
5 *
6 * ocserv is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * ocserv is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <config.h>
21 #include <worker.h>
22
23 #ifdef HAVE_LIBSECCOMP
24
25 #ifndef _GNU_SOURCE
26 # define _GNU_SOURCE
27 #endif
28 #include <unistd.h>
29 #include <sys/syscall.h>
30 #include <seccomp.h>
31 #include <sys/ioctl.h>
32 #include <signal.h>
33 #include <errno.h>
34
35 /* libseccomp 2.4.2 broke accidentally the API. Work around it. */
36 #ifndef __SNR_ppoll
37 # ifdef __NR_ppoll
38 # define __SNR_ppoll __NR_ppoll
39 # else
40 # define __SNR_ppoll __PNR_ppoll
41 # endif
42 #endif
43
44 /* On certain cases gnulib defines gettimeofday as macro; avoid that */
45 #undef gettimeofday
46
47 #ifdef USE_SECCOMP_TRAP
48 # define _SECCOMP_ERR SCMP_ACT_TRAP
49 #include <execinfo.h>
50 #include <signal.h>
sigsys_action(int sig,siginfo_t * info,void * ucontext)51 void sigsys_action(int sig, siginfo_t * info, void* ucontext)
52 {
53 char * call_addr = *backtrace_symbols(&info->si_call_addr, 1);
54 fprintf(stderr, "Function %s called disabled syscall %d\n", call_addr, info->si_syscall);
55 exit(1);
56 }
57
set_sigsys_handler(struct worker_st * ws)58 int set_sigsys_handler(struct worker_st *ws)
59 {
60 struct sigaction sa = {};
61
62 sa.sa_sigaction = sigsys_action;
63 sa.sa_flags = SA_SIGINFO;
64
65 return sigaction(SIGSYS, &sa, NULL);
66 }
67 #else
68 # define _SECCOMP_ERR SCMP_ACT_ERRNO(ENOSYS)
set_sigsys_handler(struct worker_st * ws)69 int set_sigsys_handler(struct worker_st *ws)
70 {
71 return 0;
72 }
73 #endif
74
75
76
disable_system_calls(struct worker_st * ws)77 int disable_system_calls(struct worker_st *ws)
78 {
79 int ret;
80 scmp_filter_ctx ctx;
81 vhost_cfg_st *vhost = NULL;
82
83 if (set_sigsys_handler(ws))
84 {
85 oclog(ws, LOG_ERR, "set_sigsys_handler");
86 return -1;
87 }
88
89 ctx = seccomp_init(_SECCOMP_ERR);
90 if (ctx == NULL) {
91 oclog(ws, LOG_DEBUG, "could not initialize seccomp");
92 return -1;
93 }
94
95 #define ADD_SYSCALL(name, ...) \
96 ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(name), __VA_ARGS__); \
97 /* libseccomp returns EDOM for pseudo-syscalls due to a bug */ \
98 if (ret < 0 && ret != -EDOM) { \
99 oclog(ws, LOG_DEBUG, "could not add " #name " to seccomp filter: %s", strerror(-ret)); \
100 ret = -1; \
101 goto fail; \
102 }
103
104 /* These seem to be called by libc or some other dependent library;
105 * they are not necessary for functioning, but we must allow them in order
106 * to run under trap mode. */
107 ADD_SYSCALL(getcwd, 0);
108 ADD_SYSCALL(lstat, 0);
109
110 /* Socket wrapper tests use additional syscalls; only enable
111 * them when socket wrapper is active */
112 if (getenv("SOCKET_WRAPPER_DIR") != NULL) {
113 ADD_SYSCALL(stat64, 0);
114 ADD_SYSCALL(readlink, 0);
115 ADD_SYSCALL(newfstatat, 0);
116 }
117
118 /* we use quite some system calls here, and in the end
119 * we don't even know whether a newer libc will change the
120 * underlying calls to something else. seccomp seems to be useful
121 * in very restricted designs.
122 */
123 ADD_SYSCALL(time, 0);
124 ADD_SYSCALL(gettimeofday, 0);
125 #if defined(HAVE_CLOCK_GETTIME)
126 ADD_SYSCALL(clock_gettime, 0);
127 #endif
128 ADD_SYSCALL(clock_nanosleep, 0);
129 ADD_SYSCALL(nanosleep, 0);
130 ADD_SYSCALL(getrusage, 0);
131 ADD_SYSCALL(alarm, 0);
132 ADD_SYSCALL(getpid, 0);
133
134 /* memory allocation - both are used by different platforms */
135 ADD_SYSCALL(brk, 0);
136 ADD_SYSCALL(mmap, 0);
137
138 #ifdef __NR_getrandom
139 ADD_SYSCALL(getrandom, 0); /* used by gnutls 3.5.x */
140 #endif
141 ADD_SYSCALL(recvmsg, 0);
142 ADD_SYSCALL(sendmsg, 0);
143
144 ADD_SYSCALL(read, 0);
145
146 ADD_SYSCALL(write, 0);
147 ADD_SYSCALL(writev, 0);
148
149 ADD_SYSCALL(send, 0);
150 ADD_SYSCALL(recv, 0);
151
152 /* it seems we need to add sendto and recvfrom
153 * since send() and recv() aren't called by libc.
154 */
155 ADD_SYSCALL(sendto, 0);
156 ADD_SYSCALL(recvfrom, 0);
157
158 /* allow returning from the signal handler */
159 ADD_SYSCALL(sigreturn, 0);
160 ADD_SYSCALL(rt_sigreturn, 0);
161
162 /* we use it in select */
163 ADD_SYSCALL(sigprocmask, 0);
164 ADD_SYSCALL(rt_sigprocmask, 0);
165
166 ADD_SYSCALL(poll, 0);
167 ADD_SYSCALL(ppoll, 0);
168
169 /* allow setting non-blocking sockets */
170 ADD_SYSCALL(fcntl, 0);
171 ADD_SYSCALL(close, 0);
172 ADD_SYSCALL(exit, 0);
173 ADD_SYSCALL(exit_group, 0);
174 ADD_SYSCALL(socket, 0);
175 ADD_SYSCALL(connect, 0);
176
177 ADD_SYSCALL(openat, 0);
178 ADD_SYSCALL(fstat, 0);
179 ADD_SYSCALL(lseek, 0);
180
181 ADD_SYSCALL(getsockopt, 0);
182 ADD_SYSCALL(setsockopt, 0);
183
184
185 #ifdef ANYCONNECT_CLIENT_COMPAT
186 /* we need to open files when we have an xml_config_file setup on any vhost */
187 list_for_each(ws->vconfig, vhost, list) {
188 if (vhost->perm_config.config->xml_config_file) {
189 ADD_SYSCALL(stat, 0);
190 ADD_SYSCALL(stat64, 0);
191 ADD_SYSCALL(newfstatat, 0);
192 ADD_SYSCALL(open, 0);
193 ADD_SYSCALL(openat, 0);
194 break;
195 }
196 }
197 #endif
198
199 /* this we need to get the MTU from
200 * the TUN device */
201 ADD_SYSCALL(ioctl, 1, SCMP_A1(SCMP_CMP_EQ, (int)SIOCGIFMTU));
202
203 // Add calls to support libev
204 ADD_SYSCALL(epoll_wait, 0);
205 ADD_SYSCALL(epoll_create1, 0);
206 ADD_SYSCALL(epoll_ctl, 0);
207 ADD_SYSCALL(rt_sigaction, 0);
208 ADD_SYSCALL(eventfd2, 0);
209
210 ret = seccomp_load(ctx);
211 if (ret < 0) {
212 oclog(ws, LOG_DEBUG, "could not load seccomp filter");
213 ret = -1;
214 goto fail;
215 }
216
217 ret = 0;
218
219 fail:
220 seccomp_release(ctx);
221 return ret;
222 }
223 #else
disable_system_calls(struct worker_st * ws)224 int disable_system_calls(struct worker_st *ws)
225 {
226 return 0;
227 }
228 #endif
229