sanebox: integrate with pasta
(passt) for better net sandboxing
This commit is contained in:
parent
118ed5f950
commit
7b1bc210fd
|
@ -723,6 +723,8 @@ in
|
|||
# settings (electron app)
|
||||
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
|
||||
|
||||
passt.sandbox.enable = false; #< sandbox helper (netns specifically)
|
||||
|
||||
parted.sandbox.method = "landlock";
|
||||
parted.sandbox.extraPaths = [
|
||||
"/dev"
|
||||
|
|
|
@ -74,6 +74,10 @@ let
|
|||
vpn.name
|
||||
else
|
||||
sandbox.net;
|
||||
netGateway = if sandbox.net == "vpn" then
|
||||
vpn.addrV4
|
||||
else
|
||||
null;
|
||||
dns = if sandbox.net == "vpn" then
|
||||
vpn.dns
|
||||
else
|
||||
|
@ -430,8 +434,9 @@ let
|
|||
else
|
||||
wrapPkg name config config.packageUnwrapped
|
||||
;
|
||||
suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [ "bubblewrap" ]
|
||||
++ lib.optionals (config.sandbox.method == "firejail") [ "firejail" ];
|
||||
suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [
|
||||
"bubblewrap" "passt"
|
||||
] ++ lib.optionals (config.sandbox.method == "firejail") [ "firejail" ];
|
||||
# declare a fs dependency for each secret, but don't specify how to populate it yet.
|
||||
# can't populate it here because it varies per-user.
|
||||
# this gets the symlink into the sandbox, but not the actual secret.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
, capabilities ? []
|
||||
, dns ? null
|
||||
, netDev ? null
|
||||
, netGateway ? null
|
||||
, whitelistPwd ? false
|
||||
, extraConfig ? []
|
||||
}:
|
||||
|
@ -22,6 +23,9 @@ let
|
|||
netItems = lib.optionals (netDev != null) [
|
||||
"--sanebox-net-dev"
|
||||
netDev
|
||||
] ++ lib.optionals (netGateway != null) [
|
||||
"--sanebox-net-gateway"
|
||||
netGateway
|
||||
] ++ lib.optionals (dns != null) (
|
||||
lib.flatten (builtins.map
|
||||
(addr: [ "--sanebox-dns" addr ])
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{ lib, stdenv
|
||||
, bash
|
||||
, bubblewrap
|
||||
, passt
|
||||
, firejail
|
||||
, landlock-sandboxer
|
||||
, libcap
|
||||
|
@ -24,7 +25,8 @@ stdenv.mkDerivation {
|
|||
--replace-fail '@bwrap@' '${lib.getExe bubblewrap}' \
|
||||
--replace-fail '@firejail@' '${lib.getExe' firejail "firejail"}' \
|
||||
--replace-fail '@landlockSandboxer@' '${lib.getExe landlock-sandboxer}' \
|
||||
--replace-fail '@capsh@' '${lib.getExe' libcap "capsh"}'
|
||||
--replace-fail '@capsh@' '${lib.getExe' libcap "capsh"}' \
|
||||
--replace-fail '@pasta@' '${lib.getExe' passt "pasta"}'
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ FIREJAIL_FALLBACK='@firejail@'
|
|||
BWRAP_FALLBACK='@bwrap@'
|
||||
LANDLOCK_SANDBOXER_FALLBACK='@landlockSandboxer@'
|
||||
CAPSH_FALLBACK='@capsh@'
|
||||
PASTA_FALLBACK='@pasta@'
|
||||
|
||||
|
||||
## EARLY DEBUG HOOKS
|
||||
|
@ -80,7 +81,10 @@ capabilities=()
|
|||
# - "all": as if all the above were specified
|
||||
keepNamespace=()
|
||||
# name of some network device to make available to the sandbox, if any.
|
||||
# or "all" to keep all devices available
|
||||
netDev=
|
||||
# IPv4 address of the default gateway associated with the bridged network device (usually that's just the VPN's IP addr)
|
||||
netGateway=
|
||||
# list of IP addresses to use for DNS servers inside the sandbox (firejail only)
|
||||
dns=()
|
||||
# list of `VAR=VALUE` environment variables to add to the sandboxed program's environment
|
||||
|
@ -121,6 +125,7 @@ usage() {
|
|||
echo ' --sanebox-firejail-arg <arg>'
|
||||
echo ' --sanebox-bwrap-arg <arg>'
|
||||
echo ' --sanebox-net-dev <iface>'
|
||||
echo ' --sanebox-net-gateway <ip-address>'
|
||||
echo ' --sanebox-dns <server>'
|
||||
echo ' --sanebox-keep-namespace <cgroup|ipc|pid|uts|all>'
|
||||
echo ' do not unshare the provided linux namespace'
|
||||
|
@ -516,10 +521,14 @@ parseArgs() {
|
|||
netDev=$1
|
||||
shift
|
||||
;;
|
||||
(--sanebox-dns)
|
||||
local dns=$1
|
||||
(--sanebox-net-gateway)
|
||||
netGateway=$1
|
||||
shift
|
||||
dns+=("$dns")
|
||||
;;
|
||||
(--sanebox-dns)
|
||||
local dnsServer=$1
|
||||
shift
|
||||
dns+=("$dnsServer")
|
||||
;;
|
||||
(--sanebox-keep-namespace)
|
||||
local namespace=$1
|
||||
|
@ -578,6 +587,9 @@ firejailIngestNetDev() {
|
|||
# firejail can then spawn a veth from this bridge and namespace it that way.
|
||||
firejailFlags+=("--net=br-$1")
|
||||
}
|
||||
firejailIngestNetGateway() {
|
||||
debug "firejailIngestNetGateway: noop"
|
||||
}
|
||||
firejailIngestDns() {
|
||||
firejailFlags+=("--dns=$1")
|
||||
}
|
||||
|
@ -604,6 +616,9 @@ bwrapUnshareUts=(--unshare-uts)
|
|||
bwrapVirtualizeDev=(--dev /dev)
|
||||
bwrapVirtualizeProc=(--proc /proc)
|
||||
bwrapVirtualizeTmp=(--tmpfs /tmp)
|
||||
# args to invoke `pasta` (user-mode network stack) with
|
||||
bwrapPastaArgs=()
|
||||
bwrapNetSetup=
|
||||
|
||||
bwrapSetup() {
|
||||
debug "bwrapSetup: noop"
|
||||
|
@ -652,8 +667,22 @@ bwrapIngestPath() {
|
|||
esac
|
||||
}
|
||||
bwrapIngestNetDev() {
|
||||
debug "bwrapIngestNetDev: enabling full net access for '$1' because don't know how to restrict it more narrowly"
|
||||
local dev=$1
|
||||
bwrapUnshareNet=()
|
||||
case $dev in
|
||||
(all)
|
||||
;;
|
||||
(*)
|
||||
bwrapPastaArgs+=(--outbound-if4 "$dev")
|
||||
;;
|
||||
esac
|
||||
}
|
||||
bwrapIngestNetGateway() {
|
||||
bwrapPastaArgs+=(--gateway "$1")
|
||||
}
|
||||
bwrapIngestDns() {
|
||||
# NAT DNS requests to localhost to the VPN's DNS resolver
|
||||
bwrapNetSetup="ip addr del 127.0.0.1/8 dev lo; iptables -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.1 -j DNAT --to-destination $1:53; $bwrapNetSetup"
|
||||
}
|
||||
bwrapIngestKeepNamespace() {
|
||||
case $1 in
|
||||
|
@ -693,6 +722,21 @@ bwrapGetCli() {
|
|||
"${bwrapFlags[@]}" --
|
||||
env "${portalEnv[@]}" "${cliArgs[@]}"
|
||||
)
|
||||
if [ ${#bwrapPastaArgs} -ne 0 ]; then
|
||||
# if [ -n "$bwrapNetSetup" ]; then
|
||||
cliArgs=(
|
||||
"/bin/sh" "-c"
|
||||
"$bwrapNetSetup exec"' "$0" "$@"'
|
||||
"${cliArgs[@]}"
|
||||
)
|
||||
# fi
|
||||
locate _pasta "pasta" "$PASTA_FALLBACK"
|
||||
cliArgs=(
|
||||
"$_pasta" --ipv4-only -U none -T none --config-net
|
||||
"${bwrapPastaArgs[@]}" --
|
||||
"${cliArgs[@]}"
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
@ -741,6 +785,12 @@ landlockIngestPath() {
|
|||
landlockIngestNetDev() {
|
||||
debug "landlockIngestNetDev: '$1': stubbed (landlock network is always unrestricted)"
|
||||
}
|
||||
landlockIngestNetGateway() {
|
||||
debug "landlockIngestNetGateway: noop"
|
||||
}
|
||||
landlockIngestDns() {
|
||||
debug "landlockIngestDns: noop"
|
||||
}
|
||||
landlockIngestKeepNamespace() {
|
||||
debug "landlockIngestKeepNamespace: noop"
|
||||
}
|
||||
|
@ -776,6 +826,12 @@ capshonlyIngestPath() {
|
|||
capshonlyIngestNetDev() {
|
||||
debug "capshonlyIngestNetDev: '$1': stubbed (capsh network is always unrestricted)"
|
||||
}
|
||||
capshonlyIngestNetGateway() {
|
||||
debug "capshonlyIngestNetGateway: '$1': stubbed (capsh network is always unrestricted)"
|
||||
}
|
||||
capshonlyIngestDns() {
|
||||
debug "capshonlyIngestDns: '$1': stubbed (capsh network is always unrestricted)"
|
||||
}
|
||||
capshonlyIngestKeepNamespace() {
|
||||
debug "capshonlyIngestKeepNamespace: noop"
|
||||
}
|
||||
|
@ -947,6 +1003,10 @@ ingestForBackend() {
|
|||
"$method"IngestNetDev "$netDev"
|
||||
fi
|
||||
|
||||
if [ -n "$netGateway" ]; then
|
||||
"$method"IngestNetGateway "$netGateway"
|
||||
fi
|
||||
|
||||
for addr in "${dns[@]}"; do
|
||||
"$method"IngestDns "$addr"
|
||||
done
|
||||
|
|
Loading…
Reference in New Issue
Block a user