mpv: sandbox with firejail
This commit is contained in:
parent
f8440e3811
commit
0f3f0933b1
|
@ -114,6 +114,7 @@ let
|
||||||
${pkgs.buildPackages.gnused}/bin/sed -i s'/devtools-commandkey-inspector = C/devtools-commandkey-inspector = VK_F12/' omni/localization/en-US/devtools/startup/key-shortcuts.ftl
|
${pkgs.buildPackages.gnused}/bin/sed -i s'/devtools-commandkey-inspector = C/devtools-commandkey-inspector = VK_F12/' omni/localization/en-US/devtools/startup/key-shortcuts.ftl
|
||||||
pushd omni; ${pkgs.buildPackages.zip}/bin/zip $out/lib/${cfg.browser.libName}/browser/omni.ja -r ./*; popd
|
pushd omni; ${pkgs.buildPackages.zip}/bin/zip $out/lib/${cfg.browser.libName}/browser/omni.ja -r ./*; popd
|
||||||
|
|
||||||
|
# runHook postFixup to allow sandbox wrappers to wrap the binaries
|
||||||
runHook postFixup
|
runHook postFixup
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,7 +20,7 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
packageUnwrapped = pkgs.wrapMpv pkgs.mpv-unwrapped {
|
packageUnwrapped = (pkgs.wrapMpv pkgs.mpv-unwrapped {
|
||||||
scripts = with pkgs.mpvScripts; [
|
scripts = with pkgs.mpvScripts; [
|
||||||
mpris
|
mpris
|
||||||
uosc
|
uosc
|
||||||
|
@ -55,7 +55,17 @@ in
|
||||||
# W wlshm Wayland SHM video output (software scaling)
|
# W wlshm Wayland SHM video output (software scaling)
|
||||||
"--add-flags" "--vo=${cfg.config.vo}"
|
"--add-flags" "--vo=${cfg.config.vo}"
|
||||||
];
|
];
|
||||||
};
|
}).overrideAttrs (base: {
|
||||||
|
buildCommand = base.buildCommand + ''
|
||||||
|
# runHook postFixup to allow sandbox wrappers to wrap the binaries
|
||||||
|
runHook postFixup
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
sandbox.method = "firejail";
|
||||||
|
sandbox.binMap."mpv_identify.sh" = "mpv";
|
||||||
|
sandbox.binMap."umpv" = "mpv";
|
||||||
|
|
||||||
persist.byStore.plaintext = [ ".local/state/mpv/watch_later" ];
|
persist.byStore.plaintext = [ ".local/state/mpv/watch_later" ];
|
||||||
fs.".config/mpv/input.conf".symlink.text = let
|
fs.".config/mpv/input.conf".symlink.text = let
|
||||||
execInTerm = "${pkgs.xdg-terminal-exec}/bin/xdg-terminal-exec";
|
execInTerm = "${pkgs.xdg-terminal-exec}/bin/xdg-terminal-exec";
|
||||||
|
|
|
@ -33,34 +33,43 @@ let
|
||||||
defaultEnables = solveDefaultEnableFor cfg;
|
defaultEnables = solveDefaultEnableFor cfg;
|
||||||
|
|
||||||
# wrap a package so that its binaries (maybe) run in a sandbox
|
# wrap a package so that its binaries (maybe) run in a sandbox
|
||||||
wrapPkg = { sandbox, fs, net, ... }: package: (
|
wrapPkg = { fs, net, persist, sandbox, ... }: package: (
|
||||||
if sandbox.method == null then
|
if sandbox.method == null then
|
||||||
package
|
package
|
||||||
else if sandbox.method == "firejail" then
|
else if sandbox.method == "firejail" then
|
||||||
let
|
let
|
||||||
# XXX: firejail needs suid bit for some (not all) of its sandboxing methods. hence, rely on the user installing it system-wide and call it by suid path.
|
# XXX: firejail needs suid bit for some (not all) of its sandboxing methods. hence, rely on the user installing it system-wide and call it by suid path.
|
||||||
firejailBin = "/run/wrappers/bin/firejail";
|
firejailBin = "/run/wrappers/bin/firejail";
|
||||||
vpn = lib.findSingle (v: v.default) null null (builtins.attrValues config.sane.vpn);
|
|
||||||
vpnFlags = [
|
|
||||||
"--net=${vpn.bridgeDevice}"
|
|
||||||
] ++ (builtins.map (addr: "--dns=${addr}") vpn.dns);
|
|
||||||
allowPath = p: [
|
allowPath = p: [
|
||||||
"--noblacklist=${p}"
|
"--noblacklist=${p}"
|
||||||
"--whitelist=${p}"
|
"--whitelist=${p}"
|
||||||
];
|
];
|
||||||
fsFlags = lib.flatten (builtins.map
|
allowHomePath = p: allowPath ''''${HOME}/${p}'';
|
||||||
(p: allowPath ''''${HOME}/${p}'')
|
allowPaths = paths: lib.flatten (builtins.map allowPath paths);
|
||||||
(builtins.attrNames fs)
|
allowHomePaths = paths: lib.flatten (builtins.map allowHomePath paths);
|
||||||
);
|
|
||||||
|
fsFlags = allowHomePaths (builtins.attrNames fs);
|
||||||
|
persistFlags = allowHomePaths (builtins.attrNames persist.byPath);
|
||||||
|
|
||||||
|
vpn = lib.findSingle (v: v.default) null null (builtins.attrValues config.sane.vpn);
|
||||||
|
vpnFlags = [
|
||||||
|
"--net=${vpn.bridgeDevice}"
|
||||||
|
] ++ (builtins.map (addr: "--dns=${addr}") vpn.dns);
|
||||||
|
|
||||||
firejailFlags = [
|
firejailFlags = [
|
||||||
# "--quiet" #< TODO: enable
|
# "--quiet" #< TODO: enable
|
||||||
# "--tracelog" # logs blacklist violations to syslog (but default firejail disallows this)
|
# "--tracelog" # logs blacklist violations to syslog (but default firejail disallows this)
|
||||||
] ++ allowPath "/run/current-system" #< for basics like `ls`, and all this program's `suggestedPrograms`
|
] ++ allowPath "/run/current-system" #< for basics like `ls`, and all this program's `suggestedPrograms`
|
||||||
|
# ++ allowPath "/bin/sh" #< to allow `firejail --join=...` (doesn't work)
|
||||||
|
++ allowPath "/run/systemd/resolve" #< to allow reading /etc/resolv.conf, which ultimately symlinks here
|
||||||
|
++ allowPaths [ "/run/opengl-driver" "/run/opengl-driver-32" ] #< symlinks to /nix/store; needed by e.g. mpv
|
||||||
++ fsFlags
|
++ fsFlags
|
||||||
|
++ persistFlags
|
||||||
++ lib.optionals (net == "vpn") vpnFlags;
|
++ lib.optionals (net == "vpn") vpnFlags;
|
||||||
|
|
||||||
firejailBase = pkgs.writeShellScript
|
firejailBase = pkgs.writeShellScript
|
||||||
"firejail-${package.pname}-base"
|
"firejail-${package.pname or package.name or "unknown"}-base"
|
||||||
''exec ${firejailBin} ${lib.escapeShellArgs firejailFlags} \'';
|
''exec ${firejailBin} ${lib.escapeShellArgs firejailFlags} \'';
|
||||||
|
|
||||||
# two ways i could wrap a package in a sandbox:
|
# two ways i could wrap a package in a sandbox:
|
||||||
|
@ -75,22 +84,47 @@ let
|
||||||
# ultimately, no.1 is probably more reliable, but i expect i'll factor out a switch to allow either approach -- particularly when debugging package buld failures.
|
# ultimately, no.1 is probably more reliable, but i expect i'll factor out a switch to allow either approach -- particularly when debugging package buld failures.
|
||||||
packageWrapped = package.overrideAttrs (unwrapped: {
|
packageWrapped = package.overrideAttrs (unwrapped: {
|
||||||
postFixup = (unwrapped.postFixup or "") + ''
|
postFixup = (unwrapped.postFixup or "") + ''
|
||||||
getFirejailProfile() {
|
tryFirejailProfile() {
|
||||||
_maybeProfile="${pkgs.firejail}/etc/firejail/$1.profile"
|
_maybeProfile="${pkgs.firejail}/etc/firejail/$1.profile"
|
||||||
|
echo "checking for firejail profile at: $_maybeProfile"
|
||||||
if [ -e "$_maybeProfile" ]; then
|
if [ -e "$_maybeProfile" ]; then
|
||||||
firejailProfileFlags="--profile=$_maybeProfile"
|
firejailProfilePath="$_maybeProfile"
|
||||||
|
firejailProfileName="$1"
|
||||||
|
true
|
||||||
else
|
else
|
||||||
firejailProfileFlags=
|
false
|
||||||
echo "failed to locate firejail profile for $1 (expected $_maybeProfile): aborting!" && false
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
tryFirejailProfileFromBinMap() {
|
||||||
|
case "$1" in
|
||||||
|
${builtins.concatStringsSep "\n" (lib.mapAttrsToList
|
||||||
|
(bin: profile: ''
|
||||||
|
(${bin})
|
||||||
|
tryFirejailProfile "${profile}"
|
||||||
|
;;
|
||||||
|
'')
|
||||||
|
sandbox.binMap
|
||||||
|
)}
|
||||||
|
(*)
|
||||||
|
echo "no special-case profile for $1"
|
||||||
|
false
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
getFirejailProfile() {
|
||||||
|
tryFirejailProfileFromBinMap "$1" \
|
||||||
|
|| tryFirejailProfile "$1" \
|
||||||
|
|| tryFirejailProfile "${unwrapped.pname or ""}" \
|
||||||
|
|| tryFirejailProfile "${unwrapped.name or ""}" \
|
||||||
|
|| (echo "failed to locate firejail profile for $1: aborting!" && false)
|
||||||
|
}
|
||||||
firejailWrap() {
|
firejailWrap() {
|
||||||
name="$1"
|
name="$1"
|
||||||
getFirejailProfile "$name"
|
getFirejailProfile "$name"
|
||||||
mv "$out/bin/$name" "$out/bin/.$name-firejailed"
|
mv "$out/bin/$name" "$out/bin/.$name-firejailed"
|
||||||
cat <<EOF >> "tmp-firejail-$name"
|
cat <<EOF >> "tmp-firejail-$name"
|
||||||
$firejailProfileFlags \
|
--profile="$firejailProfilePath" \
|
||||||
--join-or-start="${package.name}-$name" \
|
--join-or-start="$firejailProfileName" \
|
||||||
-- "$out/bin/.$name-firejailed" "\$@"
|
-- "$out/bin/.$name-firejailed" "\$@"
|
||||||
EOF
|
EOF
|
||||||
cat ${firejailBase} "tmp-firejail-$name" > "$out/bin/$name"
|
cat ${firejailBase} "tmp-firejail-$name" > "$out/bin/$name"
|
||||||
|
@ -110,7 +144,7 @@ let
|
||||||
priority = ((unwrapped.meta or {}).priority or 0) - 1;
|
priority = ((unwrapped.meta or {}).priority or 0) - 1;
|
||||||
};
|
};
|
||||||
passthru = (unwrapped.passthru or {}) // {
|
passthru = (unwrapped.passthru or {}) // {
|
||||||
checkSandboxed = pkgs.runCommand "${package.name}-check-sandboxed" {} ''
|
checkSandboxed = pkgs.runCommand "${unwrapped.name or unwrapped.pname or "unknown"}-check-sandboxed" {} ''
|
||||||
# this pseudo-package gets "built" as part of toplevel system build.
|
# this pseudo-package gets "built" as part of toplevel system build.
|
||||||
# if the build is failing here, that means the program isn't properly sandboxed:
|
# if the build is failing here, that means the program isn't properly sandboxed:
|
||||||
# make sure that "postFixup" gets called as part of the package's build script
|
# make sure that "postFixup" gets called as part of the package's build script
|
||||||
|
@ -277,6 +311,16 @@ let
|
||||||
how/whether to sandbox all binaries in the package.
|
how/whether to sandbox all binaries in the package.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
sandbox.binMap = mkOption {
|
||||||
|
type = types.attrsOf types.str;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
map binName -> sandboxAs.
|
||||||
|
for example,
|
||||||
|
if the package ships `bin/mpv` and `bin/umpv`, this module might know how to sandbox `mpv` but not `umpv`.
|
||||||
|
then set `sandbox.binMap.umpv = "mpv";` to sandbox `bin/umpv` with the same rules as `bin/mpv`
|
||||||
|
'';
|
||||||
|
};
|
||||||
configOption = mkOption {
|
configOption = mkOption {
|
||||||
type = types.raw;
|
type = types.raw;
|
||||||
default = mkOption {
|
default = mkOption {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user