]> Git — Sourcephile - sourcephile-nix.git/blob - nixpkgs/patches/transmission+apparmor.diff
nix: update nixpkgs/patches
[sourcephile-nix.git] / nixpkgs / patches / transmission+apparmor.diff
1 diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
2 index ac2a024eaa8..0519812df88 100644
3 --- a/nixos/modules/config/fonts/fontconfig.nix
4 +++ b/nixos/modules/config/fonts/fontconfig.nix
5 @@ -489,6 +489,38 @@ in
6 (mkIf cfg.enable {
7 environment.systemPackages = [ pkgs.fontconfig ];
8 environment.etc.fonts.source = "${fontconfigEtc}/etc/fonts/";
9 + security.apparmor.includes."abstractions/fonts" = ''
10 + # fonts.conf
11 + r ${supportFontsConf},
12 + r ${latestPkg.out}/etc/fonts/fonts.conf,
13 +
14 + # fontconfig default config files
15 + r ${supportPkg.out}/etc/fonts/conf.d/*.conf,
16 + r ${latestPkg.out}/etc/fonts/conf.d/*.conf,
17 +
18 + # 00-nixos-cache.conf
19 + r ${cacheConfSupport},
20 + r ${cacheConfLatest},
21 +
22 + # 10-nixos-rendering.conf
23 + r ${renderConf},
24 +
25 + # local.conf (indirect priority 51)
26 + ${optionalString (cfg.localConf != "") ''
27 + r ${localConf},
28 + ''}
29 +
30 + # 52-nixos-default-fonts.conf
31 + r ${defaultFontsConf},
32 +
33 + # 53-no-bitmaps.conf
34 + r ${rejectBitmaps},
35 +
36 + ${optionalString (!cfg.allowType1) ''
37 + # 53-nixos-reject-type1.conf
38 + r ${rejectType1},
39 + ''}
40 + '';
41 })
42 (mkIf (cfg.enable && !cfg.penultimate.enable) {
43 fonts.fontconfig.confPackages = [ confPkg ];
44 diff --git a/nixos/modules/security/apparmor-suid.nix b/nixos/modules/security/apparmor-suid.nix
45 index 6c479e070e2..e6d9467f296 100644
46 --- a/nixos/modules/security/apparmor-suid.nix
47 +++ b/nixos/modules/security/apparmor-suid.nix
48 @@ -21,9 +21,9 @@ with lib;
49 };
50
51 config = mkIf (cfg.confineSUIDApplications) {
52 - security.apparmor.profiles = [ (pkgs.writeText "ping" ''
53 + security.apparmor.policies."bin/ping".profile = ''
54 #include <tunables/global>
55 - /run/wrappers/bin/ping {
56 + /run/wrappers/wrappers.*/ping {
57 #include <abstractions/base>
58 #include <abstractions/consoles>
59 #include <abstractions/nameservice>
60 @@ -32,10 +32,19 @@ with lib;
61 capability setuid,
62 network inet raw,
63
64 - ${pkgs.stdenv.cc.libc.out}/lib/*.so mr,
65 - ${pkgs.libcap.lib}/lib/libcap.so* mr,
66 - ${pkgs.attr.out}/lib/libattr.so* mr,
67 + ${getLib pkgs.stdenv.cc.cc}/lib/*.so* mr,
68 + ${getLib pkgs.stdenv.cc.libc}/lib/*.so* mr,
69 + ${getLib pkgs.stdenv.cc.libc}/lib/gconv/gconv-modules r,
70 + ${getLib pkgs.glibcLocales}/lib/locale/locale-archive r,
71 + ${getLib pkgs.attr.out}/lib/libattr.so* mr,
72 + ${getLib pkgs.libcap.lib}/lib/libcap.so* mr,
73 + ${getLib pkgs.libcap_ng}/lib/libcap-ng.so* mr,
74 + ${getLib pkgs.libidn2}/lib/libidn2.so* mr,
75 + ${getLib pkgs.libunistring}/lib/libunistring.so* mr,
76 + ${getLib pkgs.nettle}/lib/libnettle.so* mr,
77
78 + #@{PROC}/@{pid}/environ r,
79 + /run/wrappers/wrappers.*/ping.real r,
80 ${pkgs.iputils}/bin/ping mixr,
81
82 #/etc/modules.conf r,
83 @@ -43,7 +52,7 @@ with lib;
84 ## Site-specific additions and overrides. See local/README for details.
85 ##include <local/bin.ping>
86 }
87 - '') ];
88 + '';
89 };
90
91 }
92 diff --git a/nixos/modules/security/apparmor.nix b/nixos/modules/security/apparmor.nix
93 index cfc65b347bc..f9abb18afd2 100644
94 --- a/nixos/modules/security/apparmor.nix
95 +++ b/nixos/modules/security/apparmor.nix
96 @@ -1,59 +1,190 @@
97 { config, lib, pkgs, ... }:
98
99 let
100 - inherit (lib) mkIf mkOption types concatMapStrings;
101 + inherit (builtins) head match readFile;
102 + inherit (lib) types;
103 + inherit (config.environment) etc;
104 cfg = config.security.apparmor;
105 + mkDisableOption = name: lib.mkEnableOption name // {
106 + default = true;
107 + example = false;
108 + };
109 in
110
111 {
112 - options = {
113 - security.apparmor = {
114 - enable = mkOption {
115 - type = types.bool;
116 - default = false;
117 - description = "Enable the AppArmor Mandatory Access Control system.";
118 - };
119 - profiles = mkOption {
120 - type = types.listOf types.path;
121 - default = [];
122 - description = "List of files containing AppArmor profiles.";
123 - };
124 - packages = mkOption {
125 - type = types.listOf types.package;
126 - default = [];
127 - description = "List of packages to be added to apparmor's include path";
128 - };
129 - };
130 - };
131 + imports = [
132 + (lib.mkRemovedOptionModule [ "security" "apparmor" "profiles" ] "Please use the new option: `security.apparmor.policies'.")
133 + apparmor/profiles.nix
134 + ];
135 + options = {
136 + security.apparmor = {
137 + enable = lib.mkEnableOption "the AppArmor Mandatory Access Control system";
138 + policies = lib.mkOption {
139 + description = ''
140 + AppArmor policies.
141 + '';
142 + type = types.attrsOf (types.submodule ({ name, config, ... }: {
143 + options = {
144 + enable = mkDisableOption "loading of the profile into the kernel";
145 + enforce = mkDisableOption "enforcing of the policy or only complain in the logs";
146 + profile = lib.mkOption {
147 + description = "The policy of the profile.";
148 + type = types.lines;
149 + apply = pkgs.writeText name;
150 + };
151 + };
152 + }));
153 + default = {};
154 + };
155 + includes = lib.mkOption {
156 + type = types.attrsOf types.lines;
157 + default = [];
158 + description = ''
159 + List of paths to be added to AppArmor's searched paths
160 + when resolving absolute #include directives.
161 + '';
162 + apply = lib.mapAttrs pkgs.writeText;
163 + };
164 + packages = lib.mkOption {
165 + type = types.listOf types.package;
166 + default = [];
167 + description = "List of packages to be added to AppArmor's include path";
168 + };
169 + enableCache = lib.mkEnableOption ''caching of AppArmor policies
170 + in <literal>/var/cache/apparmor/</literal>.
171 + Beware that AppArmor policies almost always contain Nix store paths,
172 + and thus produce at each change of these paths
173 + a new cached version accumulating in the cache.
174 + '';
175 + killUnconfinedConfinables = mkDisableOption ''killing of processes
176 + which have an AppArmor profile enabled
177 + (in <link linkend="opt-security.apparmor.policies">policies</link>)
178 + but are not confined (because AppArmor can only confine new processes).
179 + '';
180 + };
181 + };
182
183 - config = mkIf cfg.enable {
184 - environment.systemPackages = [ pkgs.apparmor-utils ];
185 + config = lib.mkIf cfg.enable {
186 + environment.systemPackages = [ pkgs.apparmor-utils ];
187 + environment.etc."apparmor.d".source = pkgs.linkFarm "apparmor.d" (
188 + lib.mapAttrsToList (name: p: {inherit name; path=p.profile;}) cfg.policies ++
189 + lib.mapAttrsToList (name: path: {inherit name path;}) cfg.includes
190 + );
191 + environment.etc."apparmor/parser.conf".text = ''
192 + ${if cfg.enableCache then "write-cache" else "skip-cache"}
193 + cache-loc /var/cache/apparmor
194 + Include /etc/apparmor.d
195 + '' +
196 + lib.concatMapStrings (p: "Include ${p}/etc/apparmor.d\n") cfg.packages;
197 + environment.etc."apparmor/logprof.conf".text = ''
198 + [settings]
199 + profiledir = /etc/apparmor.d
200 + inactive_profiledir = ${pkgs.apparmor-profiles}/share/apparmor/extra-profiles
201 + logfiles = /var/log/audit/audit.log /var/log/syslog /var/log/messages
202
203 - boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
204 + parser = ${pkgs.apparmor-parser}/bin/apparmor_parser
205 + ldd = ${pkgs.glibc.bin}/bin/ldd
206 + logger = ${pkgs.utillinux}/bin/logger
207
208 - systemd.services.apparmor = let
209 - paths = concatMapStrings (s: " -I ${s}/etc/apparmor.d")
210 - ([ pkgs.apparmor-profiles ] ++ cfg.packages);
211 - in {
212 - after = [ "local-fs.target" ];
213 - before = [ "sysinit.target" ];
214 - wantedBy = [ "multi-user.target" ];
215 - unitConfig = {
216 - DefaultDependencies = "no";
217 - };
218 - serviceConfig = {
219 - Type = "oneshot";
220 - RemainAfterExit = "yes";
221 - ExecStart = map (p:
222 - ''${pkgs.apparmor-parser}/bin/apparmor_parser -rKv ${paths} "${p}"''
223 - ) cfg.profiles;
224 - ExecStop = map (p:
225 - ''${pkgs.apparmor-parser}/bin/apparmor_parser -Rv "${p}"''
226 - ) cfg.profiles;
227 - ExecReload = map (p:
228 - ''${pkgs.apparmor-parser}/bin/apparmor_parser --reload ${paths} "${p}"''
229 - ) cfg.profiles;
230 - };
231 - };
232 - };
233 + # customize how file ownership permissions are presented
234 + # 0 - off
235 + # 1 - default of what ever mode the log reported
236 + # 2 - force the new permissions to be user
237 + # 3 - force all perms on the rule to be user
238 + default_owner_prompt = 1
239 +
240 + # custom directory locations to look for #includes
241 + #
242 + # each name should be a valid directory containing possible #include
243 + # candidate files under the profile dir which by default is /etc/apparmor.d.
244 + #
245 + # So an entry of my-includes will allow /etc/apparmor.d/my-includes to
246 + # be used by the yast UI and profiling tools as a source of #include
247 + # files.
248 + custom_includes =
249 +
250 + [qualifiers]
251 + ${pkgs.runtimeShell} = icnu
252 + ${pkgs.bashInteractive}/bin/sh = icnu
253 + ${pkgs.bashInteractive}/bin/bash = icnu
254 + '' + head (match "^.*\\[qualifiers](.*)" # Drop the original [settings] section.
255 + (readFile "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf"));
256 +
257 + boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
258 +
259 + systemd.services.apparmor = {
260 + after = [
261 + "local-fs.target"
262 + "systemd-journald-audit.socket"
263 + ];
264 + before = [ "sysinit.target" ];
265 + wantedBy = [ "multi-user.target" ];
266 + restartTriggers = [
267 + etc."apparmor/parser.conf".source
268 + etc."apparmor.d".source
269 + ];
270 + unitConfig = {
271 + Description="Load AppArmor policies";
272 + DefaultDependencies = "no";
273 + ConditionSecurity = "apparmor";
274 + };
275 + # Reloading instead of restarting enables to load new AppArmor profiles
276 + # without necessarily restarting all services which have Requires=apparmor.service
277 + # It works by:
278 + # - Adding or replacing into the kernel profiles enabled in cfg.policies
279 + # (because AppArmor can do that without stopping the processes already confined).
280 + # - Removing from the kernel any profile whose name is not
281 + # one of the names within the content of the profiles in cfg.policies.
282 + # - Killing the processes which are unconfined but now have a profile loaded
283 + # (because AppArmor can only confine new processes).
284 + reloadIfChanged = true;
285 + # Avoid searchs in /usr/share/locale/
286 + environment.LANG="C";
287 + serviceConfig = let
288 + enabledPolicies = lib.attrValues (lib.filterAttrs (n: p: p.enable) cfg.policies);
289 + removeDisabledProfiles = pkgs.writeShellScript "apparmor-remove" ''
290 + set -eux
291 +
292 + enabledProfiles=$(mktemp)
293 + loadedProfiles=$(mktemp)
294 + trap "rm -f $enabledProfiles $loadedProfiles" EXIT
295 +
296 + ${pkgs.apparmor-parser}/bin/apparmor_parser --names /dev/null ${
297 + lib.concatMapStrings (p: "\\\n "+p.profile) enabledPolicies} |
298 + sort -u >"$enabledProfiles"
299 +
300 + sed -e "s/ (\(enforce\|complain\))$//" /sys/kernel/security/apparmor/profiles |
301 + sort -u >"$loadedProfiles"
302 +
303 + comm -23 "$loadedProfiles" "$enabledProfiles" |
304 + while IFS=$'\n\r' read -r profile
305 + do printf %s "$profile" >/sys/kernel/security/apparmor/.remove
306 + done
307 + '';
308 + killUnconfinedConfinables = pkgs.writeShellScript "apparmor-kill" ''
309 + set -eux
310 + ${pkgs.apparmor-utils}/bin/aa-status --json |
311 + ${pkgs.jq}/bin/jq --raw-output '.processes | .[] | .[] | select (.status == "unconfined") | .pid' |
312 + xargs --verbose --no-run-if-empty --delimiter='\n' \
313 + kill
314 + '';
315 + commonOpts = p: "--verbose --show-cache ${lib.optionalString (!p.enforce) "--complain "}${p.profile}";
316 + in {
317 + Type = "oneshot";
318 + RemainAfterExit = "yes";
319 + ExecStartPre = "${pkgs.apparmor-utils}/bin/aa-teardown";
320 + ExecStart = map (p: "${pkgs.apparmor-parser}/bin/apparmor_parser --add ${commonOpts p}") enabledPolicies;
321 + ExecStartPost = lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
322 + ExecReload =
323 + map (p: "${pkgs.apparmor-parser}/bin/apparmor_parser --replace ${commonOpts p}") enabledPolicies ++
324 + [ removeDisabledProfiles ] ++
325 + lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
326 + ExecStop = "${pkgs.apparmor-utils}/bin/aa-teardown";
327 + CacheDirectory = [ "apparmor" ];
328 + CacheDirectoryMode = "0700";
329 + };
330 + };
331 + };
332 +
333 + meta.maintainers = with lib.maintainers; [ julm ];
334 }
335 diff --git a/nixos/modules/security/apparmor/profiles.nix b/nixos/modules/security/apparmor/profiles.nix
336 new file mode 100644
337 index 00000000000..7e33e630798
338 --- /dev/null
339 +++ b/nixos/modules/security/apparmor/profiles.nix
340 @@ -0,0 +1,333 @@
341 +{ config, lib, pkgs, ... }:
342 +let
343 + inherit (builtins) attrNames hasAttr isAttrs;
344 + inherit (lib) getLib;
345 + inherit (config.environment) etc;
346 + etcRule = arg:
347 + let go = {path ? null, mode ? "r", trail ? ""}:
348 + lib.optionalString (hasAttr path etc)
349 + "${mode} ${config.environment.etc."${path}".source}${trail},";
350 + in if isAttrs arg
351 + then go arg
352 + else go {path=arg;};
353 +in
354 +{
355 +config.security.apparmor.packages = [ pkgs.apparmor-profiles ];
356 +# FIXME: most of the etcRule calls below have been
357 +# written systematically by converting from apparmor-profiles's profiles
358 +# without testing nor deep understanding of their uses,
359 +# and thus may need more rules or can have less rules;
360 +# this remains to me determined case by case,
361 +# some may even be completely useless.
362 +config.security.apparmor.includes = {
363 + # This one is included by <tunables/global>
364 + # which is usualy included before any profile.
365 + "abstractions/tunables/alias" = ''
366 + alias /bin -> /run/current-system/sw/bin,
367 + # Unfortunately /etc is mainly built using symlinks,
368 + # thus aliasing does not work.
369 + #alias /etc -> /run/current-system/etc,
370 + alias /lib/modules -> /run/current-system/kernel/lib/modules,
371 + alias /sbin -> /run/current-system/sw/sbin,
372 + alias /usr -> /run/current-system/sw,
373 + '';
374 + "abstractions/audio" = ''
375 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/audio
376 + ${etcRule "asound.conf"}
377 + ${etcRule "esound/esd.conf"}
378 + ${etcRule "libao.conf"}
379 + ${etcRule {path="pulse"; trail="/";}}
380 + ${etcRule {path="pulse"; trail="/**";}}
381 + ${etcRule {path="sound"; trail="/";}}
382 + ${etcRule {path="sound"; trail="/**";}}
383 + ${etcRule {path="alsa/conf.d"; trail="/";}}
384 + ${etcRule {path="alsa/conf.d"; trail="/*";}}
385 + ${etcRule "openal/alsoft.conf"}
386 + ${etcRule "wildmidi/wildmidi.conf"}
387 + '';
388 + # FIXME: security.pam configures more .so than allowed here,
389 + # but has many tests to decide what .so to use,
390 + # so it would be simpler to let security.pam add those .so
391 + # to the present security.apparmor.includes."abstractions/authentication"
392 + "abstractions/authentication" = ''
393 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/authentication
394 + ${etcRule "nologin"}
395 + ${lib.concatMapStringsSep "\n"
396 + (name: "r ${etc."pam.d/${name}".source},")
397 + (attrNames config.security.pam.services)}
398 + mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
399 + mr ${getLib pkgs.pam}/lib/security/pam_*.so,
400 + r ${getLib pkgs.pam}/lib/security/,
401 + ${etcRule "securetty"}
402 + ${etcRule {path="security"; trail="/*";}}
403 + ${etcRule "shadow"}
404 + ${etcRule "gshadow"}
405 + ${etcRule "pwdb.conf"}
406 + ${etcRule "default/passwd"}
407 + ${etcRule "login.defs"}
408 + '';
409 + "abstractions/base" = ''
410 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/base
411 + r ${pkgs.stdenv.cc.libc}/share/locale/**,
412 + r ${pkgs.stdenv.cc.libc}/share/locale.alias,
413 + ${etcRule "localtime"}
414 + r /etc/ld-nix.so.preload,
415 + ${etcRule "ld-nix.so.preload"}
416 + ${lib.concatMapStrings (p: lib.optionalString (p != "") "mr ${p},\n")
417 + (lib.splitString "\n" etc."ld-nix.so.preload".text)
418 + # TODO: avoid this line splitting by nixifying ld-nix.so.preload as a list or attrset,
419 + # and make services.config.malloc use it.
420 + }
421 + r ${pkgs.tzdata}/share/zoneinfo/**,
422 + r ${pkgs.stdenv.cc.libc}/share/i18n/**,
423 + '';
424 + "abstractions/bash" = ''
425 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/bash
426 + # system-wide bash configuration
427 + ${etcRule "profile.dos"}
428 + ${etcRule "profile"}
429 + ${etcRule "profile.d"}
430 + ${etcRule {path="profile.d"; trail="/*";}}
431 + ${etcRule "bashrc"}
432 + ${etcRule "bash.bashrc"}
433 + ${etcRule "bash.bashrc.local"}
434 + ${etcRule "bash_completion"}
435 + ${etcRule "bash_completion.d"}
436 + ${etcRule {path="bash_completion.d"; trail="/*";}}
437 + # bash relies on system-wide readline configuration
438 + ${etcRule "inputrc"}
439 + # bash inspects filesystems at startup
440 + # and /etc/mtab is linked to /proc/mounts
441 + @{PROC}/mounts
442 +
443 + # run out of /etc/bash.bashrc
444 + ${etcRule "DIR_COLORS"}
445 + '';
446 + "abstractions/cups-client" = ''
447 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/cpus-client
448 + ${etcRule "cups/cups-client.conf"}
449 + '';
450 + "abstractions/consoles" = ''
451 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/consoles
452 + '';
453 + "abstractions/dbus-session-strict" = ''
454 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dbus-session-strict
455 + ${etcRule "machine-id"}
456 + '';
457 + "abstractions/dconf" = ''
458 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dconf
459 + ${etcRule {path="dconf"; trail="/**";}}
460 + '';
461 + "abstractions/dri-common" = ''
462 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dri-common
463 + ${etcRule "drirc"}
464 + '';
465 + # The config.fonts.fontconfig NixOS module adds many files to /etc/fonts/
466 + # by symlinking them but without exporting them outside of its NixOS module,
467 + # those are therefore added there to this "abstractions/fonts".
468 + "abstractions/fonts" = ''
469 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/fonts
470 + ${etcRule {path="fonts"; trail="/**";}}
471 + '';
472 + "abstractions/gnome" = ''
473 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/gnome
474 + ${etcRule {path="gnome"; trail="/gtkrc*";}}
475 + ${etcRule {path="gtk"; trail="/*";}}
476 + ${etcRule {path="gtk-2.0"; trail="/*";}}
477 + ${etcRule {path="gtk-3.0"; trail="/*";}}
478 + ${etcRule "orbitrc"}
479 + #include <abstractions/fonts>
480 + ${etcRule {path="pango"; trail="/*";}}
481 + ${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/";}}
482 + ${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/*";}}
483 + ${etcRule "papersize"}
484 + ${etcRule {path="cups"; trail="/lpoptions";}}
485 + ${etcRule {path="gnome"; trail="/defaults.list";}}
486 + ${etcRule {path="xdg"; trail="/{,*-}mimeapps.list";}}
487 + ${etcRule "xdg/mimeapps.list"}
488 + '';
489 + "abstractions/kde" = ''
490 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kde
491 + ${etcRule {path="qt3"; trail="/kstylerc";}}
492 + ${etcRule {path="qt3"; trail="/qt_plugins_3.3rc";}}
493 + ${etcRule {path="qt3"; trail="/qtrc";}}
494 + ${etcRule "kderc"}
495 + ${etcRule {path="kde3"; trail="/*";}}
496 + ${etcRule "kde4rc"}
497 + ${etcRule {path="xdg"; trail="/kdeglobals";}}
498 + ${etcRule {path="xdg"; trail="/Trolltech.conf";}}
499 + '';
500 + "abstractions/kerberosclient" = ''
501 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kerberosclient
502 + ${etcRule {path="krb5.keytab"; mode="rk";}}
503 + ${etcRule "krb5.conf"}
504 + ${etcRule "krb5.conf.d"}
505 + ${etcRule {path="krb5.conf.d"; trail="/*";}}
506 +
507 + # config files found via strings on libs
508 + ${etcRule "krb.conf"}
509 + ${etcRule "krb.realms"}
510 + ${etcRule "srvtab"}
511 + '';
512 + "abstractions/ldapclient" = ''
513 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ldapclient
514 + ${etcRule "ldap.conf"}
515 + ${etcRule "ldap.secret"}
516 + ${etcRule {path="openldap"; trail="/*";}}
517 + ${etcRule {path="openldap"; trail="/cacerts/*";}}
518 + ${etcRule {path="sasl2"; trail="/*";}}
519 + '';
520 + "abstractions/likewise" = ''
521 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/likewise
522 + '';
523 + "abstractions/mdns" = ''
524 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/mdns
525 + ${etcRule "nss_mdns.conf"}
526 + '';
527 + "abstractions/nameservice" = ''
528 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nameservice
529 +
530 + # Many programs wish to perform nameservice-like operations, such as
531 + # looking up users by name or id, groups by name or id, hosts by name
532 + # or IP, etc. These operations may be performed through files, dns,
533 + # NIS, NIS+, LDAP, hesiod, wins, etc. Allow them all here.
534 + ${etcRule "group"}
535 + ${etcRule "host.conf"}
536 + ${etcRule "hosts"}
537 + ${etcRule "nsswitch.conf"}
538 + ${etcRule "gai.conf"}
539 + ${etcRule "passwd"}
540 + ${etcRule "protocols"}
541 +
542 + # libtirpc (used for NIS/YP login) needs this
543 + ${etcRule "netconfig"}
544 +
545 + ${etcRule "resolv.conf"}
546 +
547 + ${etcRule {path="samba"; trail="/lmhosts";}}
548 + ${etcRule "services"}
549 +
550 + ${etcRule "default/nss"}
551 +
552 + # libnl-3-200 via libnss-gw-name
553 + ${etcRule {path="libnl"; trail="/classid";}}
554 + ${etcRule {path="libnl-3"; trail="/classid";}}
555 +
556 + mr ${getLib pkgs.nss}/lib/libnss_*.so*,
557 + mr ${getLib pkgs.nss}/lib64/libnss_*.so*,
558 + '';
559 + "abstractions/nis" = ''
560 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nis
561 + '';
562 + "abstractions/nvidia" = ''
563 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nvidia
564 + ${etcRule "vdpau_wrapper.cfg"}
565 + '';
566 + "abstractions/opencl-common" = ''
567 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-common
568 + ${etcRule {path="OpenCL"; trail="/**";}}
569 + '';
570 + "abstractions/opencl-mesa" = ''
571 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-mesa
572 + ${etcRule "default/drirc"}
573 + '';
574 + "abstractions/openssl" = ''
575 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/openssl
576 + ${etcRule {path="ssl"; trail="/openssl.cnf";}}
577 + '';
578 + "abstractions/p11-kit" = ''
579 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/p11-kit
580 + ${etcRule {path="pkcs11"; trail="/";}}
581 + ${etcRule {path="pkcs11"; trail="/pkcs11.conf";}}
582 + ${etcRule {path="pkcs11"; trail="/modules/";}}
583 + ${etcRule {path="pkcs11"; trail="/modules/*";}}
584 + '';
585 + "abstractions/perl" = ''
586 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/perl
587 + ${etcRule {path="perl"; trail="/**";}}
588 + '';
589 + "abstractions/php" = ''
590 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/php
591 + ${etcRule {path="php"; trail="/**/";}}
592 + ${etcRule {path="php5"; trail="/**/";}}
593 + ${etcRule {path="php7"; trail="/**/";}}
594 + ${etcRule {path="php"; trail="/**.ini";}}
595 + ${etcRule {path="php5"; trail="/**.ini";}}
596 + ${etcRule {path="php7"; trail="/**.ini";}}
597 + '';
598 + "abstractions/postfix-common" = ''
599 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/postfix-common
600 + ${etcRule "mailname"}
601 + ${etcRule {path="postfix"; trail="/*.cf";}}
602 + ${etcRule "postfix/main.cf"}
603 + ${etcRule "postfix/master.cf"}
604 + '';
605 + "abstractions/python" = ''
606 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/python
607 + ${etcRule {path="python2.4"; trail="/**";}}
608 + ${etcRule {path="python2.5"; trail="/**";}}
609 + ${etcRule {path="python2.6"; trail="/**";}}
610 + ${etcRule {path="python2.7"; trail="/**";}}
611 + ${etcRule {path="python3.0"; trail="/**";}}
612 + ${etcRule {path="python3.1"; trail="/**";}}
613 + ${etcRule {path="python3.2"; trail="/**";}}
614 + ${etcRule {path="python3.3"; trail="/**";}}
615 + ${etcRule {path="python3.4"; trail="/**";}}
616 + ${etcRule {path="python3.5"; trail="/**";}}
617 + ${etcRule {path="python3.6"; trail="/**";}}
618 + ${etcRule {path="python3.7"; trail="/**";}}
619 + ${etcRule {path="python3.8"; trail="/**";}}
620 + ${etcRule {path="python3.9"; trail="/**";}}
621 + '';
622 + "abstractions/qt5" = ''
623 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/qt5
624 + ${etcRule {path="xdg"; trail="/QtProject/qtlogging.ini";}}
625 + ${etcRule {path="xdg/QtProject"; trail="/qtlogging.ini";}}
626 + ${etcRule "xdg/QtProject/qtlogging.ini"}
627 + '';
628 + "abstractions/samba" = ''
629 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/samba
630 + ${etcRule {path="samba"; trail="/*";}}
631 + '';
632 + "abstractions/ssl_certs" = ''
633 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ssl_certs
634 + ${etcRule "ssl/certs/ca-certificates.crt"}
635 + ${etcRule "ssl/certs/ca-bundle.crt"}
636 + ${etcRule "pki/tls/certs/ca-bundle.crt"}
637 +
638 + ${etcRule {path="ssl/trust"; trail="/";}}
639 + ${etcRule {path="ssl/trust"; trail="/*";}}
640 + ${etcRule {path="ssl/trust/anchors"; trail="/";}}
641 + ${etcRule {path="ssl/trust/anchors"; trail="/**";}}
642 + ${etcRule {path="pki/trust"; trail="/";}}
643 + ${etcRule {path="pki/trust"; trail="/*";}}
644 + ${etcRule {path="pki/trust/anchors"; trail="/";}}
645 + ${etcRule {path="pki/trust/anchors"; trail="/**";}}
646 +
647 + # security.acme NixOS module
648 + r /var/lib/acme/*/cert.pem,
649 + r /var/lib/acme/*/chain.pem,
650 + r /var/lib/acme/*/fullchain.pem,
651 + '';
652 + "abstractions/ssl_keys" = ''
653 + # security.acme NixOS module
654 + r /var/lib/acme/*/full.pem,
655 + r /var/lib/acme/*/key.pem,
656 + '';
657 + "abstractions/vulkan" = ''
658 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/vulkan
659 + ${etcRule {path="vulkan/icd.d"; trail="/";}}
660 + ${etcRule {path="vulkan/icd.d"; trail="/*.json";}}
661 + '';
662 + "abstractions/winbind" = ''
663 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/winbind
664 + ${etcRule {path="samba"; trail="/smb.conf";}}
665 + ${etcRule {path="samba"; trail="/dhcp.conf";}}
666 + '';
667 + "abstractions/X" = ''
668 + #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/X
669 + ${etcRule {path="X11/cursors"; trail="/";}}
670 + ${etcRule {path="X11/cursors"; trail="/**";}}
671 + '';
672 +};
673 +}
674 diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
675 index 688344852ae..339dbd4cb3a 100644
676 --- a/nixos/modules/security/pam.nix
677 +++ b/nixos/modules/security/pam.nix
678 @@ -789,6 +789,57 @@ in
679 runuser-l = { rootOK = true; unixAuth = false; };
680 };
681
682 + security.apparmor.includes."abstractions/pam" = let
683 + isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
684 + in ''
685 + ${optionalString use_ldap
686 + "mr ${pam_ldap}/lib/security/pam_ldap.so,"}
687 + ${optionalString config.services.sssd.enable
688 + "mr ${pkgs.sssd}/lib/security/pam_sss.so,"}
689 + ${optionalString config.krb5.enable ''
690 + mr ${pam_krb5}/lib/security/pam_krb5.so,
691 + mr ${pam_ccreds}/lib/security/pam_ccreds.so,
692 + ''}
693 + ${optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
694 + mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,
695 + mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so,
696 + ''}
697 + ${optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication))
698 + "mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,"}
699 + ${optionalString (config.security.pam.enableSSHAgentAuth && isEnabled (cfg: cfg.sshAgentAuth))
700 + "mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,"}
701 + ${optionalString (isEnabled (cfg: cfg.fprintAuth))
702 + "mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,"}
703 + ${optionalString (isEnabled (cfg: cfg.u2fAuth))
704 + "mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,"}
705 + ${optionalString (isEnabled (cfg: cfg.usbAuth))
706 + "mr ${pkgs.pam_usb}/lib/security/pam_usb.so,"}
707 + ${optionalString (isEnabled (cfg: cfg.oathAuth))
708 + "mr ${pkgs.oathToolkit}/lib/security/pam_oath.so,"}
709 + ${optionalString (isEnabled (cfg: cfg.yubicoAuth))
710 + "mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,"}
711 + ${optionalString (isEnabled (cfg: cfg.duoSecurity.enable))
712 + "mr ${pkgs.duo-unix}/lib/security/pam_duo.so,"}
713 + ${optionalString (isEnabled (cfg: cfg.otpwAuth))
714 + "mr ${pkgs.otpw}/lib/security/pam_otpw.so,"}
715 + ${optionalString config.security.pam.enableEcryptfs
716 + "mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,"}
717 + ${optionalString (isEnabled (cfg: cfg.pamMount))
718 + "mr ${pkgs.pam_mount}/lib/security/pam_mount.so,"}
719 + ${optionalString config.services.samba.syncPasswordsByPam
720 + "mr ${pkgs.samba}/lib/security/pam_smbpass.so,"}
721 + ${optionalString (isEnabled (cfg: cfg.enableGnomeKeyring))
722 + "mr ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so,"}
723 + ${optionalString (isEnabled (cfg: cfg.startSession))
724 + "mr ${pkgs.systemd}/lib/security/pam_systemd.so,"}
725 + ${optionalString (isEnabled (cfg: cfg.enableAppArmor) && config.security.apparmor.enable)
726 + "mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,"}
727 + ${optionalString (isEnabled (cfg: cfg.enableKwallet))
728 + "mr ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so,"}
729 + ${optionalString config.virtualisation.lxc.lxcfs.enable
730 + "mr ${pkgs.lxc}/lib/security/pam_cgfs.so"}
731 + '';
732 +
733 };
734
735 }
736 diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
737 index 1bfcf2de82f..a1c6d949bfe 100644
738 --- a/nixos/modules/services/torrent/transmission.nix
739 +++ b/nixos/modules/services/torrent/transmission.nix
740 @@ -1,52 +1,56 @@
741 -{ config, lib, pkgs, ... }:
742 +{ config, lib, pkgs, options, ... }:
743
744 with lib;
745
746 let
747 cfg = config.services.transmission;
748 + inherit (config.environment) etc;
749 apparmor = config.security.apparmor.enable;
750 -
751 - homeDir = cfg.home;
752 - downloadDirPermissions = cfg.downloadDirPermissions;
753 - downloadDir = "${homeDir}/Downloads";
754 - incompleteDir = "${homeDir}/.incomplete";
755 -
756 - settingsDir = "${homeDir}/config";
757 - settingsFile = pkgs.writeText "settings.json" (builtins.toJSON fullSettings);
758 -
759 - # for users in group "transmission" to have access to torrents
760 - fullSettings = { umask = 2; download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings;
761 -
762 - preStart = pkgs.writeScript "transmission-pre-start" ''
763 - #!${pkgs.runtimeShell}
764 - set -ex
765 - cp -f ${settingsFile} ${settingsDir}/settings.json
766 - '';
767 + stateDir = "/var/lib/transmission";
768 + # TODO: switch to configGen.json once RFC0042 is implemented
769 + settingsFile = pkgs.writeText "settings.json" (builtins.toJSON (cfg.settings // {
770 + download-dir = "${stateDir}/Downloads";
771 + incomplete-dir = "${stateDir}/.incomplete";
772 + }));
773 + settingsDir = ".config/transmission-daemon";
774 + makeAbsolute = base: path:
775 + if builtins.match "^/.*" path == null
776 + then base+"/"+path else path;
777 in
778 {
779 options = {
780 services.transmission = {
781 - enable = mkOption {
782 - type = types.bool;
783 - default = false;
784 - description = ''
785 - Whether or not to enable the headless Transmission BitTorrent daemon.
786 + enable = mkEnableOption ''the headless Transmission BitTorrent daemon.
787
788 - Transmission daemon can be controlled via the RPC interface using
789 - transmission-remote or the WebUI (http://localhost:9091/ by default).
790 + Transmission daemon can be controlled via the RPC interface using
791 + transmission-remote, the WebUI (http://${cfg.settings.rpc-bind-address}:${toString cfg.settings.rpc-port}/ by default),
792 + or other clients like stig or tremc.
793
794 - Torrents are downloaded to ${downloadDir} by default and are
795 - accessible to users in the "transmission" group.
796 - '';
797 - };
798 + Torrents are downloaded to ${cfg.settings.download-dir} by default and are
799 + accessible to users in the "transmission" group'';
800
801 - settings = mkOption {
802 + settings = mkOption rec {
803 + # TODO: switch to types.config.json as prescribed by RFC0042 once it's implemented
804 type = types.attrs;
805 + apply = attrs:
806 + let super = recursiveUpdate default attrs; in
807 + super // {
808 + download-dir = makeAbsolute cfg.home super.download-dir;
809 + incomplete-dir = makeAbsolute cfg.home super.incomplete-dir;
810 + };
811 default =
812 {
813 - download-dir = downloadDir;
814 - incomplete-dir = incompleteDir;
815 + download-dir = "${cfg.home}/Downloads";
816 + incomplete-dir = "${cfg.home}/.incomplete";
817 incomplete-dir-enabled = true;
818 + peer-port = 51413;
819 + peer-port-random-high = 65535;
820 + peer-port-random-low = 49152;
821 + peer-port-random-on-start = false;
822 + rpc-bind-address = "127.0.0.1";
823 + rpc-port = 9091;
824 + umask = 18; # 0o022 in decimal as expected by Transmission, obtained with: echo $((8#022))
825 + utp-enabled = true;
826 };
827 example =
828 {
829 @@ -56,8 +60,9 @@ in
830 rpc-whitelist = "127.0.0.1,192.168.*.*";
831 };
832 description = ''
833 - Attribute set whos fields overwrites fields in settings.json (each
834 - time the service starts). String values must be quoted, integer and
835 + Attribute set whose fields overwrites fields in
836 + <literal>.config/transmission-daemon/settings.json</literal>
837 + (each time the service starts). String values must be quoted, integer and
838 boolean values must not.
839
840 See https://github.com/transmission/transmission/wiki/Editing-Configuration-Files
841 @@ -70,22 +75,30 @@ in
842 default = "770";
843 example = "775";
844 description = ''
845 - The permissions to set for download-dir and incomplete-dir.
846 - They will be applied on every service start.
847 + The permissions set by the <literal>systemd-tmpfiles-setup</literal> service
848 + on <link linkend="opt-services.transmission.settings">settings.download-dir</link>
849 + and <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link>.
850 '';
851 };
852
853 port = mkOption {
854 - type = types.int;
855 - default = 9091;
856 - description = "TCP port number to run the RPC/web interface.";
857 + type = types.port;
858 + description = ''
859 + TCP port number to run the RPC/web interface.
860 +
861 + If instead you want to change the peer port,
862 + use <link linkend="opt-services.transmission.settings">settings.peer-port</link>
863 + or <link linkend="opt-services.transmission.settings">settings.peer-port-random-on-start</link>.
864 + '';
865 };
866
867 home = mkOption {
868 type = types.path;
869 - default = "/var/lib/transmission";
870 + default = stateDir;
871 description = ''
872 - The directory where transmission will create files.
873 + The directory where Transmission will create <literal>.config/transmission-daemon/</literal>.
874 + as well as <literal>Downloads/</literal> unless <link linkend="opt-services.transmission.settings">settings.download-dir</link> is changed,
875 + and <literal>.incomplete/</literal> unless <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link> is changed.
876 '';
877 };
878
879 @@ -100,32 +113,136 @@ in
880 default = "transmission";
881 description = "Group account under which Transmission runs.";
882 };
883 +
884 + credentialsFile = mkOption {
885 + type = types.path;
886 + description = ''
887 + Path to a JSON file to be merged with the settings.
888 + Useful to merge a file which is better kept out of the Nix store
889 + because it contains sensible data like <link linkend="opt-services.transmission.settings">settings.rpc-password</link>.
890 + '';
891 + default = "/dev/null";
892 + example = "/var/lib/secrets/transmission/settings.json";
893 + };
894 +
895 + openFirewall = mkEnableOption "opening of the peer port(s) in the firewall";
896 };
897 };
898
899 config = mkIf cfg.enable {
900 - systemd.tmpfiles.rules = [
901 - "d '${homeDir}' 0770 '${cfg.user}' '${cfg.group}' - -"
902 - "d '${settingsDir}' 0700 '${cfg.user}' '${cfg.group}' - -"
903 - "d '${fullSettings.download-dir}' '${downloadDirPermissions}' '${cfg.user}' '${cfg.group}' - -"
904 - "d '${fullSettings.incomplete-dir}' '${downloadDirPermissions}' '${cfg.user}' '${cfg.group}' - -"
905 + systemd.tmpfiles.rules =
906 + optional (cfg.home != stateDir) "d '${cfg.home}/${settingsDir}' 700 '${cfg.user}' '${cfg.group}' - -"
907 + ++ [ "d '${cfg.settings.download-dir}' '${cfg.downloadDirPermissions}' '${cfg.user}' '${cfg.group}' - -" ]
908 + ++ optional cfg.settings.incomplete-dir-enabled
909 + "d '${cfg.settings.incomplete-dir}' '${cfg.downloadDirPermissions}' '${cfg.user}' '${cfg.group}' - -";
910 +
911 + assertions = [
912 + { assertion = builtins.match "^/.*" cfg.home != null;
913 + message = "`services.transmission.home' must be an absolute path.";
914 + }
915 + { assertion = types.port.check cfg.settings.rpc-port;
916 + message = "${toString cfg.settings.rpc-port} is not a valid port number for `services.transmission.settings.rpc-port`.";
917 + }
918 + # In case both port and settings.rpc-port are explicitely defined: they must be the same.
919 + { assertion = !options.services.transmission.port.isDefined || cfg.port == cfg.settings.rpc-port;
920 + message = "`services.transmission.port' is not equal to `services.transmission.settings.rpc-port'";
921 + }
922 ];
923
924 + services.transmission.settings =
925 + optionalAttrs options.services.transmission.port.isDefined { rpc-port = cfg.port; };
926 +
927 systemd.services.transmission = {
928 description = "Transmission BitTorrent Service";
929 after = [ "network.target" ] ++ optional apparmor "apparmor.service";
930 - requires = mkIf apparmor [ "apparmor.service" ];
931 + requires = optional apparmor "apparmor.service";
932 wantedBy = [ "multi-user.target" ];
933 + environment.CURL_CA_BUNDLE = etc."ssl/certs/ca-certificates.crt".source;
934
935 - # 1) Only the "transmission" user and group have access to torrents.
936 - # 2) Optionally update/force specific fields into the configuration file.
937 - serviceConfig.ExecStartPre = preStart;
938 - serviceConfig.ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f --port ${toString config.services.transmission.port} --config-dir ${settingsDir}";
939 - serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
940 - serviceConfig.User = cfg.user;
941 - serviceConfig.Group = cfg.group;
942 - # NOTE: transmission has an internal umask that also must be set (in settings.json)
943 - serviceConfig.UMask = "0002";
944 + serviceConfig = {
945 + WorkingDirectory = stateDir;
946 + # Use "+" because credentialsFile may not be accessible to the User.
947 + ExecStartPre = "+" + pkgs.writeShellScript "transmission-prestart" ''
948 + set -eux
949 + ${pkgs.jq}/bin/jq --slurp add ${settingsFile} '${cfg.credentialsFile}' |
950 + install -m 700 -o ${cfg.user} -g ${cfg.group} /dev/stdin '${stateDir}/${settingsDir}/settings.json'
951 + '';
952 + ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f";
953 + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
954 + User = cfg.user;
955 + Group = cfg.group;
956 + StateDirectory = removePrefix "/var/lib/" stateDir + "/" + settingsDir;
957 + StateDirectoryMode = "0700";
958 + BindPaths =
959 + optional (cfg.home != stateDir) "${cfg.home}/${settingsDir}:${stateDir}/${settingsDir}"
960 + ++ [ "${cfg.settings.download-dir}:${stateDir}/Downloads" ]
961 + ++ optional cfg.settings.incomplete-dir-enabled "${cfg.settings.incomplete-dir}:${stateDir}/.incomplete";
962 + # The following options give:
963 + # systemd-analyze security transmission
964 + # → Overall exposure level for transmission.service: 1.5 OK
965 + AmbientCapabilities = "";
966 + CapabilityBoundingSet = "";
967 + LockPersonality = true;
968 + MemoryDenyWriteExecute = true;
969 + NoNewPrivileges = true;
970 + PrivateDevices = true;
971 + PrivateMounts = true;
972 + PrivateNetwork = false;
973 + PrivateTmp = true;
974 + PrivateUsers = false;
975 + ProtectClock = true;
976 + ProtectControlGroups = true;
977 + ProtectHome = mkDefault true;
978 + ProtectHostname = true;
979 + ProtectKernelLogs = true;
980 + ProtectKernelModules = true;
981 + ProtectKernelTunables = true;
982 + ProtectSystem = mkDefault "strict";
983 + ReadWritePaths = [ stateDir ];
984 + RemoveIPC = true;
985 + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
986 + RestrictNamespaces = true;
987 + RestrictRealtime = true;
988 + RestrictSUIDSGID = true;
989 + # In case transmission crashes with status=31/SYS,
990 + # having systemd.coredump.enable = true
991 + # and environment.enableDebugInfo = true
992 + # enables to use coredumpctl debug to find the denied syscall.
993 + SystemCallFilter = [
994 + "@default"
995 + "@aio"
996 + "@basic-io"
997 + #"@chown"
998 + #"@clock"
999 + #"@cpu-emulation"
1000 + #"@debug"
1001 + "@file-system"
1002 + "@io-event"
1003 + #"@ipc"
1004 + #"@keyring"
1005 + #"@memlock"
1006 + #"@module"
1007 + #"@mount"
1008 + "@network-io"
1009 + #"@obsolete"
1010 + #"@pkey"
1011 + #"@privileged"
1012 + # Reached when querying infos through RPC (eg. with stig)
1013 + "quotactl"
1014 + "@process"
1015 + #"@raw-io"
1016 + #"@reboot"
1017 + #"@resources"
1018 + #"@setuid"
1019 + "@signal"
1020 + #"@swap"
1021 + "@sync"
1022 + "@system-service"
1023 + "@timer"
1024 + ];
1025 + SystemCallArchitectures = "native";
1026 + UMask = "0077";
1027 + };
1028 };
1029
1030 # It's useful to have transmission in path, e.g. for remote control
1031 @@ -133,32 +250,57 @@ in
1032
1033 users.users = optionalAttrs (cfg.user == "transmission") ({
1034 transmission = {
1035 - name = "transmission";
1036 group = cfg.group;
1037 uid = config.ids.uids.transmission;
1038 description = "Transmission BitTorrent user";
1039 - home = homeDir;
1040 - createHome = true;
1041 + home = stateDir;
1042 };
1043 });
1044
1045 users.groups = optionalAttrs (cfg.group == "transmission") ({
1046 transmission = {
1047 - name = "transmission";
1048 gid = config.ids.gids.transmission;
1049 };
1050 });
1051
1052 - # AppArmor profile
1053 - security.apparmor.profiles = mkIf apparmor [
1054 - (pkgs.writeText "apparmor-transmission-daemon" ''
1055 + networking.firewall = mkIf cfg.openFirewall (
1056 + if cfg.settings.peer-port-random-on-start
1057 + then
1058 + { allowedTCPPortRanges =
1059 + [ { from = cfg.settings.peer-port-random-low;
1060 + to = cfg.settings.peer-port-random-high;
1061 + }
1062 + ];
1063 + allowedUDPPortRanges =
1064 + [ { from = cfg.settings.peer-port-random-low;
1065 + to = cfg.settings.peer-port-random-high;
1066 + }
1067 + ];
1068 + }
1069 + else
1070 + { allowedTCPPorts = [ cfg.settings.peer-port ];
1071 + allowedUDPPorts = [ cfg.settings.peer-port ];
1072 + }
1073 + );
1074 +
1075 + # Transmission uses a single UDP socket in order to implement multiple uTP sockets,
1076 + # and thus expects large kernel buffers for the UDP socket,
1077 + # at least up to the values hardcoded here:
1078 + # https://trac.transmissionbt.com/browser/trunk/libtransmission/tr-udp.c?rev=11956.
1079 + boot.kernel.sysctl = mkIf cfg.settings.utp-enabled {
1080 + "net.core.rmem_max" = mkDefault "4194304"; # 4MB
1081 + "net.core.wmem_max" = mkDefault "1048576"; # 1MB
1082 + };
1083 +
1084 + security.apparmor.policies."bin/transmission-daemon".profile = ''
1085 #include <tunables/global>
1086
1087 ${pkgs.transmission}/bin/transmission-daemon {
1088 #include <abstractions/base>
1089 #include <abstractions/nameservice>
1090
1091 - ${getLib pkgs.glibc}/lib/*.so mr,
1092 + ${getLib pkgs.stdenv.cc.cc}/lib/*.so* mr,
1093 + ${getLib pkgs.stdenv.cc.libc}/lib/*.so* mr,
1094 ${getLib pkgs.libevent}/lib/libevent*.so* mr,
1095 ${getLib pkgs.curl}/lib/libcurl*.so* mr,
1096 ${getLib pkgs.openssl}/lib/libssl*.so* mr,
1097 @@ -176,27 +318,29 @@ in
1098 ${getLib pkgs.lz4}/lib/liblz4*.so* mr,
1099 ${getLib pkgs.libkrb5}/lib/lib*.so* mr,
1100 ${getLib pkgs.keyutils}/lib/libkeyutils*.so* mr,
1101 - ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so.* mr,
1102 - ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so.* mr,
1103 - ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so.* mr,
1104 - ${getLib pkgs.gcc.cc.lib}/lib/libstdc++.so.* mr,
1105 - ${getLib pkgs.gcc.cc.lib}/lib/libgcc_s.so.* mr,
1106 + ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so* mr,
1107 + ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so* mr,
1108 + ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so* mr,
1109
1110 @{PROC}/sys/kernel/random/uuid r,
1111 @{PROC}/sys/vm/overcommit_memory r,
1112 + #@{PROC}/@{pid}/environ r,
1113 + @{PROC}/@{pid}/mounts r,
1114 + /tmp/tr_session_id_* rwk,
1115
1116 - ${pkgs.openssl.out}/etc/** r,
1117 + ${pkgs.openssl.out}/etc/** r,
1118 + ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE} r,
1119 ${pkgs.transmission}/share/transmission/** r,
1120
1121 - owner ${settingsDir}/** rw,
1122 + owner ${stateDir}/${settingsDir}/** rw,
1123
1124 - ${fullSettings.download-dir}/** rw,
1125 - ${optionalString fullSettings.incomplete-dir-enabled ''
1126 - ${fullSettings.incomplete-dir}/** rw,
1127 + ${stateDir}/Downloads/** rw,
1128 + ${optionalString cfg.settings.incomplete-dir-enabled ''
1129 + ${stateDir}/.incomplete/** rw,
1130 ''}
1131 }
1132 - '')
1133 - ];
1134 + '';
1135 };
1136
1137 + meta.maintainers = with lib.maintainers; [ julm ];
1138 }
1139 diff --git a/nixos/modules/virtualisation/lxc.nix b/nixos/modules/virtualisation/lxc.nix
1140 index f484d5ee59a..a2f4a9867c6 100644
1141 --- a/nixos/modules/virtualisation/lxc.nix
1142 +++ b/nixos/modules/virtualisation/lxc.nix
1143 @@ -74,9 +74,13 @@ in
1144 systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
1145
1146 security.apparmor.packages = [ pkgs.lxc ];
1147 - security.apparmor.profiles = [
1148 - "${pkgs.lxc}/etc/apparmor.d/lxc-containers"
1149 - "${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start"
1150 - ];
1151 + security.apparmor.policies = {
1152 + "bin/lxc-start".profile = ''
1153 + #include ${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start
1154 + '';
1155 + "lxc-containers".profile = ''
1156 + #include ${pkgs.lxc}/etc/apparmor.d/lxc-containers
1157 + '';
1158 + };
1159 };
1160 }
1161 diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
1162 index 3958fc2c1d7..84c8e88f8b4 100644
1163 --- a/nixos/modules/virtualisation/lxd.nix
1164 +++ b/nixos/modules/virtualisation/lxd.nix
1165 @@ -93,11 +93,15 @@ in
1166
1167 security.apparmor = {
1168 enable = true;
1169 - profiles = [
1170 - "${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start"
1171 - "${cfg.lxcPackage}/etc/apparmor.d/lxc-containers"
1172 - ];
1173 packages = [ cfg.lxcPackage ];
1174 + policies = {
1175 + "bin/lxc-start".profile = ''
1176 + #include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start
1177 + '';
1178 + "lxc-containers".profile = ''
1179 + #include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
1180 + '';
1181 + };
1182 };
1183
1184 systemd.services.lxd = {
1185 diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix
1186 index 0a97d5556a2..c195b60cd56 100644
1187 --- a/nixos/tests/bittorrent.nix
1188 +++ b/nixos/tests/bittorrent.nix
1189 @@ -19,6 +19,7 @@ let
1190 externalClient2Address = "80.100.100.2";
1191 externalTrackerAddress = "80.100.100.3";
1192
1193 + download-dir = "/var/lib/transmission/Downloads";
1194 transmissionConfig = { ... }: {
1195 environment.systemPackages = [ pkgs.transmission ];
1196 services.transmission = {
1197 @@ -26,6 +27,7 @@ let
1198 settings = {
1199 dht-enabled = false;
1200 message-level = 3;
1201 + inherit download-dir;
1202 };
1203 };
1204 };
1205 @@ -117,12 +119,12 @@ in
1206 router.wait_for_unit("miniupnpd")
1207
1208 # Create the torrent.
1209 - tracker.succeed("mkdir /tmp/data")
1210 + tracker.succeed("mkdir ${download-dir}/data")
1211 tracker.succeed(
1212 - "cp ${file} /tmp/data/test.tar.bz2"
1213 + "cp ${file} ${download-dir}/data/test.tar.bz2"
1214 )
1215 tracker.succeed(
1216 - "transmission-create /tmp/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent"
1217 + "transmission-create ${download-dir}/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent"
1218 )
1219 tracker.succeed("chmod 644 /tmp/test.torrent")
1220
1221 @@ -133,18 +135,16 @@ in
1222
1223 # Start the initial seeder.
1224 tracker.succeed(
1225 - "transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir /tmp/data"
1226 + "transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir ${download-dir}/data"
1227 )
1228
1229 # Now we should be able to download from the client behind the NAT.
1230 tracker.wait_for_unit("httpd")
1231 client1.wait_for_unit("network-online.target")
1232 + client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &")
1233 + client1.wait_for_file("${download-dir}/test.tar.bz2")
1234 client1.succeed(
1235 - "transmission-remote --add http://${externalTrackerAddress}/test.torrent --download-dir /tmp >&2 &"
1236 - )
1237 - client1.wait_for_file("/tmp/test.tar.bz2")
1238 - client1.succeed(
1239 - "cmp /tmp/test.tar.bz2 ${file}"
1240 + "cmp ${download-dir}/test.tar.bz2 ${file}"
1241 )
1242
1243 # Bring down the initial seeder.
1244 @@ -154,11 +154,11 @@ in
1245 # the first client created a NAT hole in the router.
1246 client2.wait_for_unit("network-online.target")
1247 client2.succeed(
1248 - "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht --download-dir /tmp >&2 &"
1249 + "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &"
1250 )
1251 - client2.wait_for_file("/tmp/test.tar.bz2")
1252 + client2.wait_for_file("${download-dir}/test.tar.bz2")
1253 client2.succeed(
1254 - "cmp /tmp/test.tar.bz2 ${file}"
1255 + "cmp ${download-dir}/test.tar.bz2 ${file}"
1256 )
1257 '';
1258 })
1259 diff --git a/pkgs/os-specific/linux/apparmor/default.nix b/pkgs/os-specific/linux/apparmor/default.nix
1260 index 66c2582603c..0205abc290b 100644
1261 --- a/pkgs/os-specific/linux/apparmor/default.nix
1262 +++ b/pkgs/os-specific/linux/apparmor/default.nix
1263 @@ -10,6 +10,10 @@
1264 , pam
1265 , libnotify
1266 , buildPackages
1267 +, coreutils
1268 +, gnugrep
1269 +, gnused
1270 +, writeShellScript
1271 }:
1272
1273 let
1274 @@ -38,6 +42,22 @@ let
1275 sha256 = "0xw028iqp69j9mxv0kbwraplgkj5i5djdlgf0anpkc5cdbsf96r9";
1276 };
1277
1278 + aa-teardown = writeShellScript "aa-teardown" ''
1279 + SECURITYFS=/sys/kernel/security
1280 + SFS_MOUNTPOINT="$SECURITYFS/apparmor"
1281 + ${gnused}/bin/sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | \
1282 + LC_COLLATE=C ${coreutils}/bin/sort | ${gnugrep}/bin/grep -v // | {
1283 + while read -r profile ; do
1284 + printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove"
1285 + rc=$?
1286 + if [ "$rc" -ne 0 ] ; then
1287 + retval=$rc
1288 + fi
1289 + done
1290 + exit "''${retval:-0}"
1291 + }
1292 + '';
1293 +
1294 prePatchCommon = ''
1295 substituteInPlace ./common/Make.rules --replace "/usr/bin/pod2man" "${buildPackages.perl}/bin/pod2man"
1296 substituteInPlace ./common/Make.rules --replace "/usr/bin/pod2html" "${buildPackages.perl}/bin/pod2html"
1297 @@ -142,6 +162,8 @@ let
1298 # aa-notify checks its name and does not work named ".aa-notify-wrapped"
1299 mv $out/bin/aa-notify $out/bin/aa-notify-wrapped
1300 makeWrapper ${perl}/bin/perl $out/bin/aa-notify --set PERL5LIB ${libapparmor}/${perl.libPrefix} --add-flags $out/bin/aa-notify-wrapped
1301 +
1302 + ln -s ${aa-teardown} $out/bin/aa-teardown
1303 '';
1304
1305 inherit doCheck;