apparmor: fix and improve the service

This commit is contained in:
Julien Moutinho 2020-08-08 02:01:35 +02:00
parent 539ae5c932
commit fb6d63f3fd
20 changed files with 793 additions and 164 deletions

View file

@ -4169,7 +4169,7 @@
name = "Julien Dehos";
};
julm = {
email = "julm+nix@sourcephile.fr";
email = "julm+nixpkgs@sourcephile.fr";
github = "ju1m";
githubId = 21160136;
name = "Julien Moutinho";

View file

@ -910,6 +910,24 @@ services.transmission.settings.rpc-bind-address = "0.0.0.0";
to get the previous behavior of listening on all network interfaces.
</para>
</listitem>
<listitem>
<para>
The <literal>security.apparmor</literal> module,
for the <link xlink:href="https://gitlab.com/apparmor/apparmor/-/wikis/Documentation">AppArmor</link>
Mandatory Access Control system,
has been substantialy improved along with related tools,
so that module maintainers can now more easily write AppArmor profiles for NixOS.
The most notable change on the user-side is the new option <xref linkend="opt-security.apparmor.policies"/>,
replacing the previous <literal>profiles</literal> option
to provide a way to disable a profile
and to select whether to confine in enforce mode (default)
or in complain mode (see <literal>journalctl -b --grep apparmor</literal>).
Before enabling this module, either directly
or by importing <literal>&lt;nixpkgs/nixos/modules/profiles/hardened.nix&gt;</literal>,
please be sure to read the documentation of <link linkend="opt-security.apparmor.enable">security.apparmor.enable</link>,
and especially the part about <xref linkend="opt-security.apparmor.killUnconfinedConfinables"/>.
</para>
</listitem>
<listitem>
<para>
With this release <literal>systemd-networkd</literal> (when enabled through <xref linkend="opt-networking.useNetworkd"/>)

View file

@ -449,6 +449,40 @@ in
(mkIf cfg.enable {
environment.systemPackages = [ pkgs.fontconfig ];
environment.etc.fonts.source = "${fontconfigEtc}/etc/fonts/";
security.apparmor.includes."abstractions/fonts" = ''
# fonts.conf
r ${pkg.out}/etc/fonts/fonts.conf,
# fontconfig default config files
r ${pkg.out}/etc/fonts/conf.d/*.conf,
# 00-nixos-cache.conf
r ${cacheConf},
# 10-nixos-rendering.conf
r ${renderConf},
# 50-user.conf
${optionalString cfg.includeUserConf ''
r ${pkg.out}/etc/fonts/conf.d.bak/50-user.conf,
''}
# local.conf (indirect priority 51)
${optionalString (cfg.localConf != "") ''
r ${localConf},
''}
# 52-nixos-default-fonts.conf
r ${defaultFontsConf},
# 53-no-bitmaps.conf
r ${rejectBitmaps},
${optionalString (!cfg.allowType1) ''
# 53-nixos-reject-type1.conf
r ${rejectType1},
''}
'';
})
(mkIf cfg.enable {
fonts.fontconfig.confPackages = [ confPkg ];

View file

@ -87,5 +87,12 @@ in
environment.etc."ld-nix.so.preload".text = ''
${providerLibPath}
'';
security.apparmor.includes = {
"abstractions/base" = ''
r /etc/ld-nix.so.preload,
r ${config.environment.etc."ld-nix.so.preload".source},
mr ${providerLibPath},
'';
};
};
}

View file

@ -183,7 +183,6 @@
./rename.nix
./security/acme.nix
./security/apparmor.nix
./security/apparmor-suid.nix
./security/audit.nix
./security/auditd.nix
./security/ca.nix

View file

@ -1,49 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.security.apparmor;
in
with lib;
{
imports = [
(mkRenamedOptionModule [ "security" "virtualization" "flushL1DataCache" ] [ "security" "virtualisation" "flushL1DataCache" ])
];
options.security.apparmor.confineSUIDApplications = mkOption {
type = types.bool;
default = true;
description = ''
Install AppArmor profiles for commonly-used SUID application
to mitigate potential privilege escalation attacks due to bugs
in such applications.
Currently available profiles: ping
'';
};
config = mkIf (cfg.confineSUIDApplications) {
security.apparmor.profiles = [ (pkgs.writeText "ping" ''
#include <tunables/global>
/run/wrappers/bin/ping {
#include <abstractions/base>
#include <abstractions/consoles>
#include <abstractions/nameservice>
capability net_raw,
capability setuid,
network inet raw,
${pkgs.stdenv.cc.libc.out}/lib/*.so mr,
${pkgs.libcap.lib}/lib/libcap.so* mr,
${pkgs.attr.out}/lib/libattr.so* mr,
${pkgs.iputils}/bin/ping mixr,
#/etc/modules.conf r,
## Site-specific additions and overrides. See local/README for details.
##include <local/bin.ping>
}
'') ];
};
}

View file

@ -1,59 +1,198 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf mkOption types concatMapStrings;
inherit (builtins) attrNames head map match readFile;
inherit (lib) types;
inherit (config.environment) etc;
cfg = config.security.apparmor;
mkDisableOption = name: lib.mkEnableOption name // {
default = true;
example = false;
};
enabledPolicies = lib.filterAttrs (n: p: p.enable) cfg.policies;
in
{
options = {
security.apparmor = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable the AppArmor Mandatory Access Control system.";
};
profiles = mkOption {
type = types.listOf types.path;
default = [];
description = "List of files containing AppArmor profiles.";
};
packages = mkOption {
type = types.listOf types.package;
default = [];
description = "List of packages to be added to apparmor's include path";
};
};
};
imports = [
(lib.mkRenamedOptionModule [ "security" "virtualization" "flushL1DataCache" ] [ "security" "virtualisation" "flushL1DataCache" ])
(lib.mkRemovedOptionModule [ "security" "apparmor" "confineSUIDApplications" ] "Please use the new options: `security.apparmor.policies.<policy>.enable'.")
(lib.mkRemovedOptionModule [ "security" "apparmor" "profiles" ] "Please use the new option: `security.apparmor.policies'.")
apparmor/includes.nix
apparmor/profiles.nix
];
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.apparmor-utils ];
options = {
security.apparmor = {
enable = lib.mkEnableOption ''the AppArmor Mandatory Access Control system.
boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
If you're enabling this module on a running system,
note that a reboot will be required to activate AppArmor in the kernel.
systemd.services.apparmor = let
paths = concatMapStrings (s: " -I ${s}/etc/apparmor.d")
([ pkgs.apparmor-profiles ] ++ cfg.packages);
in {
after = [ "local-fs.target" ];
before = [ "sysinit.target" ];
wantedBy = [ "multi-user.target" ];
unitConfig = {
DefaultDependencies = "no";
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
ExecStart = map (p:
''${pkgs.apparmor-parser}/bin/apparmor_parser -rKv ${paths} "${p}"''
) cfg.profiles;
ExecStop = map (p:
''${pkgs.apparmor-parser}/bin/apparmor_parser -Rv "${p}"''
) cfg.profiles;
ExecReload = map (p:
''${pkgs.apparmor-parser}/bin/apparmor_parser --reload ${paths} "${p}"''
) cfg.profiles;
};
};
};
Also, beware that enabling this module will by default
try to kill unconfined but confinable running processes,
in order to obtain a confinement matching what is declared in the NixOS configuration.
This will happen when upgrading to a NixOS revision
introducing an AppArmor profile for the executable of a running process.
This is because enabling an AppArmor profile for an executable
can only confine new or already confined processes of that executable,
but leaves already running processes unconfined.
Set <link linkend="opt-security.apparmor.killUnconfinedConfinables">killUnconfinedConfinables</link>
to <literal>false</literal> if you prefer to leave those processes running'';
policies = lib.mkOption {
description = ''
AppArmor policies.
'';
type = types.attrsOf (types.submodule ({ name, config, ... }: {
options = {
enable = mkDisableOption "loading of the profile into the kernel";
enforce = mkDisableOption "enforcing of the policy or only complain in the logs";
profile = lib.mkOption {
description = "The policy of the profile.";
type = types.lines;
apply = pkgs.writeText name;
};
};
}));
default = {};
};
includes = lib.mkOption {
type = types.attrsOf types.lines;
default = {};
description = ''
List of paths to be added to AppArmor's searched paths
when resolving <literal>include</literal> directives.
'';
apply = lib.mapAttrs pkgs.writeText;
};
packages = lib.mkOption {
type = types.listOf types.package;
default = [];
description = "List of packages to be added to AppArmor's include path";
};
enableCache = lib.mkEnableOption ''caching of AppArmor policies
in <literal>/var/cache/apparmor/</literal>.
Beware that AppArmor policies almost always contain Nix store paths,
and thus produce at each change of these paths
a new cached version accumulating in the cache'';
killUnconfinedConfinables = mkDisableOption ''killing of processes
which have an AppArmor profile enabled
(in <link linkend="opt-security.apparmor.policies">policies</link>)
but are not confined (because AppArmor can only confine new processes).
Beware that due to a current limitation of AppArmor,
only profiles with exact paths (and no name) can enable such kills'';
};
};
config = lib.mkIf cfg.enable {
assertions = map (policy:
{ assertion = match ".*/.*" policy == null;
message = "`security.apparmor.policies.\"${policy}\"' must not contain a slash.";
# Because, for instance, aa-remove-unknown uses profiles_names_list() in rc.apparmor.functions
# which does not recurse into sub-directories.
}
) (attrNames cfg.policies);
environment.systemPackages = [ pkgs.apparmor-utils ];
environment.etc."apparmor.d".source = pkgs.linkFarm "apparmor.d" (
# It's important to put only enabledPolicies here and not all cfg.policies
# because aa-remove-unknown reads profiles from all /etc/apparmor.d/*
lib.mapAttrsToList (name: p: {inherit name; path=p.profile;}) enabledPolicies ++
lib.mapAttrsToList (name: path: {inherit name path;}) cfg.includes
);
environment.etc."apparmor/parser.conf".text = ''
${if cfg.enableCache then "write-cache" else "skip-cache"}
cache-loc /var/cache/apparmor
Include /etc/apparmor.d
'' +
lib.concatMapStrings (p: "Include ${p}/etc/apparmor.d\n") cfg.packages;
# For aa-logprof
environment.etc."apparmor/apparmor.conf".text = ''
'';
# For aa-logprof
environment.etc."apparmor/severity.db".source = pkgs.apparmor-utils + "/etc/apparmor/severity.db";
environment.etc."apparmor/logprof.conf".text = ''
[settings]
# /etc/apparmor.d/ is read-only on NixOS
profiledir = /var/cache/apparmor/logprof
inactive_profiledir = /etc/apparmor.d/disable
# Use: journalctl -b --since today --grep audit: | aa-logprof
logfiles = /dev/stdin
parser = ${pkgs.apparmor-parser}/bin/apparmor_parser
ldd = ${pkgs.glibc.bin}/bin/ldd
logger = ${pkgs.utillinux}/bin/logger
# customize how file ownership permissions are presented
# 0 - off
# 1 - default of what ever mode the log reported
# 2 - force the new permissions to be user
# 3 - force all perms on the rule to be user
default_owner_prompt = 1
custom_includes = /etc/apparmor.d ${lib.concatMapStringsSep " " (p: "${p}/etc/apparmor.d") cfg.packages}
[qualifiers]
${pkgs.runtimeShell} = icnu
${pkgs.bashInteractive}/bin/sh = icnu
${pkgs.bashInteractive}/bin/bash = icnu
'' + head (match "^.*\\[qualifiers](.*)" # Drop the original [settings] section.
(readFile "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf"));
boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
systemd.services.apparmor = {
after = [
"local-fs.target"
"systemd-journald-audit.socket"
];
before = [ "sysinit.target" ];
wantedBy = [ "multi-user.target" ];
unitConfig = {
Description="Load AppArmor policies";
DefaultDependencies = "no";
ConditionSecurity = "apparmor";
};
# Reloading instead of restarting enables to load new AppArmor profiles
# without necessarily restarting all services which have Requires=apparmor.service
reloadIfChanged = true;
restartTriggers = [
etc."apparmor/parser.conf".source
etc."apparmor.d".source
];
serviceConfig = let
killUnconfinedConfinables = pkgs.writeShellScript "apparmor-kill" ''
set -eu
${pkgs.apparmor-utils}/bin/aa-status --json |
${pkgs.jq}/bin/jq --raw-output '.processes | .[] | .[] | select (.status == "unconfined") | .pid' |
xargs --verbose --no-run-if-empty --delimiter='\n' \
kill
'';
commonOpts = p: "--verbose --show-cache ${lib.optionalString (!p.enforce) "--complain "}${p.profile}";
in {
Type = "oneshot";
RemainAfterExit = "yes";
ExecStartPre = "${pkgs.apparmor-utils}/bin/aa-teardown";
ExecStart = lib.mapAttrsToList (n: p: "${pkgs.apparmor-parser}/bin/apparmor_parser --add ${commonOpts p}") enabledPolicies;
ExecStartPost = lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
ExecReload =
# Add or replace into the kernel profiles in enabledPolicies
# (because AppArmor can do that without stopping the processes already confined).
lib.mapAttrsToList (n: p: "${pkgs.apparmor-parser}/bin/apparmor_parser --replace ${commonOpts p}") enabledPolicies ++
# Remove from the kernel any profile whose name is not
# one of the names within the content of the profiles in enabledPolicies
# (indirectly read from /etc/apparmor.d/*, without recursing into sub-directory).
# Note that this does not remove profiles dynamically generated by libvirt.
[ "${pkgs.apparmor-utils}/bin/aa-remove-unknown" ] ++
# Optionaly kill the processes which are unconfined but now have a profile loaded
# (because AppArmor can only start to confine new processes).
lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
ExecStop = "${pkgs.apparmor-utils}/bin/aa-teardown";
CacheDirectory = [ "apparmor" "apparmor/logprof" ];
CacheDirectoryMode = "0700";
};
};
};
meta.maintainers = with lib.maintainers; [ julm ];
}

