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