1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
/*
* Copyright 2015-2024 Gentoo Foundation
* Distributed under the terms of the GNU General Public License v2
*
* Copyright 2015-2024 Mike Frysinger - <vapier@gentoo.org>
*/
#include "paxinc.h"
#include "seccomp-bpf.h"
#ifdef __linux__
/* Older versions of Linux might not have these. */
#ifndef CLONE_NEWIPC
#define CLONE_NEWIPC 0
#endif
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0
#endif
#ifndef CLONE_NEWNS
#define CLONE_NEWNS 0
#endif
#ifndef CLONE_NEWPID
#define CLONE_NEWPID 0
#endif
#ifndef CLONE_NEWUTS
#define CLONE_NEWUTS 0
#endif
#ifndef PR_SET_SECCOMP
#define PR_SET_SECCOMP 22
#endif
#ifndef SECCOMP_MODE_FILTER
#define SECCOMP_MODE_FILTER 2
#endif
#ifdef __SANITIZE_ADDRESS__
/* ASAN does some weird stuff. */
# define ALLOW_PIDNS 0
# undef WANT_SECCOMP
#else
# define ALLOW_PIDNS 1
#endif
#ifndef SECCOMP_BPF_AVAILABLE
# undef WANT_SECCOMP
#endif
#if PAX_UTILS_LIBFUZZ
# undef WANT_SECCOMP
#endif
static int ns_unshare(int flags)
{
int flag, ret = 0;
/* Try to oneshot it. Maybe we'll get lucky! */
if (unshare(flags) == 0)
return flags;
/* No access at all, so don't waste time below. */
else if (errno == EPERM)
return ret;
/*
* We have to run these one permission at a time because if any are
* not supported (too old a kernel, or it's disabled), then all of
* them will be rejected and we won't know which one is a problem.
*/
/* First the ones that work against the current process. */
flag = 1;
while (flags) {
if (flags & flag) {
if (unshare(flag) == 0)
ret |= flag;
flags &= ~flag;
}
flag <<= 1;
}
return ret;
}
void security_init_pid(void)
{
int flags;
if (!ALLOW_PIDNS || CLONE_NEWPID == 0)
return;
flags = ns_unshare(CLONE_NEWPID);
if (USE_SLOW_SECURITY) {
if (flags & CLONE_NEWPID)
if (vfork() == 0)
_exit(0);
}
}
void security_init(bool allow_forking)
{
(void) allow_forking;
int flags;
if (!ALLOW_PIDNS)
allow_forking = true;
/* Drop all possible caps for us and our children. */
#ifdef PR_SET_NO_NEW_PRIVS /* New to linux-3.5 */
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
#endif
#ifdef PR_SET_SECUREBITS /* New to linux-2.6.26 */
# ifdef SECBIT_KEEP_CAPS_LOCKED /* New to linux-2.6.33 (all SECBIT_xxx) */
prctl(PR_SET_SECUREBITS,
SECBIT_KEEP_CAPS_LOCKED |
SECBIT_NO_SETUID_FIXUP |
SECBIT_NO_SETUID_FIXUP_LOCKED |
SECBIT_NOROOT |
SECBIT_NOROOT_LOCKED, 0, 0, 0);
# endif
#endif
/* None of the pax tools need access to these features. */
flags = CLONE_NEWIPC | CLONE_NEWUTS;
/* Would be nice to leverage mount/net ns, but they're just way too slow. */
if (USE_SLOW_SECURITY)
flags |= CLONE_NEWNET | CLONE_NEWNS;
if (!allow_forking)
flags |= CLONE_NEWPID;
flags = ns_unshare(flags);
if (USE_SLOW_SECURITY) {
/* We spawn one child and kill it so the kernel will fail in the future. */
if (flags & CLONE_NEWPID)
if (vfork() == 0)
_exit(0);
}
#ifdef WANT_SECCOMP
{
int ret;
if (allow_forking)
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &seccomp_bpf_program_fork);
else
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &seccomp_bpf_program_base);
if (ret)
warn("enabling seccomp failed");
}
#endif
}
#endif
|