View file

@ -0,0 +1,301 @@
{ config, lib, pkgs, ... }:
let
inherit (builtins) attrNames hasAttr isAttrs;
inherit (lib) getLib;
inherit (config.environment) etc;
etcRule = arg:
let go = {path ? null, mode ? "r", trail ? ""}:
lib.optionalString (hasAttr path etc)
"${mode} ${config.environment.etc.${path}.source}${trail},";
in if isAttrs arg
then go arg
else go {path=arg;};
in
{
# FIXME: most of the etcRule calls below have been
# written systematically by converting from apparmor-profiles's profiles
# without testing nor deep understanding of their uses,
# and thus may need more rules or can have less rules;
# this remains to be determined case by case,
# some may even be completely useless.
config.security.apparmor.includes = {
# This one is included by <tunables/global>
# which is usualy included before any profile.
"abstractions/tunables/alias" = ''
alias /bin -> /run/current-system/sw/bin,
alias /lib/modules -> /run/current-system/kernel/lib/modules,
alias /sbin -> /run/current-system/sw/sbin,
alias /usr -> /run/current-system/sw,
'';
"abstractions/audio" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/audio"
${etcRule "asound.conf"}
${etcRule "esound/esd.conf"}
${etcRule "libao.conf"}
${etcRule {path="pulse"; trail="/";}}
${etcRule {path="pulse"; trail="/**";}}
${etcRule {path="sound"; trail="/";}}
${etcRule {path="sound"; trail="/**";}}
${etcRule {path="alsa/conf.d"; trail="/";}}
${etcRule {path="alsa/conf.d"; trail="/*";}}
${etcRule "openal/alsoft.conf"}
${etcRule "wildmidi/wildmidi.conf"}
'';
"abstractions/authentication" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/authentication"
# Defined in security.pam
include <abstractions/pam>
${etcRule "nologin"}
${etcRule "securetty"}
${etcRule {path="security"; trail="/*";}}
${etcRule "shadow"}
${etcRule "gshadow"}
${etcRule "pwdb.conf"}
${etcRule "default/passwd"}
${etcRule "login.defs"}
'';
"abstractions/base" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/base"
r ${pkgs.stdenv.cc.libc}/share/locale/**,
r ${pkgs.stdenv.cc.libc}/share/locale.alias,
${lib.optionalString (pkgs.glibcLocales != null) "r ${pkgs.glibcLocales}/lib/locale/locale-archive,"}
${etcRule "localtime"}
r ${pkgs.tzdata}/share/zoneinfo/**,
r ${pkgs.stdenv.cc.libc}/share/i18n/**,
'';
"abstractions/bash" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/bash"
# system-wide bash configuration
${etcRule "profile.dos"}
${etcRule "profile"}
${etcRule "profile.d"}
${etcRule {path="profile.d"; trail="/*";}}
${etcRule "bashrc"}
${etcRule "bash.bashrc"}
${etcRule "bash.bashrc.local"}
${etcRule "bash_completion"}
${etcRule "bash_completion.d"}
${etcRule {path="bash_completion.d"; trail="/*";}}
# bash relies on system-wide readline configuration
${etcRule "inputrc"}
# bash inspects filesystems at startup
# and /etc/mtab is linked to /proc/mounts
@{PROC}/mounts
# run out of /etc/bash.bashrc
${etcRule "DIR_COLORS"}
'';
"abstractions/cups-client" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/cpus-client"
${etcRule "cups/cups-client.conf"}
'';
"abstractions/consoles" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/consoles"
'';
"abstractions/dbus-session-strict" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dbus-session-strict"
${etcRule "machine-id"}
'';
"abstractions/dconf" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dconf"
${etcRule {path="dconf"; trail="/**";}}
'';
"abstractions/dri-common" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dri-common"
${etcRule "drirc"}
'';
# The config.fonts.fontconfig NixOS module adds many files to /etc/fonts/
# by symlinking them but without exporting them outside of its NixOS module,
# those are therefore added there to this "abstractions/fonts".
"abstractions/fonts" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/fonts"
${etcRule {path="fonts"; trail="/**";}}
'';
"abstractions/gnome" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/gnome"
${etcRule {path="gnome"; trail="/gtkrc*";}}
${etcRule {path="gtk"; trail="/*";}}
${etcRule {path="gtk-2.0"; trail="/*";}}
${etcRule {path="gtk-3.0"; trail="/*";}}
${etcRule "orbitrc"}
include <abstractions/fonts>
${etcRule {path="pango"; trail="/*";}}
${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/";}}
${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/*";}}
${etcRule "papersize"}
${etcRule {path="cups"; trail="/lpoptions";}}
${etcRule {path="gnome"; trail="/defaults.list";}}
${etcRule {path="xdg"; trail="/{,*-}mimeapps.list";}}
${etcRule "xdg/mimeapps.list"}
'';
"abstractions/kde" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kde"
${etcRule {path="qt3"; trail="/kstylerc";}}
${etcRule {path="qt3"; trail="/qt_plugins_3.3rc";}}
${etcRule {path="qt3"; trail="/qtrc";}}
${etcRule "kderc"}
${etcRule {path="kde3"; trail="/*";}}
${etcRule "kde4rc"}
${etcRule {path="xdg"; trail="/kdeglobals";}}
${etcRule {path="xdg"; trail="/Trolltech.conf";}}
'';
"abstractions/kerberosclient" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kerberosclient"
${etcRule {path="krb5.keytab"; mode="rk";}}
${etcRule "krb5.conf"}
${etcRule "krb5.conf.d"}
${etcRule {path="krb5.conf.d"; trail="/*";}}
# config files found via strings on libs
${etcRule "krb.conf"}
${etcRule "krb.realms"}
${etcRule "srvtab"}
'';
"abstractions/ldapclient" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ldapclient"
${etcRule "ldap.conf"}
${etcRule "ldap.secret"}
${etcRule {path="openldap"; trail="/*";}}
${etcRule {path="openldap"; trail="/cacerts/*";}}
${etcRule {path="sasl2"; trail="/*";}}
'';
"abstractions/likewise" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/likewise"
'';
"abstractions/mdns" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/mdns"
${etcRule "nss_mdns.conf"}
'';
"abstractions/nameservice" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nameservice"
# Many programs wish to perform nameservice-like operations, such as
# looking up users by name or id, groups by name or id, hosts by name
# or IP, etc. These operations may be performed through files, dns,
# NIS, NIS+, LDAP, hesiod, wins, etc. Allow them all here.
${etcRule "group"}
${etcRule "host.conf"}
${etcRule "hosts"}
${etcRule "nsswitch.conf"}
${etcRule "gai.conf"}
${etcRule "passwd"}
${etcRule "protocols"}
# libtirpc (used for NIS/YP login) needs this
${etcRule "netconfig"}
${etcRule "resolv.conf"}
${etcRule {path="samba"; trail="/lmhosts";}}
${etcRule "services"}
${etcRule "default/nss"}
# libnl-3-200 via libnss-gw-name
${etcRule {path="libnl"; trail="/classid";}}
${etcRule {path="libnl-3"; trail="/classid";}}
mr ${getLib pkgs.nss}/lib/libnss_*.so*,
mr ${getLib pkgs.nss}/lib64/libnss_*.so*,
'';
"abstractions/nis" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nis"
'';
"abstractions/nvidia" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nvidia"
${etcRule "vdpau_wrapper.cfg"}
'';
"abstractions/opencl-common" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-common"
${etcRule {path="OpenCL"; trail="/**";}}
'';
"abstractions/opencl-mesa" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-mesa"
${etcRule "default/drirc"}
'';
"abstractions/openssl" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/openssl"
${etcRule {path="ssl"; trail="/openssl.cnf";}}
'';
"abstractions/p11-kit" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/p11-kit"
${etcRule {path="pkcs11"; trail="/";}}
${etcRule {path="pkcs11"; trail="/pkcs11.conf";}}
${etcRule {path="pkcs11"; trail="/modules/";}}
${etcRule {path="pkcs11"; trail="/modules/*";}}
'';
"abstractions/perl" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/perl"
${etcRule {path="perl"; trail="/**";}}
'';
"abstractions/php" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/php"
${etcRule {path="php"; trail="/**/";}}
${etcRule {path="php5"; trail="/**/";}}
${etcRule {path="php7"; trail="/**/";}}
${etcRule {path="php"; trail="/**.ini";}}
${etcRule {path="php5"; trail="/**.ini";}}
${etcRule {path="php7"; trail="/**.ini";}}
'';
"abstractions/postfix-common" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/postfix-common"
${etcRule "mailname"}
${etcRule {path="postfix"; trail="/*.cf";}}
${etcRule "postfix/main.cf"}
${etcRule "postfix/master.cf"}
'';
"abstractions/python" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/python"
'';
"abstractions/qt5" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/qt5"
${etcRule {path="xdg"; trail="/QtProject/qtlogging.ini";}}
${etcRule {path="xdg/QtProject"; trail="/qtlogging.ini";}}
${etcRule "xdg/QtProject/qtlogging.ini"}
'';
"abstractions/samba" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/samba"
${etcRule {path="samba"; trail="/*";}}
'';
"abstractions/ssl_certs" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ssl_certs"
${etcRule "ssl/certs/ca-certificates.crt"}
${etcRule "ssl/certs/ca-bundle.crt"}
${etcRule "pki/tls/certs/ca-bundle.crt"}
${etcRule {path="ssl/trust"; trail="/";}}
${etcRule {path="ssl/trust"; trail="/*";}}
${etcRule {path="ssl/trust/anchors"; trail="/";}}
${etcRule {path="ssl/trust/anchors"; trail="/**";}}
${etcRule {path="pki/trust"; trail="/";}}
${etcRule {path="pki/trust"; trail="/*";}}
${etcRule {path="pki/trust/anchors"; trail="/";}}
${etcRule {path="pki/trust/anchors"; trail="/**";}}
# security.acme NixOS module
r /var/lib/acme/*/cert.pem,
r /var/lib/acme/*/chain.pem,
r /var/lib/acme/*/fullchain.pem,
'';
"abstractions/ssl_keys" = ''
# security.acme NixOS module
r /var/lib/acme/*/full.pem,
r /var/lib/acme/*/key.pem,
'';
"abstractions/vulkan" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/vulkan"
${etcRule {path="vulkan/icd.d"; trail="/";}}
${etcRule {path="vulkan/icd.d"; trail="/*.json";}}
'';
"abstractions/winbind" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/winbind"
${etcRule {path="samba"; trail="/smb.conf";}}
${etcRule {path="samba"; trail="/dhcp.conf";}}
'';
"abstractions/X" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/X"
${etcRule {path="X11/cursors"; trail="/";}}
${etcRule {path="X11/cursors"; trail="/**";}}
'';
};
}

View file

@ -0,0 +1,11 @@
{ config, lib, pkgs, ... }:
let apparmor = config.security.apparmor; in
{
config.security.apparmor.packages = [ pkgs.apparmor-profiles ];
config.security.apparmor.policies."bin.ping".profile = lib.mkIf apparmor.policies."bin.ping".enable ''
include "${pkgs.iputils.apparmor}/bin.ping"
include "${pkgs.inetutils.apparmor}/bin.ping"
# Note that including those two profiles in the same profile
# would not work if the second one were to re-include <tunables/global>.
'';
}

View file

@ -836,6 +836,63 @@ in
runuser-l = { rootOK = true; unixAuth = false; };
};
security.apparmor.includes."abstractions/pam" = let
isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
in ''
${lib.concatMapStringsSep "\n"
(name: "r ${config.environment.etc."pam.d/${name}".source},")
(attrNames config.security.pam.services)}
mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
mr ${getLib pkgs.pam}/lib/security/pam_*.so,
r ${getLib pkgs.pam}/lib/security/,
${optionalString use_ldap
"mr ${pam_ldap}/lib/security/pam_ldap.so,"}
${optionalString config.services.sssd.enable
"mr ${pkgs.sssd}/lib/security/pam_sss.so,"}
${optionalString config.krb5.enable ''
mr ${pam_krb5}/lib/security/pam_krb5.so,
mr ${pam_ccreds}/lib/security/pam_ccreds.so,
''}
${optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,
mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so,
''}
${optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication))
"mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,"}
${optionalString (config.security.pam.enableSSHAgentAuth && isEnabled (cfg: cfg.sshAgentAuth))
"mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,"}
${optionalString (isEnabled (cfg: cfg.fprintAuth))
"mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,"}
${optionalString (isEnabled (cfg: cfg.u2fAuth))
"mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,"}
${optionalString (isEnabled (cfg: cfg.usbAuth))
"mr ${pkgs.pam_usb}/lib/security/pam_usb.so,"}
${optionalString (isEnabled (cfg: cfg.oathAuth))
"mr ${pkgs.oathToolkit}/lib/security/pam_oath.so,"}
${optionalString (isEnabled (cfg: cfg.yubicoAuth))
"mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,"}
${optionalString (isEnabled (cfg: cfg.duoSecurity.enable))
"mr ${pkgs.duo-unix}/lib/security/pam_duo.so,"}
${optionalString (isEnabled (cfg: cfg.otpwAuth))
"mr ${pkgs.otpw}/lib/security/pam_otpw.so,"}
${optionalString config.security.pam.enableEcryptfs
"mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,"}
${optionalString (isEnabled (cfg: cfg.pamMount))
"mr ${pkgs.pam_mount}/lib/security/pam_mount.so,"}
${optionalString config.services.samba.syncPasswordsByPam
"mr ${pkgs.samba}/lib/security/pam_smbpass.so,"}
${optionalString (isEnabled (cfg: cfg.enableGnomeKeyring))
"mr ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so,"}
${optionalString (isEnabled (cfg: cfg.startSession))
"mr ${pkgs.systemd}/lib/security/pam_systemd.so,"}
${optionalString (isEnabled (cfg: cfg.enableAppArmor) && config.security.apparmor.enable)
"mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,"}
${optionalString (isEnabled (cfg: cfg.enableKwallet))
"mr ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so,"}
${optionalString config.virtualisation.lxc.lxcfs.enable
"mr ${pkgs.lxc}/lib/security/pam_cgfs.so"}
'';
};
}

View file

@ -179,6 +179,14 @@ in
export PATH="${wrapperDir}:$PATH"
'';
security.apparmor.includes."nixos/security.wrappers" = ''
include "${pkgs.apparmorRulesFromClosure {} [
securityWrapper
pkgs.stdenv.cc.cc
pkgs.stdenv.cc.libc
]}"
'';
###### setcap activation script
system.activationScripts.wrappers =
lib.stringAfter [ "specialfs" "users" ]

View file

@ -5,7 +5,7 @@ with lib;
let
cfg = config.services.transmission;
inherit (config.environment) etc;
apparmor = config.security.apparmor.enable;
apparmor = config.security.apparmor;
rootDir = "/run/transmission";
homeDir = "/var/lib/transmission";
settingsDir = ".config/transmission-daemon";
@ -184,8 +184,8 @@ in
systemd.services.transmission = {
description = "Transmission BitTorrent Service";
after = [ "network.target" ] ++ optional apparmor "apparmor.service";
requires = optional apparmor "apparmor.service";
after = [ "network.target" ] ++ optional apparmor.enable "apparmor.service";
requires = optional apparmor.enable "apparmor.service";
wantedBy = [ "multi-user.target" ];
environment.CURL_CA_BUNDLE = etc."ssl/certs/ca-certificates.crt".source;
@ -357,61 +357,21 @@ in
})
];
security.apparmor.profiles = mkIf apparmor [
(pkgs.writeText "apparmor-transmission-daemon" ''
security.apparmor.policies."bin.transmission-daemon".profile = ''
include <tunables/global>
${pkgs.transmission}/bin/transmission-daemon {
include <abstractions/base>
include <abstractions/nameservice>
# NOTE: https://github.com/NixOS/nixpkgs/pull/93457
# will remove the need for these by fixing <abstractions/base>
r ${etc."hosts".source},
r /etc/ld-nix.so.preload,
${lib.optionalString (builtins.hasAttr "ld-nix.so.preload" etc) ''
r ${etc."ld-nix.so.preload".source},
${concatMapStrings (p: optionalString (p != "") ("mr ${p},\n"))
(splitString "\n" config.environment.etc."ld-nix.so.preload".text)}
''}
r ${etc."ssl/certs/ca-certificates.crt".source},
r ${pkgs.tzdata}/share/zoneinfo/**,
r ${pkgs.stdenv.cc.libc}/share/i18n/**,
r ${pkgs.stdenv.cc.libc}/share/locale/**,
mr ${getLib pkgs.stdenv.cc.cc}/lib/*.so*,
mr ${getLib pkgs.stdenv.cc.libc}/lib/*.so*,
mr ${getLib pkgs.attr}/lib/libattr*.so*,
mr ${getLib pkgs.c-ares}/lib/libcares*.so*,
mr ${getLib pkgs.curl}/lib/libcurl*.so*,
mr ${getLib pkgs.keyutils}/lib/libkeyutils*.so*,
mr ${getLib pkgs.libcap}/lib/libcap*.so*,
mr ${getLib pkgs.libevent}/lib/libevent*.so*,
mr ${getLib pkgs.libgcrypt}/lib/libgcrypt*.so*,
mr ${getLib pkgs.libgpgerror}/lib/libgpg-error*.so*,
mr ${getLib pkgs.libkrb5}/lib/lib*.so*,
mr ${getLib pkgs.libssh2}/lib/libssh2*.so*,
mr ${getLib pkgs.lz4}/lib/liblz4*.so*,
mr ${getLib pkgs.nghttp2}/lib/libnghttp2*.so*,
mr ${getLib pkgs.openssl}/lib/libcrypto*.so*,
mr ${getLib pkgs.openssl}/lib/libssl*.so*,
mr ${getLib pkgs.systemd}/lib/libsystemd*.so*,
mr ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so*,
mr ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so*,
mr ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so*,
mr ${getLib pkgs.xz}/lib/liblzma*.so*,
mr ${getLib pkgs.zlib}/lib/libz*.so*,
include <abstractions/ssl_certs>
include "${pkgs.apparmorRulesFromClosure {} [pkgs.transmission]}"
include <local/bin.transmission-daemon>
r @{PROC}/sys/kernel/random/uuid,
r @{PROC}/sys/vm/overcommit_memory,
# @{pid} is not a kernel variable yet but a regexp
#r @{PROC}/@{pid}/environ,
r @{PROC}/@{pid}/environ,
r @{PROC}/@{pid}/mounts,
rwk /tmp/tr_session_id_*,
r ${pkgs.openssl.out}/etc/**,
r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE},
r ${pkgs.transmission}/share/transmission/**,
owner rw ${cfg.home}/${settingsDir}/**,
rw ${cfg.settings.download-dir}/**,
@ -439,12 +399,9 @@ in
# https://gitlab.com/apparmor/apparmor/-/wikis/AppArmorStacking#seccomp-and-no_new_privs
px ${cfg.settings.script-torrent-done-filename} -> &@{dirs},
''}
# FIXME: enable customizing using https://github.com/NixOS/nixpkgs/pull/93457
# include <local/transmission-daemon>
}
'')
];
'';
security.apparmor.includes."local/bin.transmission-daemon" = "";
};
meta.maintainers = with lib.maintainers; [ julm ];

View file

@ -1089,6 +1089,21 @@ in
} else {
ping.source = "${pkgs.iputils.out}/bin/ping";
};
security.apparmor.policies."bin.ping".profile = lib.mkIf config.security.apparmor.policies."bin.ping".enable (lib.mkAfter ''
/run/wrappers/bin/ping {
include <abstractions/base>
include <nixos/security.wrappers>
rpx /run/wrappers/wrappers.*/ping,
}
/run/wrappers/wrappers.*/ping {
include <abstractions/base>
include <nixos/security.wrappers>
r /run/wrappers/wrappers.*/ping.real,
mrpx ${config.security.wrappers.ping.source},
capability net_raw,
capability setpcap,
}
'');
# Set the host and domain names in the activation script. Don't
# clear it if it's not configured in the NixOS configuration,

