mirror of
https://github.com/cjdelisle/cjdns
synced 2025-10-06 00:32:50 +02:00
Get rid of Seccomp because the whitelist strategy doesn't work with Rust libraries and it is not maintained anymore
This commit is contained in:
@@ -540,7 +540,6 @@ static void ethInterface(Dict* config, struct Context* ctx)
|
||||
|
||||
static void security(struct Allocator* tempAlloc, List* conf, struct Log* log, struct Context* ctx)
|
||||
{
|
||||
int seccomp = 1;
|
||||
int nofiles = 0;
|
||||
int noforks = 1;
|
||||
int chroot = 1;
|
||||
@@ -601,10 +600,6 @@ static void security(struct Allocator* tempAlloc, List* conf, struct Log* log, s
|
||||
if (!*x) { setuser = 0; }
|
||||
continue;
|
||||
}
|
||||
if (elem && (x = Dict_getIntC(elem, "seccomp"))) {
|
||||
if (!*x) { seccomp = 0; }
|
||||
continue;
|
||||
}
|
||||
if (elem && (x = Dict_getIntC(elem, "noforks"))) {
|
||||
if (!*x) { noforks = 0; }
|
||||
continue;
|
||||
@@ -652,11 +647,6 @@ static void security(struct Allocator* tempAlloc, List* conf, struct Log* log, s
|
||||
Dict* d = Dict_new(tempAlloc);
|
||||
rpcCall(String_CONST("Security_nofiles"), d, ctx, tempAlloc);
|
||||
}
|
||||
if (seccomp) {
|
||||
Log_debug(log, "Security_seccomp()");
|
||||
Dict* d = Dict_new(tempAlloc);
|
||||
rpcCall(String_CONST("Security_seccomp"), d, ctx, tempAlloc);
|
||||
}
|
||||
if (setupComplete) {
|
||||
Log_debug(log, "Security_setupComplete()");
|
||||
Dict* d = Dict_new(tempAlloc);
|
||||
|
@@ -385,20 +385,7 @@ static int genconf(struct Allocator* alloc, struct Random* rand, bool eth, bool
|
||||
" // Noforks will prevent cjdns from spawning any new processes or threads,\n"
|
||||
" // this prevents many types of exploits from attacking the wider system.\n"
|
||||
" // Default: enabled\n"
|
||||
" { \"noforks\": 1 },\n"
|
||||
"\n"
|
||||
" // Seccomp is the most advanced sandboxing feature in cjdns, it uses\n"
|
||||
" // SECCOMP_BPF to filter the system calls which cjdns is able to make on a\n"
|
||||
" // linux system, strictly limiting it's access to the outside world\n"
|
||||
" // This will fail quietly on any non-linux system\n");
|
||||
if (Defined(Cjdns_android)) {
|
||||
printf(" // Default: disabled\n"
|
||||
" { \"seccomp\": 0 },\n");
|
||||
}
|
||||
else {
|
||||
printf(" // Default: enabled\n"
|
||||
" { \"seccomp\": 1 },\n");
|
||||
}
|
||||
" { \"noforks\": 1 },\n");
|
||||
printf("\n"
|
||||
" // The client sets up the core using a sequence of RPC calls, the responses\n"
|
||||
" // to these calls are verified but in the event that the client crashes\n"
|
||||
@@ -786,8 +773,7 @@ int cjdroute2_main(int argc, char** argv)
|
||||
break;
|
||||
}
|
||||
// sleep 50ms
|
||||
struct timespec timeout = { 0, 1000000 * 50 };
|
||||
nanosleep(&timeout, NULL);
|
||||
Rffi_sleep_ms_sync(50);
|
||||
}
|
||||
if (!exists) {
|
||||
Except_throw(eh, "Core did not setup pipe file [%s] within 60 seconds",
|
||||
|
1
debian/docs
vendored
1
debian/docs
vendored
@@ -1,7 +1,6 @@
|
||||
README.md
|
||||
doc/configure.md
|
||||
doc/Whitepaper.md
|
||||
doc/Seccomp.md
|
||||
doc/nat-gateway.md
|
||||
doc/non-root-user.md
|
||||
tunnel/README.md
|
||||
|
@@ -1,43 +0,0 @@
|
||||
# Seccomp
|
||||
|
||||
SECCOMP (secure computing) is a way for programs to declare to the Linux kernel
|
||||
that they will never make certain system calls, thus any attempt to make one of
|
||||
these calls is interpreted as a security penetration and the kernel can forcibly
|
||||
kill off the program, preventing harm to the computer.
|
||||
|
||||
## Seccomp failures in cjdns
|
||||
|
||||
If you are reading this because cjdns is halting on you, you are probably getting
|
||||
a log message like the following:
|
||||
|
||||
Attempted banned syscall number [232] see docs/Seccomp.md for more information
|
||||
|
||||
This number (`232` in the example) is specific to your system and you need to
|
||||
run a command to convert it to a syscall name.
|
||||
|
||||
```bash
|
||||
echo '#include <sys/syscall.h>' | cpp -dM | grep '#define __NR_.* 232'
|
||||
```
|
||||
|
||||
Obviously you'll be replacing `232` with the actual syscall number which your system
|
||||
printed. The Result might look something like the following:
|
||||
|
||||
```c
|
||||
#define __NR_epoll_wait 232
|
||||
```
|
||||
|
||||
Which would tell you (for example) that the `epoll_wait` syscall was disallowed on
|
||||
your system. In this case you'd need to go to `util/Seccomp.c` and inside of the
|
||||
`mkfilter()` function where the actual SECCOMP rules are set up, you'll see a set
|
||||
of entries such as the following.
|
||||
|
||||
```c
|
||||
#ifdef __NR_mmap2
|
||||
IFEQ(__NR_mmap2, success),
|
||||
#endif
|
||||
```
|
||||
|
||||
Add a similar entry for the syscall (make sure you put it with the others and not)
|
||||
below the `RET(SECCOMP_RET_TRAP),` line which triggers the failure). When you have
|
||||
finished adding your system call rebuild and re-test cjdns. If it works well then
|
||||
please make a Pull Request :-) If not then open a bug report and explain the problem.
|
@@ -52,7 +52,7 @@ Achievements expire, so if at any given time you don't qualify, you lose those p
|
||||
40. Configure an authorizedPassword without restarting cjdns.
|
||||
41. Find out whether your home router can run cjdns: [OpenWrt table of hardware](http://wiki.openwrt.org/toh/start)
|
||||
42. Try out the [Meshbox firmware](https://github.com/seattlemeshnet/meshbox) on your home router.
|
||||
43. Harden your cjdns OpenWrt router by building OpenWrt with cjdns from source and make sure [seccomp](http://lwn.net/Articles/475043/), [SSP](http://lwn.net/Articles/584225/) and [RELRO](http://tk-blog.blogspot.de/2009/02/relro-not-so-well-known-memory.html) are enabled. Using [musl](http://www.musl-libc.org/) instead of [uClibc](http://www.uclibc.org/) may make you sleep even better. See [buildsdk.sh](https://github.com/SeattleMeshnet/meshbox/blob/master/buildsdk.sh) to see how this can work.
|
||||
43. Harden your cjdns OpenWrt router by building OpenWrt with cjdns from source and make sure [SSP](http://lwn.net/Articles/584225/) and [RELRO](http://tk-blog.blogspot.de/2009/02/relro-not-so-well-known-memory.html) are enabled. Using [musl](http://www.musl-libc.org/) instead of [uClibc](http://www.uclibc.org/) may make you sleep even better. See [buildsdk.sh](https://github.com/SeattleMeshnet/meshbox/blob/master/buildsdk.sh) to see how this can work.
|
||||
44. Monitor your nodes' cjdns preformance and make pretty graphs with munin (hint: [here's a nice munin plugin to help](https://github.com/thefinn93/munin-plugins/blob/master/cjdns/cjdns_bandwidth.py))
|
||||
|
||||
## Penalties
|
||||
|
@@ -71,7 +71,6 @@ You can contribute to its documentaion: https://github.com/hyperboria/docs
|
||||
- Troubleshooting
|
||||
- [Read this first](bugs/policy.md)
|
||||
- [Memory leaks](debugging_memory_leaks.md)
|
||||
- [SecComp](Seccomp.md)
|
||||
- [Analyzing network IO](TrafficAnalisys.md)
|
||||
- Known issues
|
||||
- [Black Hole](bugs/black-hole.md)
|
||||
|
@@ -22,7 +22,7 @@ apt install -y nodejs
|
||||
cd /opt
|
||||
git clone https://github.com/cjdelisle/cjdns.git
|
||||
cd cjdns
|
||||
NO_TEST=1 Seccomp_NO=1 ./do
|
||||
NO_TEST=1 ./do
|
||||
ln -s /opt/cjdns/cjdroute /usr/bin
|
||||
|
||||
# Generate a config file
|
||||
|
@@ -27,7 +27,7 @@ If you see something listed here that has been taken care of, please knock it of
|
||||
- allows obfsproxy deployment
|
||||
+ in datacenters (private networking)
|
||||
+ over iodine
|
||||
* Security mechanisms (seccomp, angel/core, etc.)
|
||||
* Security mechanisms (angel/core, etc.)
|
||||
* WiFi Recommendations
|
||||
* cjdns/contrib/ scripts
|
||||
+ dumpTable
|
||||
|
@@ -28,7 +28,7 @@ var LDFLAGS = process.env['LDFLAGS'];
|
||||
// case clang doesn't reliably support march except on x86/amd64.
|
||||
var NO_MARCH_FLAG = ['arm', 'ppc', 'ppc64', 'arm64'];
|
||||
|
||||
if (process.version.replace('v','').split('.').map(Number)[0] >= 18) {
|
||||
if (process.version.replace('v','').split('.').map(Number)[0] >= 12) {
|
||||
// OK
|
||||
} else if ('OLD_NODE_VERSION_I_EXPECT_ERRORS' in process.env) {
|
||||
console.log('OLD_NODE_VERSION_I_EXPECT_ERRORS is set, ignoring old version');
|
||||
|
@@ -206,6 +206,8 @@ uint64_t Rffi_hrtime(void);
|
||||
*/
|
||||
uint64_t Rffi_now_ms(void);
|
||||
|
||||
void Rffi_sleep_ms_sync(uint64_t ms);
|
||||
|
||||
RTypes_IfWrapper_t Rffi_testwrapper_create(Allocator_t *a);
|
||||
|
||||
RTypes_IfWrapper_t Rffi_android_create(Allocator_t *a);
|
||||
|
@@ -129,10 +129,10 @@ impl <const COUNT: usize> IoContext<COUNT> {
|
||||
assert!((d as usize) >= bottom && (d as usize + std::mem::size_of::<i32>()) <= top);
|
||||
*d = send_fd;
|
||||
let len = libc::CMSG_LEN(std::mem::size_of::<i32>() as _);
|
||||
(*cmsg).cmsg_len = len;
|
||||
(*cmsg).cmsg_len = len as _;
|
||||
(*cmsg).cmsg_type = libc::SCM_RIGHTS;
|
||||
(*cmsg).cmsg_level = libc::SOL_SOCKET;
|
||||
hdr.msg_hdr.msg_controllen = len;
|
||||
hdr.msg_hdr.msg_controllen = len as _;
|
||||
}
|
||||
} else {
|
||||
hdr.msg_hdr.msg_control = std::ptr::null_mut();
|
||||
|
@@ -22,3 +22,8 @@ pub extern "C" fn Rffi_now_ms() -> u64 {
|
||||
|
||||
(Instant::now() - *BASE_INSTANT).as_millis() as u64 + *INSTANT_OFFSET
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Rffi_sleep_ms_sync(ms: u64) {
|
||||
std::thread::sleep(Duration::from_millis(ms));
|
||||
}
|
||||
|
@@ -1,18 +0,0 @@
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
/*
|
||||
* You may redistribute this program and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "util/Seccomp.h"
|
||||
#include "util/Js.h"
|
||||
|
||||
Js({ require("../util/Seccomp.js").detect(js, builder); })
|
@@ -1,22 +0,0 @@
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
/*
|
||||
* You may redistribute this program and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Seccomp_H
|
||||
#define Seccomp_H
|
||||
|
||||
#include "util/Seccomp_impl.h"
|
||||
#include "util/Linker.h"
|
||||
Linker_require("util/Seccomp.c")
|
||||
|
||||
#endif
|
101
util/Seccomp.js
101
util/Seccomp.js
@@ -1,101 +0,0 @@
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
/*
|
||||
* You may redistribute this program and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
'use strict';
|
||||
var Os = require('os');
|
||||
|
||||
var TEST_PROGRAM = [
|
||||
"#include <sys/resource.h>",
|
||||
"#include <sys/prctl.h>",
|
||||
"#include <linux/filter.h>",
|
||||
"#include <linux/seccomp.h>",
|
||||
"#include <linux/audit.h>",
|
||||
"#include <sys/syscall.h>",
|
||||
"int main() {",
|
||||
" return __NR_read",
|
||||
" | PR_SET_NO_NEW_PRIVS | PR_SET_SECCOMP | AUDIT_ARCH_X86_64",
|
||||
" | BPF_K | SECCOMP_MODE_FILTER;",
|
||||
"}"
|
||||
].join('\n');
|
||||
|
||||
// Turns a version string into an array of integers
|
||||
// 1.2.3-4-generic-x-5 -> [1, 2, 3, 4, 5]
|
||||
// 1.2.3-xx-14.2 -> [1, 2, 3, 14, 2]
|
||||
// 3.2.0-23-generic-pae -> [3, 2, 0, 23]
|
||||
var version_to_array = function (version) {
|
||||
var ver_list =
|
||||
version.replace(/[^0-9]/g, '.').replace(/\.+/g, '.').replace(/\.$/, '').split('.');
|
||||
|
||||
for (var i = 0; i < ver_list.length; i++) {
|
||||
ver_list[i] = Number(ver_list[i]);
|
||||
}
|
||||
|
||||
return ver_list;
|
||||
};
|
||||
|
||||
// Compares two arrays of integers
|
||||
// Returns
|
||||
// -1 for version1 < version2
|
||||
// 0 for version1 == version2
|
||||
// 1 for version1 > version2
|
||||
var compare_versions = function (version1, version2) {
|
||||
if (version1.length === 0 && version2.length === 0) {
|
||||
return 0;
|
||||
} else if (version1.length === 0) {
|
||||
return (version2[0] === 0) ? 0 : 1;
|
||||
} else if (version2.length === 0) {
|
||||
return (version1[0] === 0) ? 0 : -1;
|
||||
} else if (version1[0] === version2[0]) {
|
||||
return compare_versions(version1.splice(1), version2.splice(1));
|
||||
} else {
|
||||
return (version1[0] < version2[0]) ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
var seccomp_version_check = function (version) {
|
||||
var ver_list = version_to_array(version);
|
||||
return compare_versions(ver_list, [3, 5, 0]);
|
||||
};
|
||||
|
||||
module.exports.detect = function (js, builder)
|
||||
{
|
||||
console.log("Searching for SECCOMP");
|
||||
var osversion = Os.release();
|
||||
|
||||
if (builder.config.systemName !== 'linux') {
|
||||
console.log("SECCOMP is only available on linux");
|
||||
} else if (process.env['Seccomp_NO']) {
|
||||
console.log("SECCOMP disabled");
|
||||
} else if (!builder.config.crossCompiling && (seccomp_version_check(osversion) === -1)) {
|
||||
console.log("SECCOMP filtering is only available in Linux 3.5+");
|
||||
} else {
|
||||
var done = js.async();
|
||||
var CanCompile = require('../node_build/CanCompile');
|
||||
var cflags = [ builder.config.cflags, '-x', 'c' ];
|
||||
|
||||
CanCompile.check(builder, TEST_PROGRAM, cflags, function (err, can) {
|
||||
if (can) {
|
||||
console.log("SECCOMP enabled");
|
||||
js.linkerDependency("util/Seccomp_linux.c");
|
||||
} else {
|
||||
console.log("Failed to get SECCOMP, compile failure: [" + err + "]");
|
||||
js.linkerDependency("util/Seccomp_dummy.c");
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
js.linkerDependency("util/Seccomp_dummy.c");
|
||||
};
|
@@ -1,32 +0,0 @@
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
/*
|
||||
* You may redistribute this program and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "util/Seccomp_impl.h"
|
||||
|
||||
// This file is for machines which do not support seccomp.
|
||||
|
||||
Er_DEFUN(void Seccomp_dropPermissions(struct Allocator* tempAlloc, struct Log* logger))
|
||||
{
|
||||
Er_ret();
|
||||
}
|
||||
|
||||
int Seccomp_isWorking()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Seccomp_exists()
|
||||
{
|
||||
return 0;
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
/*
|
||||
* You may redistribute this program and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Seccomp_impl_H
|
||||
#define Seccomp_impl_H
|
||||
|
||||
#include "exception/Er.h"
|
||||
#include "memory/Allocator.h"
|
||||
#include "util/log/Log.h"
|
||||
|
||||
Er_DEFUN(void Seccomp_dropPermissions(struct Allocator* tempAlloc, struct Log* logger));
|
||||
|
||||
int Seccomp_isWorking(void);
|
||||
|
||||
int Seccomp_exists(void);
|
||||
|
||||
#endif
|
@@ -1,467 +0,0 @@
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
/*
|
||||
* You may redistribute this program and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// sigaction() siginfo_t SIG_UNBLOCK
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
|
||||
#include "util/Seccomp_impl.h"
|
||||
#include "util/Bits.h"
|
||||
#include "util/ArchInfo.h"
|
||||
#include "util/Defined.h"
|
||||
|
||||
// getpriority()
|
||||
#include <sys/resource.h>
|
||||
#include <signal.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <errno.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/seccomp.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* A unique number which is returned as errno by getpriority(), a syscall we never use
|
||||
* this will be used by Seccomp_isWorking() to detect that the filter has been properly installed.
|
||||
*/
|
||||
#define IS_WORKING_ERRNO 3333
|
||||
|
||||
/**
|
||||
* Accessing the SIGSYS siginfo depends on the fields being defined by the libc.
|
||||
* Older libc do not yet include the needed definitions and accessor macros.
|
||||
* Work around that by falling back to si_value.sival_int which works on some
|
||||
* but not all architectures.
|
||||
*/
|
||||
#if defined(si_syscall)
|
||||
# define GET_SYSCALL_NUM(si) ((si)->si_syscall)
|
||||
#else
|
||||
#pragma message "your libc doesn't define SIGSYS signal info! \
|
||||
info about syscall number in case of SECCOMP crash can be invalid"
|
||||
# define GET_SYSCALL_NUM(si) ((si)->si_value.sival_int)
|
||||
#endif
|
||||
|
||||
static void catchViolation(int sig, siginfo_t* si, void* threadContext)
|
||||
{
|
||||
printf("Attempted banned syscall number [%d] see doc/Seccomp.md for more information\n",
|
||||
GET_SYSCALL_NUM(si));
|
||||
|
||||
if (Defined(si_syscall)) {
|
||||
printf("Your libc doesn't define SIGSYS signal info. "
|
||||
"Above information about syscall number can be invalid.\n");
|
||||
}
|
||||
|
||||
Assert_failure("Disallowed Syscall");
|
||||
}
|
||||
|
||||
struct Filter {
|
||||
int label;
|
||||
int jt;
|
||||
int jf;
|
||||
struct sock_filter sf;
|
||||
};
|
||||
|
||||
static struct sock_fprog* compile(struct Filter* input, int inputLen, struct Allocator* alloc)
|
||||
{
|
||||
// compute gotos
|
||||
int totalOut = 0;
|
||||
for (int i = inputLen-1; i >= 0; i--) {
|
||||
struct Filter* a = &input[i];
|
||||
if (a->label == 0) {
|
||||
// check for unresolved gotos...
|
||||
Assert_true(a->jt == 0 && a->jf == 0);
|
||||
totalOut++;
|
||||
continue;
|
||||
}
|
||||
int diff = 0;
|
||||
for (int j = i-1; j >= 0; j--) {
|
||||
struct Filter* b = &input[j];
|
||||
if (b->label != 0) { continue; }
|
||||
if (b->jt == a->label) {
|
||||
b->sf.jt = diff;
|
||||
b->jt = 0;
|
||||
}
|
||||
if (b->jf == a->label) {
|
||||
b->sf.jf = diff;
|
||||
b->jf = 0;
|
||||
}
|
||||
diff++;
|
||||
}
|
||||
}
|
||||
|
||||
// copy into output filter array...
|
||||
struct sock_filter* sf = Allocator_calloc(alloc, sizeof(struct sock_filter), totalOut);
|
||||
int outI = 0;
|
||||
for (int i = 0; i < inputLen; i++) {
|
||||
if (input[i].label == 0) {
|
||||
Bits_memcpy(&sf[outI++], &input[i].sf, sizeof(struct sock_filter));
|
||||
}
|
||||
Assert_true(outI <= totalOut);
|
||||
Assert_true(i != inputLen-1 || outI == totalOut);
|
||||
}
|
||||
|
||||
struct sock_fprog* out = Allocator_malloc(alloc, sizeof(struct sock_fprog));
|
||||
out->len = (unsigned short) totalOut;
|
||||
out->filter = sf;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#define RET_TRAP 0x00030000u
|
||||
#define RET_ERRNO(x) (0x00050000u | ((x) & 0x0000ffffu))
|
||||
#define RET_SUCCESS 0x7fff0000u
|
||||
|
||||
static Er_DEFUN(struct sock_fprog* mkFilter(struct Allocator* alloc))
|
||||
{
|
||||
// Adding exceptions to the syscall filter:
|
||||
//
|
||||
// echo '#include <sys/syscall.h>' | gcc -E -dM - | grep 'define __NR_' | sort
|
||||
// for the full list of system calls with syscall numbers (different per ABI)
|
||||
//
|
||||
// If gdb traps out it will look like this:
|
||||
//
|
||||
// Program received signal SIGSYS, Bad system call.
|
||||
// [Switching to Thread 0x7ffff7fdd740 (LWP 14673)]
|
||||
// 0x00007ffff74d1caa in mmap64 () at ../sysdeps/unix/syscall-template.S:81
|
||||
// 81 ../sysdeps/unix/syscall-template.S: No such file or directory.
|
||||
//
|
||||
// %eax should contain the system call number (on different ABIs YMMV)
|
||||
//
|
||||
// (gdb) print $eax
|
||||
// $1 = 9
|
||||
// (gdb)
|
||||
//
|
||||
// Consult your syscall table from the above gcc command...
|
||||
//
|
||||
// #define __NR_mmap 9
|
||||
//
|
||||
// Then add:
|
||||
//
|
||||
// IFEQ(__NR_mmap, success),
|
||||
//
|
||||
// And add a comment documenting where you needed that syscall :)
|
||||
|
||||
#define STMT(code, val) { .sf = BPF_STMT(code, val) }
|
||||
|
||||
#define JMPK(type, not, input, label) { \
|
||||
.sf = BPF_JUMP(BPF_JMP+(type)+BPF_K, (input), 0, 0), \
|
||||
.jt = (!(not) ? (label) : 0), \
|
||||
.jf = ((not) ? (label) : 0) \
|
||||
}
|
||||
|
||||
// Create a label for jumps, the label must be represented by a non-zero integer.
|
||||
#define LABEL(lbl) { .label = (lbl) }
|
||||
|
||||
// Load offset into the register
|
||||
#define LOAD(offset) STMT(BPF_LD+BPF_W+BPF_ABS, (offset))
|
||||
|
||||
// Return constant value
|
||||
#define RET(val) STMT(BPF_RET+BPF_K, (val))
|
||||
|
||||
// If-equal if the currently loaded value equals input, jump to label.
|
||||
#define IFEQ(input, label) JMPK(BPF_JEQ, 0, (input), (label))
|
||||
|
||||
// If-not-equal if the currently loaded value is not equal to input, jump to label.
|
||||
#define IFNE(input, label) JMPK(BPF_JEQ, 1, (input), (label))
|
||||
|
||||
// If-greater-than
|
||||
#define IFGT(input, label) JMPK(BPF_JGT, 0, (input), (label))
|
||||
|
||||
// If-greater-than-or-equal-to
|
||||
#define IFGE(input, label) JMPK(BPF_JGE, 0, (input), (label))
|
||||
|
||||
// If-less-than
|
||||
#define IFLT(input, label) JMPK(BPF_JGE, 1, (input), (label))
|
||||
|
||||
// If-less-than-or-equal-to
|
||||
#define IFLE(input, label) JMPK(BPF_JGT, 1, (input), (label))
|
||||
|
||||
|
||||
// labels are integers so they must be predefined
|
||||
int success = 1;
|
||||
int fail = 2;
|
||||
int unmaskOnly = 3;
|
||||
int isworking = 4;
|
||||
int ioctl_setip = 5;
|
||||
int bind_netlink = 6;
|
||||
|
||||
uint32_t auditArch = ArchInfo_getAuditArch();
|
||||
|
||||
struct Filter seccompFilter[] = {
|
||||
|
||||
LOAD(offsetof(struct seccomp_data, arch)),
|
||||
IFNE(auditArch, fail),
|
||||
|
||||
// Get the syscall num.
|
||||
LOAD(offsetof(struct seccomp_data, nr)),
|
||||
|
||||
// rust/threading
|
||||
#ifdef __NR_futex
|
||||
IFEQ(__NR_futex, success),
|
||||
#endif
|
||||
|
||||
// udp
|
||||
#ifdef __NR_sendmsg
|
||||
IFEQ(__NR_sendmsg, success),
|
||||
#endif
|
||||
#ifdef __NR_recvmsg
|
||||
IFEQ(__NR_recvmsg, success),
|
||||
#endif
|
||||
|
||||
// ETHInterface
|
||||
#ifdef __NR_sendto
|
||||
IFEQ(__NR_sendto, success),
|
||||
#endif
|
||||
#ifdef __NR_recvfrom
|
||||
IFEQ(__NR_recvfrom, success),
|
||||
#endif
|
||||
|
||||
#ifdef __NR_socketcall
|
||||
// 32-bit: recvmsg is a socketcall
|
||||
IFEQ(__NR_socketcall, success),
|
||||
#endif
|
||||
|
||||
// libuv
|
||||
IFEQ(__NR_epoll_ctl, success),
|
||||
#ifdef __NR_epoll_wait
|
||||
IFEQ(__NR_epoll_wait, success),
|
||||
#endif
|
||||
#ifdef __NR_epoll_pwait
|
||||
IFEQ(__NR_epoll_pwait, success),
|
||||
#endif
|
||||
|
||||
// gettimeofday is required on some architectures
|
||||
#ifdef __NR_gettimeofday
|
||||
IFEQ(__NR_gettimeofday, success),
|
||||
#endif
|
||||
|
||||
// TUN (and logging)
|
||||
IFEQ(__NR_write, success),
|
||||
IFEQ(__NR_read, success),
|
||||
// readv and writev are used by some libc (musl)
|
||||
#ifdef __NR_readv
|
||||
IFEQ(__NR_readv, success),
|
||||
#endif
|
||||
#ifdef __NR_writev
|
||||
IFEQ(__NR_writev, success),
|
||||
#endif
|
||||
|
||||
// modern librt reads a read-only mapped section of kernel space which contains the time
|
||||
// older versions need system calls for getting the time.
|
||||
// i686 glibc-2.18's time() uses __NR_time
|
||||
// Raspberry Pi and BeagleBone Black don't provide __NR_time
|
||||
// 32-bit systems with 64-bit time_t use __NR_clock_gettime64
|
||||
#ifdef __NR_clock_gettime64
|
||||
IFEQ(__NR_clock_gettime64, success),
|
||||
#endif
|
||||
#ifdef __NR_clock_gettime
|
||||
IFEQ(__NR_clock_gettime, success),
|
||||
#endif
|
||||
#ifdef __NR_time
|
||||
IFEQ(__NR_time, success),
|
||||
#endif
|
||||
|
||||
// NetPlatform_linux.c send recv
|
||||
#ifdef __NR_send
|
||||
IFEQ(__NR_send, success),
|
||||
#endif
|
||||
#ifdef __NR_recv
|
||||
IFEQ(__NR_recv, success),
|
||||
#endif
|
||||
|
||||
// malloc()
|
||||
IFEQ(__NR_brk, success),
|
||||
|
||||
// abort()
|
||||
IFEQ(__NR_gettid, success),
|
||||
IFEQ(__NR_tgkill, success),
|
||||
IFEQ(__NR_rt_sigprocmask, unmaskOnly),
|
||||
|
||||
// exit()
|
||||
IFEQ(__NR_exit_group, success),
|
||||
|
||||
// Seccomp_isWorking()
|
||||
IFEQ(__NR_getpriority, isworking),
|
||||
|
||||
// Securiy_checkPermissions() -> canOpenFiles()
|
||||
IFEQ(__NR_dup, success),
|
||||
IFEQ(__NR_close, success),
|
||||
|
||||
// Security_checkPermissions() -> getMaxMem()
|
||||
// x86/ARM use ugetrlimit and mmap2
|
||||
// ARM does not even have __NR_getrlimit or __NR_mmap defined
|
||||
// and AMD64 does not have __NR_ugetrlimit or __NR_mmap2 defined
|
||||
#ifdef __NR_getrlimit
|
||||
IFEQ(__NR_getrlimit, success),
|
||||
#endif
|
||||
#ifdef __NR_ugetrlimit
|
||||
IFEQ(__NR_ugetrlimit, success),
|
||||
#endif
|
||||
#ifdef __NR_mmap
|
||||
IFEQ(__NR_mmap, success),
|
||||
#endif
|
||||
#ifdef __NR_mmap2
|
||||
IFEQ(__NR_mmap2, success),
|
||||
#endif
|
||||
IFEQ(__NR_munmap, success),
|
||||
|
||||
// printf()
|
||||
IFEQ(__NR_fstat, success),
|
||||
#ifdef __NR_fstat64
|
||||
IFEQ(__NR_fstat64, success),
|
||||
#endif
|
||||
|
||||
// for setting IP addresses
|
||||
// socketForIfName()
|
||||
// and ETHInterface_listDevices
|
||||
#ifdef __NR_socket
|
||||
IFEQ(__NR_socket, success),
|
||||
#endif
|
||||
IFEQ(__NR_ioctl, ioctl_setip),
|
||||
|
||||
// Security_checkPermissions
|
||||
IFEQ(__NR_getuid, success),
|
||||
// Security_nofiles
|
||||
IFEQ(__NR_setrlimit, success),
|
||||
|
||||
// for ETHInterface_listDevices (netlinkk)
|
||||
#ifdef __NR_bind
|
||||
IFEQ(__NR_bind, bind_netlink),
|
||||
#endif
|
||||
#ifdef __NR_getsockname
|
||||
IFEQ(__NR_getsockname, success),
|
||||
#endif
|
||||
|
||||
// musl free() calls madvise()
|
||||
#ifdef __NR_madvise
|
||||
IFEQ(__NR_madvise, success),
|
||||
#endif
|
||||
|
||||
// accept() for PipeServer
|
||||
#ifdef __NR_accept4
|
||||
IFEQ(__NR_accept4, success),
|
||||
#endif
|
||||
|
||||
#ifdef Cjdns_android
|
||||
#ifdef __NR_rt_sigprocmask
|
||||
IFEQ(__NR_rt_sigprocmask, success),
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// rust/wg
|
||||
#ifdef __NR_getrandom
|
||||
IFEQ(__NR_getrandom, success),
|
||||
#endif
|
||||
|
||||
// https://github.com/cjdelisle/boringtun/blob/master/src/crypto/x25519/mod.rs#L22
|
||||
#if defined(__ARM_EABI__) && defined(__NR_fcntl64)
|
||||
IFEQ(__NR_fcntl64, success),
|
||||
#endif
|
||||
|
||||
// 2024-01-09 by Caleb's advice
|
||||
// it is used by Seccomp_test
|
||||
#ifdef __NR_sigaltstack
|
||||
IFEQ(__NR_sigaltstack, success),
|
||||
#endif
|
||||
|
||||
RET(SECCOMP_RET_TRAP),
|
||||
|
||||
LABEL(ioctl_setip),
|
||||
LOAD(offsetof(struct seccomp_data, args[1])),
|
||||
IFEQ(SIOCGIFINDEX, success),
|
||||
IFEQ(SIOCGIFFLAGS, success),
|
||||
IFEQ(SIOCSIFFLAGS, success),
|
||||
IFEQ(SIOCSIFADDR, success),
|
||||
IFEQ(SIOCSIFNETMASK, success),
|
||||
IFEQ(SIOCSIFMTU, success),
|
||||
RET(SECCOMP_RET_TRAP),
|
||||
|
||||
LABEL(bind_netlink),
|
||||
LOAD(offsetof(struct seccomp_data, args[2])),
|
||||
// Filter NETLINK by size of address.
|
||||
// Most importantly INET and INET6
|
||||
// are differnt.
|
||||
IFEQ(sizeof(struct sockaddr_nl), success),
|
||||
RET(SECCOMP_RET_TRAP),
|
||||
|
||||
// We allow sigprocmask to *unmask* signals but we don't allow it to mask them.
|
||||
LABEL(unmaskOnly),
|
||||
LOAD(offsetof(struct seccomp_data, args[0])),
|
||||
IFEQ(SIG_UNBLOCK, success),
|
||||
RET(SECCOMP_RET_TRAP),
|
||||
|
||||
LABEL(isworking),
|
||||
RET(RET_ERRNO(IS_WORKING_ERRNO)),
|
||||
|
||||
LABEL(fail),
|
||||
RET(SECCOMP_RET_TRAP),
|
||||
|
||||
LABEL(success),
|
||||
RET(SECCOMP_RET_ALLOW),
|
||||
};
|
||||
|
||||
Er_ret(compile(seccompFilter, sizeof(seccompFilter)/sizeof(seccompFilter[0]), alloc));
|
||||
}
|
||||
|
||||
static Er_DEFUN(void installFilter(
|
||||
struct sock_fprog* filter, struct Log* logger, struct Allocator* alloc))
|
||||
{
|
||||
struct sigaction sa = { .sa_sigaction = catchViolation, .sa_flags = SA_SIGINFO };
|
||||
if (sigaction(SIGSYS, &sa, NULL)) {
|
||||
Log_warn(logger, "sigaction(SIGSYS) -> [%s]\n", strerror(errno));
|
||||
}
|
||||
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
|
||||
// don't worry about it.
|
||||
Log_warn(logger, "prctl(PR_SET_NO_NEW_PRIVS) -> [%s]\n", strerror(errno));
|
||||
}
|
||||
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, filter) == -1) {
|
||||
Er_raise(alloc, "prctl(PR_SET_SECCOMP) -> [%s]\n", strerror(errno));
|
||||
}
|
||||
Er_ret();
|
||||
}
|
||||
|
||||
Er_DEFUN(void Seccomp_dropPermissions(struct Allocator* tempAlloc, struct Log* logger))
|
||||
{
|
||||
struct sock_fprog* filter = Er(mkFilter(tempAlloc));
|
||||
Er(installFilter(filter, logger, tempAlloc));
|
||||
if (!Seccomp_isWorking()) {
|
||||
Er_raise(tempAlloc, "Seccomp filter not installed properly, Seccomp_isWorking() -> false");
|
||||
}
|
||||
Er_ret();
|
||||
}
|
||||
|
||||
int Seccomp_isWorking(void)
|
||||
{
|
||||
errno = 0;
|
||||
// If seccomp is not working, this will fail setting errno to EINVAL
|
||||
long ret = getpriority(1000, 1);
|
||||
|
||||
int err = errno;
|
||||
|
||||
// Inside of the kernel, it seems to check whether the errno return is sane
|
||||
// and if it is not, it treates it as a return value, IS_WORKING_ERRNO (3333) is very unique so
|
||||
// we'll check for either case just in case this changes.
|
||||
return (ret == -1 && err == IS_WORKING_ERRNO) || (ret == -IS_WORKING_ERRNO && err == 0);
|
||||
}
|
||||
|
||||
int Seccomp_exists(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
@@ -18,7 +18,6 @@
|
||||
#include "exception/Except.h"
|
||||
#include "util/log/Log.h"
|
||||
#include "util/Security.h"
|
||||
#include "util/Seccomp.h"
|
||||
#include "memory/Allocator.h"
|
||||
#include "util/Bits.h"
|
||||
#include "util/Setuid.h"
|
||||
@@ -137,12 +136,6 @@ Er_DEFUN(void Security_chroot(char* root, struct Allocator* errAlloc))
|
||||
Er_ret();
|
||||
}
|
||||
|
||||
Er_DEFUN(void Security_seccomp(struct Allocator* tempAlloc, struct Log* logger))
|
||||
{
|
||||
Er(Seccomp_dropPermissions(tempAlloc, logger));
|
||||
Er_ret();
|
||||
}
|
||||
|
||||
struct Security_pvt
|
||||
{
|
||||
struct Security pub;
|
||||
@@ -181,8 +174,6 @@ Er_DEFUN(struct Security_Permissions* Security_checkPermissions(struct Allocator
|
||||
Allocator_calloc(alloc, sizeof(struct Security_Permissions), 1);
|
||||
|
||||
out->noOpenFiles = !canOpenFiles();
|
||||
out->seccompExists = Seccomp_exists();
|
||||
out->seccompEnforcing = Seccomp_isWorking();
|
||||
out->uid = getuid();
|
||||
|
||||
Er_ret(out);
|
||||
|
@@ -33,8 +33,6 @@
|
||||
struct Security_Permissions
|
||||
{
|
||||
int noOpenFiles;
|
||||
int seccompExists;
|
||||
int seccompEnforcing;
|
||||
int uid;
|
||||
};
|
||||
|
||||
@@ -55,8 +53,6 @@ Er_DEFUN(void Security_noforks(struct Allocator* errAlloc));
|
||||
|
||||
Er_DEFUN(void Security_chroot(char* root, struct Allocator* errAlloc));
|
||||
|
||||
Er_DEFUN(void Security_seccomp(struct Allocator* tempAlloc, struct Log* logger));
|
||||
|
||||
void Security_setupComplete(struct Security* security);
|
||||
|
||||
struct Security* Security_new(struct Allocator* alloc, struct Log* log, EventBase_t* base);
|
||||
|
@@ -62,8 +62,6 @@ static void checkPermissions(Dict* args, void* vctx, String* txid, struct Alloca
|
||||
}
|
||||
Dict* out = Dict_new(requestAlloc);
|
||||
Dict_putIntC(out, "noOpenFiles", sp->noOpenFiles, requestAlloc);
|
||||
Dict_putIntC(out, "seccompExists", sp->seccompExists, requestAlloc);
|
||||
Dict_putIntC(out, "seccompEnforcing", sp->seccompEnforcing, requestAlloc);
|
||||
Dict_putIntC(out, "userId", sp->uid, requestAlloc);
|
||||
Dict_putStringCC(out, "error", "none", requestAlloc);
|
||||
Admin_sendMessage(out, txid, ctx->admin);
|
||||
@@ -105,27 +103,6 @@ static void chroot(Dict* args, void* vctx, String* txid, struct Allocator* reque
|
||||
sendError("none", txid, ctx->admin);
|
||||
}
|
||||
|
||||
static void seccomp(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc)
|
||||
{
|
||||
struct Context* const ctx = Identity_check((struct Context*) vctx);
|
||||
struct Er_Ret* er = NULL;
|
||||
struct Security_Permissions* sp = Er_check(&er, Security_checkPermissions(requestAlloc));
|
||||
if (er) {
|
||||
sendError(er->message, txid, ctx->admin);
|
||||
return;
|
||||
}
|
||||
if (sp->seccompEnforcing) {
|
||||
sendError("seccomp is already enabled", txid, ctx->admin);
|
||||
return;
|
||||
}
|
||||
Er_check(&er, Security_seccomp(requestAlloc, ctx->logger));
|
||||
if (er) {
|
||||
sendError(er->message, txid, ctx->admin);
|
||||
return;
|
||||
}
|
||||
sendError("none", txid, ctx->admin);
|
||||
}
|
||||
|
||||
static void setupComplete(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc)
|
||||
{
|
||||
struct Context* const ctx = Identity_check((struct Context*) vctx);
|
||||
@@ -166,7 +143,6 @@ void Security_admin_register(struct Allocator* alloc,
|
||||
Admin_registerFunction("Security_getUser", getUser, ctx, true, ((struct Admin_FunctionArg[]) {
|
||||
{ .name = "user", .required = 0, .type = "String" }
|
||||
}), admin);
|
||||
Admin_registerFunction("Security_seccomp", seccomp, ctx, true, NULL, admin);
|
||||
Admin_registerFunction("Security_setupComplete", setupComplete, ctx, true, NULL, admin);
|
||||
Admin_registerFunction("Security_checkPermissions", checkPermissions, ctx, true, NULL, admin);
|
||||
}
|
||||
|
@@ -57,11 +57,6 @@ Er_DEFUN(void Security_chroot(char* root, struct Allocator* errAlloc))
|
||||
Er_ret();
|
||||
}
|
||||
|
||||
Er_DEFUN(void Security_seccomp(struct Allocator* tempAlloc, struct Log* logger))
|
||||
{
|
||||
Er_ret();
|
||||
}
|
||||
|
||||
struct Security_pvt
|
||||
{
|
||||
struct Security pub;
|
||||
|
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
#include "memory/Allocator.h"
|
||||
#include "util/SysInfo.h"
|
||||
#include "util/Seccomp.h"
|
||||
#include "util/CString.h"
|
||||
#include "util/Bits.h"
|
||||
#include "util/Defined.h"
|
||||
@@ -43,8 +42,6 @@ struct SysInfo SysInfo_detect(void)
|
||||
out.os = SysInfo_Os_UNKNOWN;
|
||||
}
|
||||
|
||||
out.seccomp = Seccomp_exists();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -64,9 +61,8 @@ static char* getName(enum SysInfo_Os os)
|
||||
char* SysInfo_describe(struct SysInfo si, struct Allocator* alloc)
|
||||
{
|
||||
uint8_t buff[BUFF_SZ];
|
||||
snprintf(buff, BUFF_SZ, "%s%s",
|
||||
getName(si.os),
|
||||
(si.seccomp) ? " +seccomp" : "");
|
||||
snprintf(buff, BUFF_SZ, "%s",
|
||||
getName(si.os));
|
||||
|
||||
int len = CString_strlen(buff)+1;
|
||||
char* out = Allocator_malloc(alloc, len);
|
||||
|
@@ -35,7 +35,6 @@ enum SysInfo_Os
|
||||
|
||||
struct SysInfo
|
||||
{
|
||||
int seccomp : 1;
|
||||
int os : 4;
|
||||
};
|
||||
Assert_compileTime(sizeof(struct SysInfo) == 4);
|
||||
|
@@ -1,155 +0,0 @@
|
||||
/* vim: set expandtab ts=4 sw=4: */
|
||||
/*
|
||||
* You may redistribute this program and/or modify it under the terms of
|
||||
* the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "benc/String.h"
|
||||
#include "util/Identity.h"
|
||||
#include "util/log/FileWriterLog.h"
|
||||
#include "memory/Allocator.h"
|
||||
#include "util/Seccomp.h"
|
||||
#include "util/events/EventBase.h"
|
||||
#include "util/events/Process.h"
|
||||
#include "util/events/Pipe.h"
|
||||
#include "util/events/Socket.h"
|
||||
#include "util/events/Timeout.h"
|
||||
#include "util/CString.h"
|
||||
#include "crypto/random/Random.h"
|
||||
#include "interface/addressable/AddrIface.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
struct Context
|
||||
{
|
||||
struct Iface iface;
|
||||
struct Allocator* alloc;
|
||||
EventBase_t* eventBase;
|
||||
Identity
|
||||
};
|
||||
|
||||
struct ChildCtx
|
||||
{
|
||||
EventBase_t* base;
|
||||
struct Log* log;
|
||||
Iface_t* socket;
|
||||
struct Allocator* alloc;
|
||||
Identity
|
||||
};
|
||||
|
||||
static void childMessageSent(struct Allocator_OnFreeJob* j) {
|
||||
struct ChildCtx* child = Identity_check((struct ChildCtx*) j->userData);
|
||||
printf("Child shutting down\n");
|
||||
EventBase_endLoop(child->base);
|
||||
}
|
||||
|
||||
static void timeout(void* vNULL)
|
||||
{
|
||||
Assert_true(!"timed out");
|
||||
}
|
||||
|
||||
static void onConnectionChild(struct ChildCtx* child)
|
||||
{
|
||||
Er_assert(Seccomp_dropPermissions(child->alloc, child->log));
|
||||
Assert_true(Seccomp_isWorking());
|
||||
|
||||
Allocator_t* alloc = Allocator_child(child->alloc);
|
||||
Allocator_t* alloc1 = Allocator_child(alloc);
|
||||
|
||||
Message_t* ok = Message_new(0, 512, alloc1);
|
||||
Er_assert(Message_epush(ok, "OK", 3));
|
||||
|
||||
struct Iface iface = { .send = NULL };
|
||||
Iface_plumb(child->socket, &iface);
|
||||
Iface_send(&iface, ok);
|
||||
|
||||
Allocator_onFree(alloc1, childMessageSent, child);
|
||||
|
||||
Allocator_free(alloc);
|
||||
|
||||
// just set a timeout long enough that we're pretty sure the parent will get the message
|
||||
// before we quit.
|
||||
// Timeout_setInterval(childComplete, child->base, 10, child->base, child->alloc);
|
||||
Timeout_setTimeout(timeout, child->base, 2000, child->base, alloc);
|
||||
EventBase_beginLoop(child->base);
|
||||
}
|
||||
|
||||
static void timeout2(void* vNULL)
|
||||
{
|
||||
Assert_true(!"time out 2");
|
||||
}
|
||||
|
||||
static int child(char* pipeName, struct Allocator* alloc, struct Log* logger)
|
||||
{
|
||||
struct ChildCtx* ctx = Allocator_calloc(alloc, sizeof(struct ChildCtx), 1);
|
||||
ctx->base = EventBase_new(alloc);
|
||||
ctx->alloc = alloc;
|
||||
ctx->log = logger;
|
||||
ctx->socket = Er_assert(Socket_connect(pipeName, alloc));
|
||||
Identity_set(ctx);
|
||||
onConnectionChild(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Iface_DEFUN receiveMessageParent(Message_t* msg, struct Iface* iface)
|
||||
{
|
||||
struct Context* ctx = Identity_check((struct Context*) iface);
|
||||
// PipeServer pushes a uint32 identifier of the client who sent the message
|
||||
Er_assert(AddrIface_popAddr(msg));
|
||||
Assert_true(Message_getLength(msg) == 3);
|
||||
Assert_true(!Bits_memcmp(Message_bytes(msg), "OK", 3));
|
||||
printf("Parent got reply\n");
|
||||
EventBase_endLoop(ctx->eventBase);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
struct Allocator* alloc = Allocator_new(20000);
|
||||
struct Log* logger = FileWriterLog_new(stdout, alloc);
|
||||
|
||||
if (!Seccomp_exists()) {
|
||||
Log_debug(logger, "Seccomp not supported on this system");
|
||||
return 0;
|
||||
}
|
||||
if (argc > 3 && !CString_strcmp("Seccomp_test", argv[1]) && !CString_strcmp("child", argv[2])) {
|
||||
child(argv[3], alloc, logger);
|
||||
// Allocator_free(alloc);
|
||||
// TODO: Freeing the allocator causes a Identity_check() assertion crash in Pipe.c, replace after async allocator free is abolished.
|
||||
return 0;
|
||||
}
|
||||
|
||||
EventBase_t* eb = EventBase_new(alloc);
|
||||
struct Random* rand = Random_new(alloc, logger, NULL);
|
||||
char randName[32] = {0};
|
||||
Random_base32(rand, (uint8_t*)randName, 31);
|
||||
String* name = String_printf(alloc, "%s%scjdns-test-%s", Pipe_PATH, Pipe_PATH_SEP, randName);
|
||||
|
||||
struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
|
||||
Identity_set(ctx);
|
||||
ctx->alloc = alloc;
|
||||
ctx->iface.send = receiveMessageParent;
|
||||
ctx->eventBase = eb;
|
||||
|
||||
Socket_Server_t* ss = Er_assert(Socket_server(name->bytes, alloc));
|
||||
Iface_plumb(&ctx->iface, ss->iface);
|
||||
|
||||
const char* path = Process_getPath(alloc);
|
||||
const char* args[] = { "Seccomp_test", "child", name->bytes, NULL };
|
||||
|
||||
Assert_true(!Process_spawn(path, args, alloc, NULL));
|
||||
|
||||
Timeout_setTimeout(timeout2, NULL, 2000, eb, alloc);
|
||||
|
||||
EventBase_beginLoop(eb);
|
||||
unlink(name->bytes);
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user