sanebox: integrate with pasta
(passt) for better net sandboxing
This commit is contained in:
@@ -723,6 +723,8 @@ in
|
|||||||
# settings (electron app)
|
# settings (electron app)
|
||||||
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
|
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
|
||||||
|
|
||||||
|
passt.sandbox.enable = false; #< sandbox helper (netns specifically)
|
||||||
|
|
||||||
parted.sandbox.method = "landlock";
|
parted.sandbox.method = "landlock";
|
||||||
parted.sandbox.extraPaths = [
|
parted.sandbox.extraPaths = [
|
||||||
"/dev"
|
"/dev"
|
||||||
|
@@ -74,6 +74,10 @@ let
|
|||||||
vpn.name
|
vpn.name
|
||||||
else
|
else
|
||||||
sandbox.net;
|
sandbox.net;
|
||||||
|
netGateway = if sandbox.net == "vpn" then
|
||||||
|
vpn.addrV4
|
||||||
|
else
|
||||||
|
null;
|
||||||
dns = if sandbox.net == "vpn" then
|
dns = if sandbox.net == "vpn" then
|
||||||
vpn.dns
|
vpn.dns
|
||||||
else
|
else
|
||||||
@@ -429,9 +433,10 @@ let
|
|||||||
null
|
null
|
||||||
else
|
else
|
||||||
wrapPkg name config config.packageUnwrapped
|
wrapPkg name config config.packageUnwrapped
|
||||||
;
|
;
|
||||||
suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [ "bubblewrap" ]
|
suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [
|
||||||
++ lib.optionals (config.sandbox.method == "firejail") [ "firejail" ];
|
"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.
|
# 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.
|
# can't populate it here because it varies per-user.
|
||||||
# this gets the symlink into the sandbox, but not the actual secret.
|
# this gets the symlink into the sandbox, but not the actual secret.
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
, capabilities ? []
|
, capabilities ? []
|
||||||
, dns ? null
|
, dns ? null
|
||||||
, netDev ? null
|
, netDev ? null
|
||||||
|
, netGateway ? null
|
||||||
, whitelistPwd ? false
|
, whitelistPwd ? false
|
||||||
, extraConfig ? []
|
, extraConfig ? []
|
||||||
}:
|
}:
|
||||||
@@ -22,6 +23,9 @@ let
|
|||||||
netItems = lib.optionals (netDev != null) [
|
netItems = lib.optionals (netDev != null) [
|
||||||
"--sanebox-net-dev"
|
"--sanebox-net-dev"
|
||||||
netDev
|
netDev
|
||||||
|
] ++ lib.optionals (netGateway != null) [
|
||||||
|
"--sanebox-net-gateway"
|
||||||
|
netGateway
|
||||||
] ++ lib.optionals (dns != null) (
|
] ++ lib.optionals (dns != null) (
|
||||||
lib.flatten (builtins.map
|
lib.flatten (builtins.map
|
||||||
(addr: [ "--sanebox-dns" addr ])
|
(addr: [ "--sanebox-dns" addr ])
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
{ lib, stdenv
|
{ lib, stdenv
|
||||||
, bash
|
, bash
|
||||||
, bubblewrap
|
, bubblewrap
|
||||||
|
, passt
|
||||||
, firejail
|
, firejail
|
||||||
, landlock-sandboxer
|
, landlock-sandboxer
|
||||||
, libcap
|
, libcap
|
||||||
@@ -24,7 +25,8 @@ stdenv.mkDerivation {
|
|||||||
--replace-fail '@bwrap@' '${lib.getExe bubblewrap}' \
|
--replace-fail '@bwrap@' '${lib.getExe bubblewrap}' \
|
||||||
--replace-fail '@firejail@' '${lib.getExe' firejail "firejail"}' \
|
--replace-fail '@firejail@' '${lib.getExe' firejail "firejail"}' \
|
||||||
--replace-fail '@landlockSandboxer@' '${lib.getExe landlock-sandboxer}' \
|
--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
|
runHook postBuild
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ FIREJAIL_FALLBACK='@firejail@'
|
|||||||
BWRAP_FALLBACK='@bwrap@'
|
BWRAP_FALLBACK='@bwrap@'
|
||||||
LANDLOCK_SANDBOXER_FALLBACK='@landlockSandboxer@'
|
LANDLOCK_SANDBOXER_FALLBACK='@landlockSandboxer@'
|
||||||
CAPSH_FALLBACK='@capsh@'
|
CAPSH_FALLBACK='@capsh@'
|
||||||
|
PASTA_FALLBACK='@pasta@'
|
||||||
|
|
||||||
|
|
||||||
## EARLY DEBUG HOOKS
|
## EARLY DEBUG HOOKS
|
||||||
@@ -80,7 +81,10 @@ capabilities=()
|
|||||||
# - "all": as if all the above were specified
|
# - "all": as if all the above were specified
|
||||||
keepNamespace=()
|
keepNamespace=()
|
||||||
# name of some network device to make available to the sandbox, if any.
|
# name of some network device to make available to the sandbox, if any.
|
||||||
|
# or "all" to keep all devices available
|
||||||
netDev=
|
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)
|
# list of IP addresses to use for DNS servers inside the sandbox (firejail only)
|
||||||
dns=()
|
dns=()
|
||||||
# list of `VAR=VALUE` environment variables to add to the sandboxed program's environment
|
# 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-firejail-arg <arg>'
|
||||||
echo ' --sanebox-bwrap-arg <arg>'
|
echo ' --sanebox-bwrap-arg <arg>'
|
||||||
echo ' --sanebox-net-dev <iface>'
|
echo ' --sanebox-net-dev <iface>'
|
||||||
|
echo ' --sanebox-net-gateway <ip-address>'
|
||||||
echo ' --sanebox-dns <server>'
|
echo ' --sanebox-dns <server>'
|
||||||
echo ' --sanebox-keep-namespace <cgroup|ipc|pid|uts|all>'
|
echo ' --sanebox-keep-namespace <cgroup|ipc|pid|uts|all>'
|
||||||
echo ' do not unshare the provided linux namespace'
|
echo ' do not unshare the provided linux namespace'
|
||||||
@@ -516,10 +521,14 @@ parseArgs() {
|
|||||||
netDev=$1
|
netDev=$1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
(--sanebox-dns)
|
(--sanebox-net-gateway)
|
||||||
local dns=$1
|
netGateway=$1
|
||||||
shift
|
shift
|
||||||
dns+=("$dns")
|
;;
|
||||||
|
(--sanebox-dns)
|
||||||
|
local dnsServer=$1
|
||||||
|
shift
|
||||||
|
dns+=("$dnsServer")
|
||||||
;;
|
;;
|
||||||
(--sanebox-keep-namespace)
|
(--sanebox-keep-namespace)
|
||||||
local namespace=$1
|
local namespace=$1
|
||||||
@@ -578,6 +587,9 @@ firejailIngestNetDev() {
|
|||||||
# firejail can then spawn a veth from this bridge and namespace it that way.
|
# firejail can then spawn a veth from this bridge and namespace it that way.
|
||||||
firejailFlags+=("--net=br-$1")
|
firejailFlags+=("--net=br-$1")
|
||||||
}
|
}
|
||||||
|
firejailIngestNetGateway() {
|
||||||
|
debug "firejailIngestNetGateway: noop"
|
||||||
|
}
|
||||||
firejailIngestDns() {
|
firejailIngestDns() {
|
||||||
firejailFlags+=("--dns=$1")
|
firejailFlags+=("--dns=$1")
|
||||||
}
|
}
|
||||||
@@ -604,6 +616,9 @@ bwrapUnshareUts=(--unshare-uts)
|
|||||||
bwrapVirtualizeDev=(--dev /dev)
|
bwrapVirtualizeDev=(--dev /dev)
|
||||||
bwrapVirtualizeProc=(--proc /proc)
|
bwrapVirtualizeProc=(--proc /proc)
|
||||||
bwrapVirtualizeTmp=(--tmpfs /tmp)
|
bwrapVirtualizeTmp=(--tmpfs /tmp)
|
||||||
|
# args to invoke `pasta` (user-mode network stack) with
|
||||||
|
bwrapPastaArgs=()
|
||||||
|
bwrapNetSetup=
|
||||||
|
|
||||||
bwrapSetup() {
|
bwrapSetup() {
|
||||||
debug "bwrapSetup: noop"
|
debug "bwrapSetup: noop"
|
||||||
@@ -652,8 +667,22 @@ bwrapIngestPath() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
bwrapIngestNetDev() {
|
bwrapIngestNetDev() {
|
||||||
debug "bwrapIngestNetDev: enabling full net access for '$1' because don't know how to restrict it more narrowly"
|
local dev=$1
|
||||||
bwrapUnshareNet=()
|
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() {
|
bwrapIngestKeepNamespace() {
|
||||||
case $1 in
|
case $1 in
|
||||||
@@ -693,6 +722,21 @@ bwrapGetCli() {
|
|||||||
"${bwrapFlags[@]}" --
|
"${bwrapFlags[@]}" --
|
||||||
env "${portalEnv[@]}" "${cliArgs[@]}"
|
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() {
|
landlockIngestNetDev() {
|
||||||
debug "landlockIngestNetDev: '$1': stubbed (landlock network is always unrestricted)"
|
debug "landlockIngestNetDev: '$1': stubbed (landlock network is always unrestricted)"
|
||||||
}
|
}
|
||||||
|
landlockIngestNetGateway() {
|
||||||
|
debug "landlockIngestNetGateway: noop"
|
||||||
|
}
|
||||||
|
landlockIngestDns() {
|
||||||
|
debug "landlockIngestDns: noop"
|
||||||
|
}
|
||||||
landlockIngestKeepNamespace() {
|
landlockIngestKeepNamespace() {
|
||||||
debug "landlockIngestKeepNamespace: noop"
|
debug "landlockIngestKeepNamespace: noop"
|
||||||
}
|
}
|
||||||
@@ -776,6 +826,12 @@ capshonlyIngestPath() {
|
|||||||
capshonlyIngestNetDev() {
|
capshonlyIngestNetDev() {
|
||||||
debug "capshonlyIngestNetDev: '$1': stubbed (capsh network is always unrestricted)"
|
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() {
|
capshonlyIngestKeepNamespace() {
|
||||||
debug "capshonlyIngestKeepNamespace: noop"
|
debug "capshonlyIngestKeepNamespace: noop"
|
||||||
}
|
}
|
||||||
@@ -944,7 +1000,11 @@ ingestForBackend() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ -n "$netDev" ]; then
|
if [ -n "$netDev" ]; then
|
||||||
"$method"IngestNetDev"$netDev"
|
"$method"IngestNetDev "$netDev"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$netGateway" ]; then
|
||||||
|
"$method"IngestNetGateway "$netGateway"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for addr in "${dns[@]}"; do
|
for addr in "${dns[@]}"; do
|
||||||
|
Reference in New Issue
Block a user