View file

@ -74,9 +74,13 @@ in
systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
security.apparmor.packages = [ pkgs.lxc ];
security.apparmor.profiles = [
"${pkgs.lxc}/etc/apparmor.d/lxc-containers"
"${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start"
];
security.apparmor.policies = {
"bin.lxc-start".profile = ''
include ${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start
'';
"lxc-containers".profile = ''
include ${pkgs.lxc}/etc/apparmor.d/lxc-containers
'';
};
};
}

View file

@ -93,11 +93,15 @@ in
security.apparmor = {
enable = true;
profiles = [
"${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start"
"${cfg.lxcPackage}/etc/apparmor.d/lxc-containers"
];
packages = [ cfg.lxcPackage ];
policies = {
"bin.lxc-start".profile = ''
include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start
'';
"lxc-containers".profile = ''
include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
'';
};
};
systemd.services.lxd = {

View file

@ -10,6 +10,13 @@
, pam
, libnotify
, buildPackages
, coreutils
, gnugrep
, gnused
, kmod
, writeShellScript
, closureInfo
, runCommand
}:
let
@ -38,6 +45,12 @@ let
sha256 = "0xw028iqp69j9mxv0kbwraplgkj5i5djdlgf0anpkc5cdbsf96r9";
};
aa-teardown = writeShellScript "aa-teardown" ''
PATH="${lib.makeBinPath [coreutils gnused gnugrep]}:$PATH"
. ${apparmor-parser}/lib/apparmor/rc.apparmor.functions
remove_profiles
'';
prePatchCommon = ''
patch -p1 < ${gnumake43Patch}
chmod a+x ./common/list_capabilities.sh ./common/list_af_names.sh
@ -149,6 +162,15 @@ let
# aa-notify checks its name and does not work named ".aa-notify-wrapped"
mv $out/bin/aa-notify $out/bin/aa-notify-wrapped
makeWrapper ${perl}/bin/perl $out/bin/aa-notify --set PERL5LIB ${libapparmor}/${perl.libPrefix} --add-flags $out/bin/aa-notify-wrapped
substituteInPlace $out/bin/aa-remove-unknown \
--replace "/usr/bin/aa-status" "$out/bin/aa-status" \
--replace "/sbin/modprobe" "${kmod}/bin/modprobe" \
--replace "/lib/apparmor/rc.apparmor.functions" "${apparmor-parser}/lib/apparmor/rc.apparmor.functions"
wrapProgram $out/bin/aa-remove-unknown \
--prefix PATH : ${lib.makeBinPath [gawk]}
ln -s ${aa-teardown} $out/bin/aa-teardown
'';
inherit doCheck;
@ -197,6 +219,9 @@ let
substituteInPlace ./parser/Makefile --replace "/usr/include/linux/capability.h" "${linuxHeaders}/include/linux/capability.h"
## techdoc.pdf still doesn't build ...
substituteInPlace ./parser/Makefile --replace "manpages htmlmanpages pdf" "manpages htmlmanpages"
substituteInPlace parser/rc.apparmor.functions \
--replace "/sbin/apparmor_parser" "$out/bin/apparmor_parser"
sed -i parser/rc.apparmor.functions -e '2i . ${./fix-rc.apparmor.functions.sh}'
'';
inherit patches;
postPatch = "cd ./parser";
@ -258,8 +283,32 @@ let
meta = apparmor-meta "kernel patches";
};
# Generate generic AppArmor rules in a file,
# from the closure of given rootPaths.
# To be included in an AppArmor profile like so:
# include "$(apparmorRulesFromClosure {} [pkgs.hello]}"
apparmorRulesFromClosure =
{ # The store path of the derivation is given in $path
additionalRules ? []
# TODO: factorize here some other common paths
# that may emerge from use cases.
, baseRules ? [
"r $path"
"r $path/etc/**"
"r $path/share/**"
# Note that not all libraries are prefixed with "lib",
# eg. glibc-2.30/lib/ld-2.30.so
"mr $path/lib/**.so*"
# eg. glibc-2.30/lib/gconv/gconv-modules
"r $path/lib/**"
]
}: rootPaths: runCommand "apparmor-closure-rules" {} ''
touch $out
while read -r path
do printf >>$out "%s,\n" ${lib.concatMapStringsSep " " (x: "\"${x}\"") (baseRules ++ additionalRules)}
done <${closureInfo {inherit rootPaths;}}/store-paths
'';
in
{
inherit
libapparmor
@ -268,5 +317,6 @@ in
apparmor-parser
apparmor-pam
apparmor-profiles
apparmor-kernel-patches;
apparmor-kernel-patches
apparmorRulesFromClosure;
}

