1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.programs.firejail;
10
11 wrappedBins =
12 pkgs.runCommand "firejail-wrapped-binaries"
13 {
14 preferLocalBuild = true;
15 allowSubstitutes = false;
16 # take precedence over non-firejailed versions
17 meta.priority = -1;
18 }
19 ''
20 mkdir -p $out/bin
21 mkdir -p $out/share/applications
22 ${lib.concatStringsSep "\n" (
23 lib.mapAttrsToList (
24 command: value:
25 let
26 opts =
27 if builtins.isAttrs value then
28 value
29 else
30 {
31 executable = value;
32 desktop = null;
33 profile = null;
34 extraArgs = [ ];
35 };
36 args = lib.escapeShellArgs (
37 opts.extraArgs
38 ++ (lib.optional (opts.profile != null) "--profile=${builtins.toString opts.profile}")
39 );
40 in
41 ''
42 cat <<_EOF >$out/bin/${command}
43 #! ${pkgs.runtimeShell} -e
44 exec /run/wrappers/bin/firejail ${args} -- ${builtins.toString opts.executable} "\$@"
45 _EOF
46 chmod 0755 $out/bin/${command}
47
48 ${lib.optionalString (opts.desktop != null) ''
49 substitute ${opts.desktop} $out/share/applications/$(basename ${opts.desktop}) \
50 --replace ${opts.executable} $out/bin/${command}
51 ''}
52 ''
53 ) cfg.wrappedBinaries
54 )}
55 '';
56
57in
58{
59 options.programs.firejail = {
60 enable = lib.mkEnableOption "firejail, a sandboxing tool for Linux";
61
62 wrappedBinaries = lib.mkOption {
63 type = lib.types.attrsOf (
64 lib.types.either lib.types.path (
65 lib.types.submodule {
66 options = {
67 executable = lib.mkOption {
68 type = lib.types.path;
69 description = "Executable to run sandboxed";
70 example = lib.literalExpression ''"''${lib.getBin pkgs.firefox}/bin/firefox"'';
71 };
72 desktop = lib.mkOption {
73 type = lib.types.nullOr lib.types.path;
74 default = null;
75 description = ".desktop file to modify. Only necessary if it uses the absolute path to the executable.";
76 example = lib.literalExpression ''"''${pkgs.firefox}/share/applications/firefox.desktop"'';
77 };
78 profile = lib.mkOption {
79 type = lib.types.nullOr lib.types.path;
80 default = null;
81 description = "Profile to use";
82 example = lib.literalExpression ''"''${pkgs.firejail}/etc/firejail/firefox.profile"'';
83 };
84 extraArgs = lib.mkOption {
85 type = lib.types.listOf lib.types.str;
86 default = [ ];
87 description = "Extra arguments to pass to firejail";
88 example = [ "--private=~/.firejail_home" ];
89 };
90 };
91 }
92 )
93 );
94 default = { };
95 example = lib.literalExpression ''
96 {
97 firefox = {
98 executable = "''${lib.getBin pkgs.firefox}/bin/firefox";
99 profile = "''${pkgs.firejail}/etc/firejail/firefox.profile";
100 };
101 mpv = {
102 executable = "''${lib.getBin pkgs.mpv}/bin/mpv";
103 profile = "''${pkgs.firejail}/etc/firejail/mpv.profile";
104 };
105 }
106 '';
107 description = ''
108 Wrap the binaries in firejail and place them in the global path.
109 '';
110 };
111 };
112
113 config = lib.mkIf cfg.enable {
114 security.wrappers.firejail = {
115 setuid = true;
116 owner = "root";
117 group = "root";
118 source = "${lib.getBin pkgs.firejail}/bin/firejail";
119 };
120
121 environment.systemPackages = [ pkgs.firejail ] ++ [ wrappedBins ];
122 };
123
124 meta.maintainers = with lib.maintainers; [ peterhoeg ];
125}