firejail: purge

This commit is contained in:
Colin 2024-05-25 10:21:17 +00:00
parent a5e1a804c9
commit b035d312aa
12 changed files with 31 additions and 99 deletions

View File

@ -1,7 +1,6 @@
# things to consider when changing these parameters:
# - temporary VPN access (`sane-vpn up ...`)
# - servo `ovpns` namespace (it *relies* on /etc/resolv.conf mentioning 127.0.0.53)
# - jails: `firejail --net=br-ovpnd-us --noprofile --dns=46.227.67.134 ping 1.1.1.1`
#
# components:
# - /etc/nsswitch.conf:
@ -18,9 +17,9 @@
# - modern implementations hardcodes `127.0.0.53` and then systemd-resolved proxies everything (and caches).
#
# namespacing:
# - each namespace can use a different /etc/resolv.conf to specify different DNS servers (see `firejail --dns=...`)
# - each namespace may use a different /etc/resolv.conf to specify different DNS servers
# - nscd breaks namespacing: the host nscd is unaware of the guest's /etc/resolv.conf, and so directs the guest's DNS requests to the host's servers.
# - this is fixed by either `firejail --blacklist=/var/run/nscd/socket`, or disabling nscd altogether.
# - this is fixed by either removing `/var/run/nscd/socket` from the namespace, or disabling nscd altogether.
{ config, lib, ... }:
lib.mkMerge [
{
@ -33,7 +32,7 @@ lib.mkMerge [
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
# in servo's ovnps namespace to use the provider's DNS resolvers.
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
# TODO: rework servo's netns to use `firejail`, which is capable of spoofing /etc/resolv.conf.
# TODO: improve trust-dns recursive resolver and then remove this
services.resolved.enable = true; #< to disable, set ` = lib.mkForce false`, as other systemd features default to enabling `resolved`.
# without DNSSEC:
# - dig matrix.org => works

View File

@ -39,7 +39,6 @@
./fcitx5.nix
./feedbackd.nix
./firefox.nix
./firejail.nix
./flare-signal.nix
./fontconfig.nix
./fractal.nix

View File

@ -351,7 +351,7 @@ in
# TODO: env.PASSWORD_STORE_DIR only needs to be present within the browser session.
env.PASSWORD_STORE_DIR = "/home/colin/knowledge/secrets/accounts";
# alternative to PASSWORD_STORE_DIR, but firejail doesn't handle this symlink well
# alternative to PASSWORD_STORE_DIR:
# fs.".password-store".symlink.target = lib.mkIf cfg.addons.browserpass-extension.enable "knowledge/secrets/accounts";
# flush the cache to disk to avoid it taking up too much tmp.

View File

@ -1,8 +0,0 @@
{ lib, config, ... }:
{
sane.programs.firejail = {};
programs.firejail = lib.mkIf config.sane.programs.firejail.enabled {
enable = true; #< install the suid binary
};
}

View File

@ -2,15 +2,7 @@
{ pkgs, ... }:
{
sane.programs.nicotine-plus = {
packageUnwrapped = pkgs.nicotine-plus.overrideAttrs (upstream: {
postInstall = (upstream.postInstall or "") + ''
# XXX: nixpkgs creates this symlink, seemingly just for convenience;
# third-party tools like `firejail` lack a profile for "nicotine-plus", and just for "nicotine" instead.
rm $out/bin/nicotine-plus
'';
});
sandbox.method = "firejail";
sandbox.method = "bwrap";
sandbox.whitelistWayland = true;
sandbox.net = "vpn";

View File

@ -18,7 +18,6 @@ in
sane.programs.sanebox = {
packageUnwrapped = pkgs.sanebox.override {
bubblewrap = cfg.bubblewrap.package;
firejail = cfg.firejail.package;
landlock-sandboxer = pkgs.landlock-sandboxer.override {
# not strictly necessary (landlock ABI is versioned), however when sandboxer version != kernel version,
# the sandboxer may nag about one or the other wanting to be updated.

View File

@ -165,7 +165,7 @@ in
# "monero-gui" # x86-only
# "mumble"
# "nheko" # Matrix chat client
# "nicotine-plus" # soulseek client. before re-enabling this, get it to run without firejail.
# "nicotine-plus" # soulseek client. before re-enabling this make sure it's properly sandboxed!
# "obsidian"
# "openscad" # 3d modeling
# "rhythmbox" # local music player

View File

@ -51,7 +51,7 @@ let
"/etc" #< especially for /etc/profiles/per-user/$USER/bin
"/run/current-system" #< for basics like `ls`, and all this program's `suggestedPrograms` (/run/current-system/sw/bin)
"/run/wrappers" #< SUID wrappers, in this case so that firejail can be re-entrant. TODO: remove!
"/run/wrappers" #< SUID wrappers. TODO: remove!
# /run/opengl-driver is a symlink into /nix/store; needed by e.g. mpv
"/run/opengl-driver"
"/run/opengl-driver-32" #< XXX: doesn't exist on aarch64?
@ -254,7 +254,7 @@ let
'';
};
sandbox.method = mkOption {
type = types.nullOr (types.enum [ "bwrap" "capshonly" "firejail" "landlock" ]);
type = types.nullOr (types.enum [ "bwrap" "capshonly" "pastaonly" "landlock" ]);
default = null; #< TODO: default to something non-null
description = ''
how/whether to sandbox all binaries in the package.
@ -394,10 +394,8 @@ let
description = ''
extra arguments to pass to the sandbox wrapper.
example: [
"--sanebox-firejail-arg"
"--whitelist=''${HOME}/.ssh"
"--sanebox-firejail-arg"
"--keep-dev-shm"
"--sanebox-dns"
"1.1.1.1"
]
'';
};
@ -436,7 +434,11 @@ let
;
suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [
"bubblewrap" "passt"
] ++ lib.optionals (config.sandbox.method == "firejail") [ "firejail" ];
] ++ lib.optionals (config.sandbox.method == "pastaonly") [
"passt"
] ++ lib.optionals (config.sandbox.method == "capshonly") [
"libcap_ng"
];
# 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.

View File

@ -207,7 +207,7 @@ let
# linux will drop inbound packets if it thinks a reply to that packet wouldn't exit via the same interface (rpfilter).
# wg-quick has a solution via `iptables -j CONNMARK`, and that does work for system-wide VPNs,
# but i couldn't get that to work for firejail/netns with SNAT, so set rpfilter to "loose".
# but i couldn't get that to work for netns with SNAT, so set rpfilter to "loose".
networking.firewall.checkReversePath = "loose";
# networking.firewall.extraCommands = with pkgs; ''

View File

@ -574,18 +574,18 @@ in with final; {
# });
# 2024/02/27: upstreaming is unblocked
firejail = prev.firejail.overrideAttrs (upstream: {
# firejail executes its build outputs to produce the default filter list.
# i think we *could* copy the default filters from pkgsBuildBuild, but that doesn't seem future proof
# for any (future) arch-specific filtering
postPatch = (upstream.postPatch or "") + (let
emulator = stdenv.hostPlatform.emulator buildPackages;
in lib.optionalString (!prev.stdenv.buildPlatform.canExecute prev.stdenv.hostPlatform) ''
substituteInPlace Makefile \
--replace-fail ' src/fseccomp/fseccomp' ' ${emulator} src/fseccomp/fseccomp' \
--replace-fail ' src/fsec-optimize/fsec-optimize' ' ${emulator} src/fsec-optimize/fsec-optimize'
'');
});
# firejail = prev.firejail.overrideAttrs (upstream: {
# # firejail executes its build outputs to produce the default filter list.
# # i think we *could* copy the default filters from pkgsBuildBuild, but that doesn't seem future proof
# # for any (future) arch-specific filtering
# postPatch = (upstream.postPatch or "") + (let
# emulator = stdenv.hostPlatform.emulator buildPackages;
# in lib.optionalString (!prev.stdenv.buildPlatform.canExecute prev.stdenv.hostPlatform) ''
# substituteInPlace Makefile \
# --replace-fail ' src/fseccomp/fseccomp' ' ${emulator} src/fseccomp/fseccomp' \
# --replace-fail ' src/fsec-optimize/fsec-optimize' ' ${emulator} src/fsec-optimize/fsec-optimize'
# '');
# });
# flare-signal = prev.flare-signal.override {
# # fixes "cargo:warning=aarch64-unknown-linux-gnu-gcc: error: unrecognized command-line option -m64"

View File

@ -2,7 +2,6 @@
, bash
, bubblewrap
, passt
, firejail
, landlock-sandboxer
, libcap
, substituteAll
@ -23,7 +22,6 @@ stdenv.mkDerivation {
runHook preBuild
substitute $src sanebox \
--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 '@pasta@' '${lib.getExe' passt "pasta"}'
@ -42,7 +40,7 @@ stdenv.mkDerivation {
description = ''
helper program to run some other program in a sandbox.
factoring this out allows:
1. to abstract over the particular sandbox implementation (bwrap, firejail, ...).
1. to abstract over the particular sandbox implementation (bwrap, landlock, ...).
2. to modify sandbox settings without forcing a rebuild of the sandboxed package.
'';
mainProgram = "sanebox";

View File

@ -2,7 +2,6 @@
## BUILD-TIME SUBSTITUTIONS
### <bin>_FALLBACK: if `<bin>` isn't on PATH, then use this instead
FIREJAIL_FALLBACK='@firejail@'
BWRAP_FALLBACK='@bwrap@'
LANDLOCK_SANDBOXER_FALLBACK='@landlockSandboxer@'
CAPSH_FALLBACK='@capsh@'
@ -59,7 +58,6 @@ cliArgs=()
# - "landlock"
# - "capshonly"
# - "pastaonly"
# - "firejail"
# - "none"
method=
# autodetect: set non-empty to add any path-like entities intended for the binary's CLI, into its sandbox.
@ -86,13 +84,12 @@ keepNamespace=()
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 (not supported by all backends)
dns=()
# list of `VAR=VALUE` environment variables to add to the sandboxed program's environment
portalEnv=()
# arguments to forward onto a specific backend (if that backend is active)
firejailFlags=()
bwrapFlags=()
usage() {
@ -113,7 +110,7 @@ usage() {
echo ' invoke the program directly, instead of inside a sandbox'
echo ' --sanebox-dry-run'
echo ' show what would be `exec`uted but do not perform any action'
echo ' --sanebox-method <bwrap|capshonly|pastaonly|firejail|landlock|none>'
echo ' --sanebox-method <bwrap|capshonly|pastaonly|landlock|none>'
echo ' use a specific sandboxer'
echo ' --sanebox-autodetect <existing|existingFile|existingFileOrParent|existingOrParent|parent>'
echo ' add files which appear later as CLI arguments into the sandbox'
@ -123,7 +120,6 @@ usage() {
echo ' set environment variables so that the sandboxed program will attempt to use xdg-desktop-portal for operations like opening files'
echo ' --sanebox-no-portal'
echo ' undo a previous `--sanebox-portal` arg'
echo ' --sanebox-firejail-arg <arg>'
echo ' --sanebox-bwrap-arg <arg>'
echo ' --sanebox-net-dev <iface>'
echo ' --sanebox-net-gateway <ip-address>'
@ -508,11 +504,6 @@ parseArgs() {
# override a previous --sanebox-portal call
portalEnv=()
;;
(--sanebox-firejail-arg)
local fjFlag=$1
shift
firejailFlags+=("$fjFlag")
;;
(--sanebox-bwrap-arg)
local bwrapFlag=$1
shift
@ -568,45 +559,6 @@ parseArgs() {
}
## FIREJAIL BACKEND
firejailSetup() {
debug "firejailSetup: noop"
}
firejailIngestPath() {
# XXX: firejail flat-out refuses to whitelist certain root paths
# this exception list is non-exhaustive
case $1 in
(/bin | /etc) ;;
(*)
firejailFlags+=("--noblacklist=$1" "--whitelist=$1")
;;
esac
}
firejailIngestNetDev() {
# XXX: to use a VPN tunnel named `vpn-xyz`, we keep around and link it to a bridge `br-vpn-xyz` externally.
# 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")
}
firejailIngestKeepNamespace() {
debug "firejailIngestKeepNamespace: noop"
}
firejailGetCli() {
locate _firejail "firejail" "$FIREJAIL_FALLBACK"
cliArgs=(
"$_firejail" "${firejailFlags[@]}" --
env "${portalEnv[@]}" "${cliArgs[@]}"
)
}
## BUBBLEWRAP BACKEND
bwrapUnshareCgroup=(--unshare-cgroup)
@ -952,7 +904,6 @@ maybeAutodetectPaths() {
### path sorting: if the app has access both to /FOO and /FOO/BAR, some backends get confused.
# notably bwrap, --bind /FOO /FOO followed by --bind /FOO/BAR /FOO/BAR results in /FOO being accessible but /FOO/BAR *not*.
# so reduce the paths to the minimal set which includes those requested.
# for more sophisticated (i.e. complex) backends like firejail, this may break subpaths which were blacklisted earlier.
canonicalizePaths() {
# remove '//' and simplify '.', '..' paths, into canonical absolute logical paths.
local canonPaths=()