View file

@ -0,0 +1,32 @@
aa_action() {
STRING=$1
shift
$*
rc=$?
if [ $rc -eq 0 ] ; then
aa_log_success_msg $"$STRING "
else
aa_log_failure_msg $"$STRING "
fi
return $rc
}
aa_log_success_msg() {
[ -n "$1" ] && echo -n $1
echo ": done."
}
aa_log_warning_msg() {
[ -n "$1" ] && echo -n $1
echo ": Warning."
}
aa_log_failure_msg() {
[ -n "$1" ] && echo -n $1
echo ": Failed."
}
aa_log_skipped_msg() {
[ -n "$1" ] && echo -n $1
echo ": Skipped."
}

View file

@ -1,6 +1,7 @@
{ stdenv, fetchFromGitHub
, meson, ninja, pkgconfig, gettext, libxslt, docbook_xsl_ns
, libcap, systemd, libidn2
, apparmorRulesFromClosure
}:
with stdenv.lib;
@ -22,6 +23,8 @@ in stdenv.mkDerivation rec {
sha256 = "1jhbcz75a4ij1myyyi110ma1d8d5hpm3scz9pyw7js6qym50xvh4";
};
outputs = ["out" "apparmor"];
mesonFlags = [
"-DBUILD_RARPD=true"
"-DBUILD_TRACEROUTE6=true"
@ -35,6 +38,25 @@ in stdenv.mkDerivation rec {
nativeBuildInputs = [ meson ninja pkgconfig gettext libxslt.bin docbook_xsl_ns ];
buildInputs = [ libcap systemd ]
++ optional (!stdenv.hostPlatform.isMusl) libidn2;
postInstall = ''
install -D /dev/stdin $apparmor/bin.ping <<EOF
include <tunables/global>
$out/bin/ping {
include <abstractions/base>
include <abstractions/consoles>
include <abstractions/nameservice>
include "${apparmorRulesFromClosure {}
([libcap] ++ optional (!stdenv.hostPlatform.isMusl) libidn2)}"
include <local/bin.ping>
capability net_raw,
network inet raw,
network inet6 raw,
mr $out/bin/ping,
r $out/share/locale/**,
r @{PROC}/@{pid}/environ,
}
EOF
'';
meta = {
description = "A set of small useful utilities for Linux networking";

View file

@ -1,4 +1,6 @@
{ stdenv, lib, fetchurl, ncurses, perl, help2man }:
{ stdenv, lib, fetchurl, ncurses, perl, help2man
, apparmorRulesFromClosure
}:
stdenv.mkDerivation rec {
name = "inetutils-1.9.4";
@ -8,6 +10,8 @@ stdenv.mkDerivation rec {
sha256 = "05n65k4ixl85dc6rxc51b1b732gnmm8xnqi424dy9f1nz7ppb3xy";
};
outputs = ["out" "apparmor"];
patches = [
./whois-Update-Canadian-TLD-server.patch
./service-name.patch
@ -41,6 +45,22 @@ stdenv.mkDerivation rec {
installFlags = [ "SUIDMODE=" ];
postInstall = ''
install -D /dev/stdin $apparmor/bin.ping <<EOF
$out/bin/ping {
include <abstractions/base>
include <abstractions/consoles>
include <abstractions/nameservice>
include "${apparmorRulesFromClosure {} [stdenv.cc.libc]}"
include <local/bin.ping>
capability net_raw,
network inet raw,
network inet6 raw,
mr $out/bin/ping,
}
EOF
'';
meta = with lib; {
description = "Collection of common network programs";

View file

@ -17150,7 +17150,7 @@ in
inherit (callPackages ../os-specific/linux/apparmor { python = python3; })
libapparmor apparmor-utils apparmor-bin-utils apparmor-parser apparmor-pam
apparmor-profiles apparmor-kernel-patches;
apparmor-profiles apparmor-kernel-patches apparmorRulesFromClosure;
atop = callPackage ../os-specific/linux/atop { };