bunpen: refactor kernel bindings into a rtext
module
additionally, this requires moving all other files into their own directories, else hare doesn't seem to recognize 'rtext' as a module
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
all: bunpen
|
||||
|
||||
bunpen:
|
||||
hare build -o $@ src
|
||||
hare build -o $@ main/
|
||||
|
||||
install:
|
||||
mkdir -p $(PREFIX)/bin
|
||||
install -m755 bunpen $(PREFIX)/bin
|
||||
|
||||
test:
|
||||
hare test src
|
||||
hare test
|
||||
|
||||
.PHONY: all install test
|
||||
|
62
pkgs/additional/bunpen/main/landlock.ha
Normal file
62
pkgs/additional/bunpen/main/landlock.ha
Normal file
@@ -0,0 +1,62 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
use log;
|
||||
use os;
|
||||
use rt;
|
||||
use rtext;
|
||||
|
||||
fn access_fs_roughly_read() u64 = return
|
||||
rtext::LANDLOCK_ACCESS_FS_EXECUTE |
|
||||
rtext::LANDLOCK_ACCESS_FS_READ_FILE |
|
||||
rtext::LANDLOCK_ACCESS_FS_READ_DIR
|
||||
;
|
||||
fn access_fs_roughly_write() u64 = return
|
||||
rtext::LANDLOCK_ACCESS_FS_WRITE_FILE |
|
||||
rtext::LANDLOCK_ACCESS_FS_REMOVE_DIR |
|
||||
rtext::LANDLOCK_ACCESS_FS_REMOVE_FILE |
|
||||
rtext::LANDLOCK_ACCESS_FS_MAKE_CHAR |
|
||||
rtext::LANDLOCK_ACCESS_FS_MAKE_DIR |
|
||||
rtext::LANDLOCK_ACCESS_FS_MAKE_REG |
|
||||
rtext::LANDLOCK_ACCESS_FS_MAKE_SOCK |
|
||||
rtext::LANDLOCK_ACCESS_FS_MAKE_FIFO |
|
||||
rtext::LANDLOCK_ACCESS_FS_MAKE_BLOCK |
|
||||
rtext::LANDLOCK_ACCESS_FS_MAKE_SYM |
|
||||
rtext::LANDLOCK_ACCESS_FS_REFER |
|
||||
rtext::LANDLOCK_ACCESS_FS_TRUNCATE |
|
||||
rtext::LANDLOCK_ACCESS_FS_IOCTL_DEV
|
||||
;
|
||||
|
||||
fn access_fs_roughly_rw() u64 = return access_fs_roughly_read() | access_fs_roughly_write();
|
||||
|
||||
fn landlock_restrict() void = {
|
||||
let abi = rtext::landlock_create_ruleset(null, rtext::LANDLOCK_CREATE_RULESET_VERSION)!;
|
||||
log::printfln("found landlock version {}", abi);
|
||||
|
||||
// determine the access modes we can ask this kernel to restrict on:
|
||||
let ruleset_attr = rtext::landlock_ruleset_attr {
|
||||
handled_access_fs = access_fs_roughly_rw(),
|
||||
handled_access_net = rtext::LANDLOCK_ACCESS_NET_BIND_TCP | rtext::LANDLOCK_ACCESS_NET_CONNECT_TCP,
|
||||
};
|
||||
if (abi == 1) {
|
||||
ruleset_attr.handled_access_fs &= ~rtext::LANDLOCK_ACCESS_FS_REFER;
|
||||
};
|
||||
if (abi <= 2) {
|
||||
ruleset_attr.handled_access_fs &= ~rtext::LANDLOCK_ACCESS_FS_TRUNCATE;
|
||||
};
|
||||
if (abi <= 3) {
|
||||
ruleset_attr.handled_access_net &= ~(rtext::LANDLOCK_ACCESS_NET_BIND_TCP | rtext::LANDLOCK_ACCESS_NET_CONNECT_TCP);
|
||||
};
|
||||
if (abi <= 4) {
|
||||
ruleset_attr.handled_access_fs &= ~rtext::LANDLOCK_ACCESS_FS_IOCTL_DEV;
|
||||
};
|
||||
let ruleset_fd = rtext::landlock_create_ruleset(&ruleset_attr)!;
|
||||
|
||||
let root_fd = rt::open("/", rt::O_PATH | rt::O_CLOEXEC, 0)!; //< O_PATH allows for opening files which are `x` but not `r`
|
||||
rtext::landlock_add_rule(ruleset_fd, &rtext::landlock_path_beneath_attr {
|
||||
allowed_access = access_fs_roughly_rw(),
|
||||
parent_fd = root_fd,
|
||||
})!;
|
||||
|
||||
log::println("landlock_restrict: TODO: populate net access (landlock_add_rule)");
|
||||
|
||||
rtext::landlock_restrict_self(ruleset_fd)!;
|
||||
};
|
@@ -1,5 +1,6 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
use log;
|
||||
use rtext;
|
||||
use strings;
|
||||
use os;
|
||||
use os::exec;
|
||||
@@ -16,7 +17,7 @@ fn do_exec(args: []str) never = {
|
||||
export fn main() void = {
|
||||
let my_name = os::args[0];
|
||||
let exec_line = os::args[1..];
|
||||
no_new_privs();
|
||||
rtext::no_new_privs();
|
||||
landlock_restrict();
|
||||
do_exec(exec_line);
|
||||
};
|
79
pkgs/additional/bunpen/rtext/landlock.ha
Normal file
79
pkgs/additional/bunpen/rtext/landlock.ha
Normal file
@@ -0,0 +1,79 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
use rt;
|
||||
|
||||
///// kernel consts. TODO: extract these from kernel headers, somehow.
|
||||
// landlock syscall numbers
|
||||
const __NR_landlock_create_ruleset: u64 = 444;
|
||||
const __NR_landlock_add_rule: u64 = 445;
|
||||
const __NR_landlock_restrict_self: u64 = 446;
|
||||
// ---- landlock API constants ----
|
||||
export const LANDLOCK_CREATE_RULESET_VERSION = 1u64 << 0;
|
||||
// landlock API: fs_access
|
||||
export const LANDLOCK_ACCESS_FS_EXECUTE: u64 = 1u64 << 0;
|
||||
export const LANDLOCK_ACCESS_FS_WRITE_FILE: u64 = 1u64 << 1;
|
||||
export const LANDLOCK_ACCESS_FS_READ_FILE: u64 = 1u64 << 2;
|
||||
export const LANDLOCK_ACCESS_FS_READ_DIR: u64 = 1u64 << 3;
|
||||
export const LANDLOCK_ACCESS_FS_REMOVE_DIR: u64 = 1u64 << 4;
|
||||
export const LANDLOCK_ACCESS_FS_REMOVE_FILE: u64 = 1u64 << 5;
|
||||
export const LANDLOCK_ACCESS_FS_MAKE_CHAR: u64 = 1u64 << 6;
|
||||
export const LANDLOCK_ACCESS_FS_MAKE_DIR: u64 = 1u64 << 7;
|
||||
export const LANDLOCK_ACCESS_FS_MAKE_REG: u64 = 1u64 << 8;
|
||||
export const LANDLOCK_ACCESS_FS_MAKE_SOCK: u64 = 1u64 << 9;
|
||||
export const LANDLOCK_ACCESS_FS_MAKE_FIFO: u64 = 1u64 << 10;
|
||||
export const LANDLOCK_ACCESS_FS_MAKE_BLOCK: u64 = 1u64 << 11;
|
||||
export const LANDLOCK_ACCESS_FS_MAKE_SYM: u64 = 1u64 << 12;
|
||||
export const LANDLOCK_ACCESS_FS_REFER: u64 = 1u64 << 13;
|
||||
export const LANDLOCK_ACCESS_FS_TRUNCATE: u64 = 1u64 << 14;
|
||||
export const LANDLOCK_ACCESS_FS_IOCTL_DEV: u64 = 1u64 << 15;
|
||||
// landlock API: net_access
|
||||
export const LANDLOCK_ACCESS_NET_BIND_TCP: u64 = 1u64 << 0;
|
||||
export const LANDLOCK_ACCESS_NET_CONNECT_TCP: u64 = 1u64 << 1;
|
||||
// landlock API: landlock_rule_type
|
||||
const LANDLOCK_RULE_PATH_BENEATH: u64 = 1;
|
||||
const LANDLOCK_RULE_NET_PORT: u64 = 2;
|
||||
|
||||
// lifted from <repo:kernel.org/linux:include/uapi/linux/landlock.h>
|
||||
// argument to `sys_landlock_create_ruleset`.
|
||||
// landlock ruleset definition.
|
||||
export type landlock_ruleset_attr = struct {
|
||||
// bitmask of handled filesystem actions
|
||||
handled_access_fs: u64,
|
||||
// bitmask of handled network actions
|
||||
handled_access_net: u64,
|
||||
};
|
||||
export type landlock_path_beneath_attr = struct {
|
||||
allowed_access: u64,
|
||||
parent_fd: i32,
|
||||
};
|
||||
export type landlock_net_port_attr = struct {
|
||||
allowed_access: u64,
|
||||
port: u64,
|
||||
};
|
||||
|
||||
// landlock_create_ruleset syscall
|
||||
export fn landlock_create_ruleset(attr: nullable *landlock_ruleset_attr, flags: u64 = 0) (rt::errno | u64) = {
|
||||
const size_: u64 = match (attr) {
|
||||
case null => yield 0;
|
||||
case => yield size(landlock_ruleset_attr);
|
||||
};
|
||||
return syscall(__NR_landlock_create_ruleset, attr: uintptr, size_, flags);
|
||||
};
|
||||
|
||||
export fn landlock_add_rule(
|
||||
ruleset_fd: u64,
|
||||
rule_attr: (*landlock_path_beneath_attr | *landlock_net_port_attr),
|
||||
flags: u64 = 0,
|
||||
) (rt::errno | u64) = {
|
||||
const (rule_type, rule_attr) = match (rule_attr) {
|
||||
case let p: *landlock_path_beneath_attr => yield (LANDLOCK_RULE_PATH_BENEATH, p: uintptr);
|
||||
case let p: *landlock_net_port_attr => yield (LANDLOCK_RULE_NET_PORT, p: uintptr);
|
||||
};
|
||||
return syscall(__NR_landlock_add_rule, ruleset_fd: u64, rule_type, rule_attr: uintptr, flags);
|
||||
};
|
||||
|
||||
export fn landlock_restrict_self(
|
||||
ruleset_fd: u64,
|
||||
flags: u64 = 0,
|
||||
) (rt::errno | u64) = {
|
||||
return syscall(__NR_landlock_restrict_self, ruleset_fd: u64, flags);
|
||||
};
|
6
pkgs/additional/bunpen/rtext/no_new_privs.ha
Normal file
6
pkgs/additional/bunpen/rtext/no_new_privs.ha
Normal file
@@ -0,0 +1,6 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
use rt;
|
||||
|
||||
export fn no_new_privs() void = {
|
||||
rt::prctl(rt::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)!;
|
||||
};
|
18
pkgs/additional/bunpen/rtext/syscall.ha
Normal file
18
pkgs/additional/bunpen/rtext/syscall.ha
Normal file
@@ -0,0 +1,18 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
use rt;
|
||||
|
||||
// like `rt::syscall`, but maps negative return values to `errno`
|
||||
fn syscall(num: u64, args: u64...) (rt::errno | u64) = {
|
||||
return wrap_return(rt::syscall(num, args...));
|
||||
};
|
||||
|
||||
// checks the return value from a Linux syscall and, if found to be in error,
|
||||
// returns the appropriate error. otherwise, returns the original value.
|
||||
// borrowed from non-public hare internals: rt/+linux/errno.ha
|
||||
fn wrap_return(r: u64) (rt::errno | u64) = {
|
||||
if (r > -4096: u64) {
|
||||
return (-(r: i64)): rt::errno;
|
||||
};
|
||||
return r;
|
||||
};
|
||||
|
@@ -1,107 +0,0 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
use rt;
|
||||
|
||||
fn no_new_privs() void = {
|
||||
rt::prctl(rt::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)!;
|
||||
};
|
||||
|
||||
///// kernel consts. TODO: extract these from kernel headers, somehow.
|
||||
// landlock syscall numbers
|
||||
const __NR_landlock_create_ruleset: u64 = 444;
|
||||
const __NR_landlock_add_rule: u64 = 445;
|
||||
const __NR_landlock_restrict_self: u64 = 446;
|
||||
// ---- landlock API constants ----
|
||||
const LANDLOCK_CREATE_RULESET_VERSION = 1u64 << 0;
|
||||
// landlock API: fs_access
|
||||
const LANDLOCK_ACCESS_FS_EXECUTE: u64 = 1u64 << 0;
|
||||
const LANDLOCK_ACCESS_FS_WRITE_FILE: u64 = 1u64 << 1;
|
||||
const LANDLOCK_ACCESS_FS_READ_FILE: u64 = 1u64 << 2;
|
||||
const LANDLOCK_ACCESS_FS_READ_DIR: u64 = 1u64 << 3;
|
||||
const LANDLOCK_ACCESS_FS_REMOVE_DIR: u64 = 1u64 << 4;
|
||||
const LANDLOCK_ACCESS_FS_REMOVE_FILE: u64 = 1u64 << 5;
|
||||
const LANDLOCK_ACCESS_FS_MAKE_CHAR: u64 = 1u64 << 6;
|
||||
const LANDLOCK_ACCESS_FS_MAKE_DIR: u64 = 1u64 << 7;
|
||||
const LANDLOCK_ACCESS_FS_MAKE_REG: u64 = 1u64 << 8;
|
||||
const LANDLOCK_ACCESS_FS_MAKE_SOCK: u64 = 1u64 << 9;
|
||||
const LANDLOCK_ACCESS_FS_MAKE_FIFO: u64 = 1u64 << 10;
|
||||
const LANDLOCK_ACCESS_FS_MAKE_BLOCK: u64 = 1u64 << 11;
|
||||
const LANDLOCK_ACCESS_FS_MAKE_SYM: u64 = 1u64 << 12;
|
||||
const LANDLOCK_ACCESS_FS_REFER: u64 = 1u64 << 13;
|
||||
const LANDLOCK_ACCESS_FS_TRUNCATE: u64 = 1u64 << 14;
|
||||
const LANDLOCK_ACCESS_FS_IOCTL_DEV: u64 = 1u64 << 15;
|
||||
// landlock API: net_access
|
||||
const LANDLOCK_ACCESS_NET_BIND_TCP: u64 = 1u64 << 0;
|
||||
const LANDLOCK_ACCESS_NET_CONNECT_TCP: u64 = 1u64 << 1;
|
||||
// landlock API: landlock_rule_type
|
||||
const LANDLOCK_RULE_PATH_BENEATH: u64 = 1;
|
||||
const LANDLOCK_RULE_NET_PORT: u64 = 2;
|
||||
|
||||
// lifted from <repo:kernel.org/linux:include/uapi/linux/landlock.h>
|
||||
// argument to `sys_landlock_create_ruleset`.
|
||||
// landlock ruleset definition.
|
||||
type landlock_ruleset_attr = struct {
|
||||
// bitmask of handled filesystem actions
|
||||
handled_access_fs: u64,
|
||||
// bitmask of handled network actions
|
||||
handled_access_net: u64,
|
||||
};
|
||||
type landlock_path_beneath_attr = struct {
|
||||
allowed_access: u64,
|
||||
parent_fd: i32,
|
||||
};
|
||||
type landlock_net_port_attr = struct {
|
||||
allowed_access: u64,
|
||||
port: u64,
|
||||
};
|
||||
|
||||
// not defined in kernel. it just uses `*void` that could be any of the attrs;
|
||||
// hare requires me to explicitly enumerate them
|
||||
type landlock_rule_attr = union {
|
||||
path_beneath: landlock_path_beneath_attr,
|
||||
net_port: landlock_net_port_attr,
|
||||
};
|
||||
|
||||
|
||||
// landlock_create_ruleset syscall
|
||||
fn landlock_create_ruleset(attr: nullable *landlock_ruleset_attr, flags: u64 = 0) (rt::errno | u64) = {
|
||||
const size_: u64 = match (attr) {
|
||||
case null => yield 0;
|
||||
case => yield size(landlock_ruleset_attr);
|
||||
};
|
||||
return syscall(__NR_landlock_create_ruleset, attr: uintptr, size_, flags);
|
||||
};
|
||||
|
||||
fn landlock_add_rule(
|
||||
ruleset_fd: u64,
|
||||
rule_attr: (*landlock_path_beneath_attr | *landlock_net_port_attr),
|
||||
flags: u64 = 0,
|
||||
) (rt::errno | u64) = {
|
||||
const (rule_type, rule_attr) = match (rule_attr) {
|
||||
case let p: *landlock_path_beneath_attr => yield (LANDLOCK_RULE_PATH_BENEATH, p: uintptr);
|
||||
case let p: *landlock_net_port_attr => yield (LANDLOCK_RULE_NET_PORT, p: uintptr);
|
||||
};
|
||||
return syscall(__NR_landlock_add_rule, ruleset_fd: u64, rule_type, rule_attr: uintptr, flags);
|
||||
};
|
||||
|
||||
fn landlock_restrict_self(
|
||||
ruleset_fd: u64,
|
||||
flags: u64 = 0,
|
||||
) (rt::errno | u64) = {
|
||||
return syscall(__NR_landlock_restrict_self, ruleset_fd: u64, flags);
|
||||
};
|
||||
|
||||
|
||||
// like `rt::syscall`, but maps negative return values to `errno`
|
||||
fn syscall(num: u64, args: u64...) (rt::errno | u64) = {
|
||||
return wrap_return(rt::syscall(num, args...));
|
||||
};
|
||||
|
||||
// checks the return value from a Linux syscall and, if found to be in error,
|
||||
// returns the appropriate error. otherwise, returns the original value.
|
||||
// borrowed from non-public hare internals: rt/+linux/errno.ha
|
||||
fn wrap_return(r: u64) (rt::errno | u64) = {
|
||||
if (r > -4096: u64) {
|
||||
return (-(r: i64)): rt::errno;
|
||||
};
|
||||
return r;
|
||||
};
|
@@ -1,61 +0,0 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
use log;
|
||||
use os;
|
||||
use rt;
|
||||
|
||||
fn access_fs_roughly_read() u64 = return
|
||||
LANDLOCK_ACCESS_FS_EXECUTE |
|
||||
LANDLOCK_ACCESS_FS_READ_FILE |
|
||||
LANDLOCK_ACCESS_FS_READ_DIR
|
||||
;
|
||||
fn access_fs_roughly_write() u64 = return
|
||||
LANDLOCK_ACCESS_FS_WRITE_FILE |
|
||||
LANDLOCK_ACCESS_FS_REMOVE_DIR |
|
||||
LANDLOCK_ACCESS_FS_REMOVE_FILE |
|
||||
LANDLOCK_ACCESS_FS_MAKE_CHAR |
|
||||
LANDLOCK_ACCESS_FS_MAKE_DIR |
|
||||
LANDLOCK_ACCESS_FS_MAKE_REG |
|
||||
LANDLOCK_ACCESS_FS_MAKE_SOCK |
|
||||
LANDLOCK_ACCESS_FS_MAKE_FIFO |
|
||||
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
|
||||
LANDLOCK_ACCESS_FS_MAKE_SYM |
|
||||
LANDLOCK_ACCESS_FS_REFER |
|
||||
LANDLOCK_ACCESS_FS_TRUNCATE |
|
||||
LANDLOCK_ACCESS_FS_IOCTL_DEV
|
||||
;
|
||||
|
||||
fn access_fs_roughly_rw() u64 = return access_fs_roughly_read() | access_fs_roughly_write();
|
||||
|
||||
fn landlock_restrict() void = {
|
||||
let abi = landlock_create_ruleset(null, LANDLOCK_CREATE_RULESET_VERSION)!;
|
||||
log::printfln("found landlock version {}", abi);
|
||||
|
||||
// determine the access modes we can ask this kernel to restrict on:
|
||||
let ruleset_attr = landlock_ruleset_attr {
|
||||
handled_access_fs = access_fs_roughly_rw(),
|
||||
handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP,
|
||||
};
|
||||
if (abi == 1) {
|
||||
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
|
||||
};
|
||||
if (abi <= 2) {
|
||||
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
|
||||
};
|
||||
if (abi <= 3) {
|
||||
ruleset_attr.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP);
|
||||
};
|
||||
if (abi <= 4) {
|
||||
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
|
||||
};
|
||||
let ruleset_fd = landlock_create_ruleset(&ruleset_attr)!;
|
||||
|
||||
let root_fd = rt::open("/", rt::O_PATH | rt::O_CLOEXEC, 0)!; //< O_PATH allows for opening files which are `x` but not `r`
|
||||
landlock_add_rule(ruleset_fd, &landlock_path_beneath_attr {
|
||||
allowed_access = access_fs_roughly_rw(),
|
||||
parent_fd = root_fd,
|
||||
})!;
|
||||
|
||||
log::println("landlock_restrict: TODO: populate net access (landlock_add_rule)");
|
||||
|
||||
landlock_restrict_self(ruleset_fd)!;
|
||||
};
|
Reference in New Issue
Block a user