xref: /freebsd/contrib/file/src/seccomp.c (revision 48c779cdecb5f803e5fe5d761987e976ca9609db)
158a0f0d0SEitan Adler /*
258a0f0d0SEitan Adler  * Redistribution and use in source and binary forms, with or without
358a0f0d0SEitan Adler  * modification, are permitted provided that the following conditions
458a0f0d0SEitan Adler  * are met:
558a0f0d0SEitan Adler  * 1. Redistributions of source code must retain the above copyright
658a0f0d0SEitan Adler  *    notice immediately at the beginning of the file, without modification,
758a0f0d0SEitan Adler  *    this list of conditions, and the following disclaimer.
858a0f0d0SEitan Adler  * 2. Redistributions in binary form must reproduce the above copyright
958a0f0d0SEitan Adler  *    notice, this list of conditions and the following disclaimer in the
1058a0f0d0SEitan Adler  *    documentation and/or other materials provided with the distribution.
1158a0f0d0SEitan Adler  *
1258a0f0d0SEitan Adler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1358a0f0d0SEitan Adler  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1458a0f0d0SEitan Adler  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1558a0f0d0SEitan Adler  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
1658a0f0d0SEitan Adler  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1758a0f0d0SEitan Adler  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1858a0f0d0SEitan Adler  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1958a0f0d0SEitan Adler  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2058a0f0d0SEitan Adler  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2158a0f0d0SEitan Adler  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2258a0f0d0SEitan Adler  * SUCH DAMAGE.
2358a0f0d0SEitan Adler  */
2458a0f0d0SEitan Adler /*
2558a0f0d0SEitan Adler  * libseccomp hooks.
2658a0f0d0SEitan Adler  */
2758a0f0d0SEitan Adler #include "file.h"
2858a0f0d0SEitan Adler 
2958a0f0d0SEitan Adler #ifndef	lint
30*48c779cdSXin LI FILE_RCSID("@(#)$File: seccomp.c,v 1.8 2019/02/24 18:12:04 christos Exp $")
3158a0f0d0SEitan Adler #endif	/* lint */
3258a0f0d0SEitan Adler 
3358a0f0d0SEitan Adler #if HAVE_LIBSECCOMP
3458a0f0d0SEitan Adler #include <seccomp.h> /* libseccomp */
3558a0f0d0SEitan Adler #include <sys/prctl.h> /* prctl */
3658a0f0d0SEitan Adler #include <sys/socket.h>
3758a0f0d0SEitan Adler #include <fcntl.h>
3858a0f0d0SEitan Adler #include <stdlib.h>
3958a0f0d0SEitan Adler #include <errno.h>
4058a0f0d0SEitan Adler 
4158a0f0d0SEitan Adler #define DENY_RULE(call) \
4258a0f0d0SEitan Adler     do \
4358a0f0d0SEitan Adler 	if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) == -1) \
4458a0f0d0SEitan Adler 	    goto out; \
4558a0f0d0SEitan Adler     while (/*CONSTCOND*/0)
4658a0f0d0SEitan Adler #define ALLOW_RULE(call) \
4758a0f0d0SEitan Adler     do \
4858a0f0d0SEitan Adler 	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) == -1) \
4958a0f0d0SEitan Adler 	    goto out; \
5058a0f0d0SEitan Adler     while (/*CONSTCOND*/0)
5158a0f0d0SEitan Adler 
5258a0f0d0SEitan Adler static scmp_filter_ctx ctx;
5358a0f0d0SEitan Adler 
5458a0f0d0SEitan Adler 
5558a0f0d0SEitan Adler int
5658a0f0d0SEitan Adler enable_sandbox_basic(void)
5758a0f0d0SEitan Adler {
5858a0f0d0SEitan Adler 
5958a0f0d0SEitan Adler 	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
6058a0f0d0SEitan Adler 		return -1;
6158a0f0d0SEitan Adler 
6258a0f0d0SEitan Adler 	if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
6358a0f0d0SEitan Adler 		return -1;
6458a0f0d0SEitan Adler 
6558a0f0d0SEitan Adler 	// initialize the filter
6658a0f0d0SEitan Adler 	ctx = seccomp_init(SCMP_ACT_ALLOW);
6758a0f0d0SEitan Adler 	if (ctx == NULL)
6858a0f0d0SEitan Adler 	    return 1;
6958a0f0d0SEitan Adler 
7058a0f0d0SEitan Adler 	DENY_RULE(_sysctl);
7158a0f0d0SEitan Adler 	DENY_RULE(acct);
7258a0f0d0SEitan Adler 	DENY_RULE(add_key);
7358a0f0d0SEitan Adler 	DENY_RULE(adjtimex);
7458a0f0d0SEitan Adler 	DENY_RULE(chroot);
7558a0f0d0SEitan Adler 	DENY_RULE(clock_adjtime);
7658a0f0d0SEitan Adler 	DENY_RULE(create_module);
7758a0f0d0SEitan Adler 	DENY_RULE(delete_module);
7858a0f0d0SEitan Adler 	DENY_RULE(fanotify_init);
7958a0f0d0SEitan Adler 	DENY_RULE(finit_module);
8058a0f0d0SEitan Adler 	DENY_RULE(get_kernel_syms);
8158a0f0d0SEitan Adler 	DENY_RULE(get_mempolicy);
8258a0f0d0SEitan Adler 	DENY_RULE(init_module);
8358a0f0d0SEitan Adler 	DENY_RULE(io_cancel);
8458a0f0d0SEitan Adler 	DENY_RULE(io_destroy);
8558a0f0d0SEitan Adler 	DENY_RULE(io_getevents);
8658a0f0d0SEitan Adler 	DENY_RULE(io_setup);
8758a0f0d0SEitan Adler 	DENY_RULE(io_submit);
8858a0f0d0SEitan Adler 	DENY_RULE(ioperm);
8958a0f0d0SEitan Adler 	DENY_RULE(iopl);
9058a0f0d0SEitan Adler 	DENY_RULE(ioprio_set);
9158a0f0d0SEitan Adler 	DENY_RULE(kcmp);
9258a0f0d0SEitan Adler #ifdef __NR_kexec_file_load
9358a0f0d0SEitan Adler 	DENY_RULE(kexec_file_load);
9458a0f0d0SEitan Adler #endif
9558a0f0d0SEitan Adler 	DENY_RULE(kexec_load);
9658a0f0d0SEitan Adler 	DENY_RULE(keyctl);
9758a0f0d0SEitan Adler 	DENY_RULE(lookup_dcookie);
9858a0f0d0SEitan Adler 	DENY_RULE(mbind);
9958a0f0d0SEitan Adler 	DENY_RULE(nfsservctl);
10058a0f0d0SEitan Adler 	DENY_RULE(migrate_pages);
10158a0f0d0SEitan Adler 	DENY_RULE(modify_ldt);
10258a0f0d0SEitan Adler 	DENY_RULE(mount);
10358a0f0d0SEitan Adler 	DENY_RULE(move_pages);
10458a0f0d0SEitan Adler 	DENY_RULE(name_to_handle_at);
10558a0f0d0SEitan Adler 	DENY_RULE(open_by_handle_at);
10658a0f0d0SEitan Adler 	DENY_RULE(perf_event_open);
10758a0f0d0SEitan Adler 	DENY_RULE(pivot_root);
10858a0f0d0SEitan Adler 	DENY_RULE(process_vm_readv);
10958a0f0d0SEitan Adler 	DENY_RULE(process_vm_writev);
11058a0f0d0SEitan Adler 	DENY_RULE(ptrace);
11158a0f0d0SEitan Adler 	DENY_RULE(reboot);
11258a0f0d0SEitan Adler 	DENY_RULE(remap_file_pages);
11358a0f0d0SEitan Adler 	DENY_RULE(request_key);
11458a0f0d0SEitan Adler 	DENY_RULE(set_mempolicy);
11558a0f0d0SEitan Adler 	DENY_RULE(swapoff);
11658a0f0d0SEitan Adler 	DENY_RULE(swapon);
11758a0f0d0SEitan Adler 	DENY_RULE(sysfs);
11858a0f0d0SEitan Adler 	DENY_RULE(syslog);
11958a0f0d0SEitan Adler 	DENY_RULE(tuxcall);
12058a0f0d0SEitan Adler 	DENY_RULE(umount2);
12158a0f0d0SEitan Adler 	DENY_RULE(uselib);
12258a0f0d0SEitan Adler 	DENY_RULE(vmsplice);
12358a0f0d0SEitan Adler 
12458a0f0d0SEitan Adler 	// blocking dangerous syscalls that file should not need
12558a0f0d0SEitan Adler 	DENY_RULE (execve);
12658a0f0d0SEitan Adler 	DENY_RULE (socket);
12758a0f0d0SEitan Adler 	// ...
12858a0f0d0SEitan Adler 
12958a0f0d0SEitan Adler 
13058a0f0d0SEitan Adler 	// applying filter...
13158a0f0d0SEitan Adler 	if (seccomp_load (ctx) == -1)
13258a0f0d0SEitan Adler 		goto out;
13358a0f0d0SEitan Adler 	// free ctx after the filter has been loaded into the kernel
13458a0f0d0SEitan Adler 	seccomp_release(ctx);
13558a0f0d0SEitan Adler 	return 0;
13658a0f0d0SEitan Adler 
13758a0f0d0SEitan Adler out:
13858a0f0d0SEitan Adler 	seccomp_release(ctx);
13958a0f0d0SEitan Adler 	return -1;
14058a0f0d0SEitan Adler }
14158a0f0d0SEitan Adler 
14258a0f0d0SEitan Adler 
14358a0f0d0SEitan Adler int
14458a0f0d0SEitan Adler enable_sandbox_full(void)
14558a0f0d0SEitan Adler {
14658a0f0d0SEitan Adler 
14758a0f0d0SEitan Adler 	// prevent child processes from getting more priv e.g. via setuid,
14858a0f0d0SEitan Adler 	// capabilities, ...
14958a0f0d0SEitan Adler 	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
15058a0f0d0SEitan Adler 		return -1;
15158a0f0d0SEitan Adler 
15258a0f0d0SEitan Adler 	if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
15358a0f0d0SEitan Adler 		return -1;
15458a0f0d0SEitan Adler 
15558a0f0d0SEitan Adler 	// initialize the filter
15658a0f0d0SEitan Adler 	ctx = seccomp_init(SCMP_ACT_KILL);
15758a0f0d0SEitan Adler 	if (ctx == NULL)
15858a0f0d0SEitan Adler 		return -1;
15958a0f0d0SEitan Adler 
16058a0f0d0SEitan Adler 	ALLOW_RULE(access);
16158a0f0d0SEitan Adler 	ALLOW_RULE(brk);
16258a0f0d0SEitan Adler 	ALLOW_RULE(close);
16358a0f0d0SEitan Adler 	ALLOW_RULE(dup2);
16458a0f0d0SEitan Adler 	ALLOW_RULE(exit);
16558a0f0d0SEitan Adler 	ALLOW_RULE(exit_group);
16658a0f0d0SEitan Adler 	ALLOW_RULE(fcntl);
1672dc4dbb9SEitan Adler  	ALLOW_RULE(fcntl64);
16858a0f0d0SEitan Adler 	ALLOW_RULE(fstat);
1692dc4dbb9SEitan Adler  	ALLOW_RULE(fstat64);
17058a0f0d0SEitan Adler 	ALLOW_RULE(getdents);
1712dc4dbb9SEitan Adler #ifdef __NR_getdents64
1722dc4dbb9SEitan Adler 	ALLOW_RULE(getdents64);
1732dc4dbb9SEitan Adler #endif
17458a0f0d0SEitan Adler 	ALLOW_RULE(ioctl);
17558a0f0d0SEitan Adler 	ALLOW_RULE(lseek);
1762dc4dbb9SEitan Adler  	ALLOW_RULE(_llseek);
17758a0f0d0SEitan Adler 	ALLOW_RULE(lstat);
1782dc4dbb9SEitan Adler  	ALLOW_RULE(lstat64);
179*48c779cdSXin LI 	ALLOW_RULE(madvise);
18058a0f0d0SEitan Adler 	ALLOW_RULE(mmap);
1812dc4dbb9SEitan Adler  	ALLOW_RULE(mmap2);
18258a0f0d0SEitan Adler 	ALLOW_RULE(mprotect);
18358a0f0d0SEitan Adler 	ALLOW_RULE(mremap);
18458a0f0d0SEitan Adler 	ALLOW_RULE(munmap);
1852dc4dbb9SEitan Adler #ifdef __NR_newfstatat
1862dc4dbb9SEitan Adler 	ALLOW_RULE(newfstatat);
1872dc4dbb9SEitan Adler #endif
18858a0f0d0SEitan Adler 	ALLOW_RULE(open);
18958a0f0d0SEitan Adler 	ALLOW_RULE(openat);
19058a0f0d0SEitan Adler 	ALLOW_RULE(pread64);
19158a0f0d0SEitan Adler 	ALLOW_RULE(read);
19258a0f0d0SEitan Adler 	ALLOW_RULE(readlink);
19358a0f0d0SEitan Adler 	ALLOW_RULE(rt_sigaction);
19458a0f0d0SEitan Adler 	ALLOW_RULE(rt_sigprocmask);
19558a0f0d0SEitan Adler 	ALLOW_RULE(rt_sigreturn);
19658a0f0d0SEitan Adler 	ALLOW_RULE(select);
19758a0f0d0SEitan Adler 	ALLOW_RULE(stat);
1982dc4dbb9SEitan Adler 	ALLOW_RULE(stat64);
19958a0f0d0SEitan Adler 	ALLOW_RULE(sysinfo);
20058a0f0d0SEitan Adler 	ALLOW_RULE(unlink);
20158a0f0d0SEitan Adler 	ALLOW_RULE(write);
20258a0f0d0SEitan Adler 
20358a0f0d0SEitan Adler 
20458a0f0d0SEitan Adler #if 0
20558a0f0d0SEitan Adler 	// needed by valgrind
20658a0f0d0SEitan Adler 	ALLOW_RULE(gettid);
20758a0f0d0SEitan Adler 	ALLOW_RULE(getpid);
20858a0f0d0SEitan Adler 	ALLOW_RULE(rt_sigtimedwait);
20958a0f0d0SEitan Adler #endif
21058a0f0d0SEitan Adler 
21158a0f0d0SEitan Adler #if 0
21258a0f0d0SEitan Adler 	 /* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */
21358a0f0d0SEitan Adler 	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
21458a0f0d0SEitan Adler 	     SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) == -1)
21558a0f0d0SEitan Adler 	 	goto out;
21658a0f0d0SEitan Adler 
21758a0f0d0SEitan Adler 	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
21858a0f0d0SEitan Adler 	     SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) == -1)
21958a0f0d0SEitan Adler 	 	goto out;
22058a0f0d0SEitan Adler 
22158a0f0d0SEitan Adler 
22258a0f0d0SEitan Adler 	 /* special restrictions for open, prevent opening files for writing */
22358a0f0d0SEitan Adler 	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1,
22458a0f0d0SEitan Adler 	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) == -1)
22558a0f0d0SEitan Adler 	 	goto out;
22658a0f0d0SEitan Adler 
22758a0f0d0SEitan Adler 	 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
22858a0f0d0SEitan Adler 	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) == -1)
22958a0f0d0SEitan Adler 	 	goto out;
23058a0f0d0SEitan Adler 
23158a0f0d0SEitan Adler 	 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
23258a0f0d0SEitan Adler 	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) == -1)
23358a0f0d0SEitan Adler 	 	goto out;
23458a0f0d0SEitan Adler 
23558a0f0d0SEitan Adler 
23658a0f0d0SEitan Adler 	 /* allow stderr */
23758a0f0d0SEitan Adler 	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
23858a0f0d0SEitan Adler 	     SCMP_CMP(0, SCMP_CMP_EQ, 2)) == -1)
23958a0f0d0SEitan Adler 		 goto out;
24058a0f0d0SEitan Adler #endif
24158a0f0d0SEitan Adler 
24258a0f0d0SEitan Adler 	// applying filter...
24358a0f0d0SEitan Adler 	if (seccomp_load(ctx) == -1)
24458a0f0d0SEitan Adler 		goto out;
24558a0f0d0SEitan Adler 	// free ctx after the filter has been loaded into the kernel
24658a0f0d0SEitan Adler 	seccomp_release(ctx);
24758a0f0d0SEitan Adler 	return 0;
24858a0f0d0SEitan Adler 
24958a0f0d0SEitan Adler out:
25058a0f0d0SEitan Adler 	// something went wrong
25158a0f0d0SEitan Adler 	seccomp_release(ctx);
25258a0f0d0SEitan Adler 	return -1;
25358a0f0d0SEitan Adler }
25458a0f0d0SEitan Adler #endif
255