Merge pull request #101071 from ju1m/apparmor

apparmor: try again to fix and improve
master
Michael Raskin 2021-04-24 11:24:26 +00:00 committed by GitHub
commit d04f1c4314
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 999 additions and 217 deletions

View File

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

View File

@ -868,6 +868,23 @@ environment.systemPackages = [
Note that users defined with an explicit UID below 500 are exempted from this check, as <xref linkend="opt-users.users._name_.isSystemUser" /> has no effect for those.
</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>).
Security-minded users may also want to enable <xref linkend="opt-security.apparmor.killUnconfinedConfinables"/>,
at the cost of having some of their processes killed
when updating to a NixOS version introducing new AppArmor profiles.
</para>
</listitem>
<listitem>
<para>
The GNOME desktop manager once again installs <package>gnome3.epiphany</package> by default.

View File

@ -448,6 +448,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

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

View File

@ -36,6 +36,7 @@ with lib;
security.virtualisation.flushL1DataCache = mkDefault "always";
security.apparmor.enable = mkDefault true;
security.apparmor.killUnconfinedConfinables = mkDefault true;
boot.kernelParams = [
# Slab/slub sanity checks, redzoning, and poisoning

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,216 @@
{ config, lib, pkgs, ... }:
with lib;
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: mkEnableOption name // {
default = true;
example = false;
};
enabledPolicies = 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 = [
(mkRemovedOptionModule [ "security" "apparmor" "confineSUIDApplications" ] "Please use the new options: `security.apparmor.policies.<policy>.enable'.")
(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 = 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 privileges stability over security
by not trying to kill unconfined but newly confinable running processes by default,
though it would be needed because AppArmor can only confine new
or already confined processes of an executable.
This killing would for instance be necessary when upgrading to a NixOS revision
introducing for the first time an AppArmor profile for the executable
of a running process.
Enable <xref linkend="opt-security.apparmor.killUnconfinedConfinables"/>
if you want this service to do such killing
by sending a <literal>SIGTERM</literal> to those running processes'';
policies = 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 = mkOption {
description = "The policy of the profile.";
type = types.lines;
apply = pkgs.writeText name;
};
};
}));
default = {};
};
includes = 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 = mapAttrs pkgs.writeText;
};
packages = mkOption {
type = types.listOf types.package;
default = [];
description = "List of packages to be added to AppArmor's include path";
};
enableCache = 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 = mkEnableOption ''
killing of processes which have an AppArmor profile enabled
(in <xref linkend="opt-security.apparmor.policies"/>)
but are not confined (because AppArmor can only confine new processes).
This is only sending a gracious <literal>SIGTERM</literal> signal to the processes,
not a <literal>SIGKILL</literal>.
Beware that due to a current limitation of AppArmor,
only profiles with exact paths (and no name) can enable such kills'';
};
};
config = 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
pkgs.apparmor-bin-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/*
mapAttrsToList (name: p: { inherit name; path = p.profile; }) enabledPolicies ++
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
'' +
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".source = pkgs.runCommand "logprof.conf" {
header = ''
[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 ${concatMapStringsSep " " (p: "${p}/etc/apparmor.d") cfg.packages}
[qualifiers]
${pkgs.runtimeShell} = icnu
${pkgs.bashInteractive}/bin/sh = icnu
${pkgs.bashInteractive}/bin/bash = icnu
${config.users.defaultUserShell} = icnu
'';
footer = "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf";
passAsFile = [ "header" ];
} ''
cp $headerPath $out
sed '1,/\[qualifiers\]/d' $footer >> $out
'';
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-bin-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 ${optionalString (!p.enforce) "--complain "}${p.profile}";
in {
Type = "oneshot";
RemainAfterExit = "yes";
ExecStartPre = "${pkgs.apparmor-utils}/bin/aa-teardown";
ExecStart = mapAttrsToList (n: p: "${pkgs.apparmor-parser}/bin/apparmor_parser --add ${commonOpts p}") enabledPolicies;
ExecStartPost = 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).
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).
optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
ExecStop = "${pkgs.apparmor-utils}/bin/aa-teardown";
CacheDirectory = [ "apparmor" "apparmor/logprof" ];
CacheDirectoryMode = "0700";
};
};
};
meta.maintainers = with maintainers; [ julm ];
}

View File

@ -0,0 +1,317 @@
{ config, lib, pkgs, ... }:
let
inherit (builtins) attrNames hasAttr isAttrs;
inherit (lib) getLib;
inherit (config.environment) etc;
# Utility to generate an AppArmor rule
# only when the given path exists in 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"
'' + lib.concatMapStringsSep "\n" etcRule [
"asound.conf"
"esound/esd.conf"
"libao.conf"
{ path = "pulse"; trail = "/"; }
{ path = "pulse"; trail = "/**"; }
{ path = "sound"; trail = "/"; }
{ path = "sound"; trail = "/**"; }
{ path = "alsa/conf.d"; trail = "/"; }
{ path = "alsa/conf.d"; trail = "/*"; }
"openal/alsoft.conf"
"wildmidi/wildmidi.conf"
];
"abstractions/authentication" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/authentication"
# Defined in security.pam
include <abstractions/pam>
'' + lib.concatMapStringsSep "\n" etcRule [
"nologin"
"securetty"
{ path = "security"; trail = "/*"; }
"shadow"
"gshadow"
"pwdb.conf"
"default/passwd"
"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"
# bash inspects filesystems at startup
# and /etc/mtab is linked to /proc/mounts
@{PROC}/mounts
# system-wide bash configuration
'' + lib.concatMapStringsSep "\n" etcRule [
"profile.dos"
"profile"
"profile.d"
{ path = "profile.d"; trail = "/*"; }
"bashrc"
"bash.bashrc"
"bash.bashrc.local"
"bash_completion"
"bash_completion.d"
{ path = "bash_completion.d"; trail = "/*"; }
# bash relies on system-wide readline configuration
"inputrc"
# run out of /etc/bash.bashrc
"DIR_COLORS"
];
"abstractions/consoles" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/consoles"
'';
"abstractions/cups-client" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/cpus-client"
${etcRule "cups/cups-client.conf"}
'';
"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"
include <abstractions/fonts>
'' + lib.concatMapStringsSep "\n" etcRule [
{ path = "gnome"; trail = "/gtkrc*"; }
{ path = "gtk"; trail = "/*"; }
{ path = "gtk-2.0"; trail = "/*"; }
{ path = "gtk-3.0"; trail = "/*"; }
"orbitrc"
{ path = "pango"; trail = "/*"; }
{ path = "/etc/gnome-vfs-2.0"; trail = "/modules/"; }
{ path = "/etc/gnome-vfs-2.0"; trail = "/modules/*"; }
"papersize"
{ path = "cups"; trail = "/lpoptions"; }
{ path = "gnome"; trail = "/defaults.list"; }
{ path = "xdg"; trail = "/{,*-}mimeapps.list"; }
"xdg/mimeapps.list"
];
"abstractions/kde" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kde"
'' + lib.concatMapStringsSep "\n" etcRule [
{ path = "qt3"; trail = "/kstylerc"; }
{ path = "qt3"; trail = "/qt_plugins_3.3rc"; }
{ path = "qt3"; trail = "/qtrc"; }
"kderc"
{ path = "kde3"; trail = "/*"; }
"kde4rc"
{ path = "xdg"; trail = "/kdeglobals"; }
{ path = "xdg"; trail = "/Trolltech.conf"; }
];
"abstractions/kerberosclient" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kerberosclient"
'' + lib.concatMapStringsSep "\n" etcRule [
{ path = "krb5.keytab"; mode="rk"; }
"krb5.conf"
"krb5.conf.d"
{ path = "krb5.conf.d"; trail = "/*"; }
# config files found via strings on libs
"krb.conf"
"krb.realms"
"srvtab"
];
"abstractions/ldapclient" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ldapclient"
'' + lib.concatMapStringsSep "\n" etcRule [
"ldap.conf"
"ldap.secret"
{ path = "openldap"; trail = "/*"; }
{ path = "openldap"; trail = "/cacerts/*"; }
{ 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.
mr ${getLib pkgs.nss}/lib/libnss_*.so*,
mr ${getLib pkgs.nss}/lib64/libnss_*.so*,
'' + lib.concatMapStringsSep "\n" etcRule [
"group"
"host.conf"
"hosts"
"nsswitch.conf"
"gai.conf"
"passwd"
"protocols"
# libtirpc (used for NIS/YP login) needs this
"netconfig"
"resolv.conf"
{ path = "samba"; trail = "/lmhosts"; }
"services"
"default/nss"
# libnl-3-200 via libnss-gw-name
{ path = "libnl"; trail = "/classid"; }
{ path = "libnl-3"; trail = "/classid"; }
];
"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"
'' + lib.concatMapStringsSep "\n" etcRule [
{ path = "pkcs11"; trail = "/"; }
{ path = "pkcs11"; trail = "/pkcs11.conf"; }
{ path = "pkcs11"; trail = "/modules/"; }
{ 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"
'' + lib.concatMapStringsSep "\n" etcRule [
{ path = "php"; trail = "/**/"; }
{ path = "php5"; trail = "/**/"; }
{ path = "php7"; trail = "/**/"; }
{ path = "php"; trail = "/**.ini"; }
{ path = "php5"; trail = "/**.ini"; }
{ path = "php7"; trail = "/**.ini"; }
];
"abstractions/postfix-common" = ''
include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/postfix-common"
'' + lib.concatMapStringsSep "\n" etcRule [
"mailname"
{ path = "postfix"; trail = "/*.cf"; }
"postfix/main.cf"
"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"
'' + lib.concatMapStringsSep "\n" etcRule [
{ path = "xdg"; trail = "/QtProject/qtlogging.ini"; }
{ path = "xdg/QtProject"; trail = "/qtlogging.ini"; }
"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"
# For the NixOS module: security.acme
r /var/lib/acme/*/cert.pem,
r /var/lib/acme/*/chain.pem,
r /var/lib/acme/*/fullchain.pem,
'' + lib.concatMapStringsSep "\n" etcRule [
"ssl/certs/ca-certificates.crt"
"ssl/certs/ca-bundle.crt"
"pki/tls/certs/ca-bundle.crt"
{ path = "ssl/trust"; trail = "/"; }
{ path = "ssl/trust"; trail = "/*"; }
{ path = "ssl/trust/anchors"; trail = "/"; }
{ path = "ssl/trust/anchors"; trail = "/**"; }
{ path = "pki/trust"; trail = "/"; }
{ path = "pki/trust"; trail = "/*"; }
{ path = "pki/trust/anchors"; trail = "/"; }
{ path = "pki/trust/anchors"; trail = "/**"; }
];
"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

@ -7,6 +7,10 @@ with lib;
maintainers = [ maintainers.joachifm ];
};
imports = [
(lib.mkRenamedOptionModule [ "security" "virtualization" "flushL1DataCache" ] [ "security" "virtualisation" "flushL1DataCache" ])
];
options = {
security.allowUserNamespaces = mkOption {
type = types.bool;

View File

@ -895,6 +895,81 @@ 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 (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

@ -171,6 +171,14 @@ in
export PATH="${wrapperDir}:$PATH"
'';
security.apparmor.includes."nixos/security.wrappers" = ''
include "${pkgs.apparmorRulesFromClosure { name="security.wrappers"; } [
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;
@ -358,95 +358,39 @@ in
})
];
security.apparmor.profiles = mkIf apparmor [
(pkgs.writeText "apparmor-transmission-daemon" ''
include <tunables/global>
security.apparmor.policies."bin.transmission-daemon".profile = ''
include "${pkgs.transmission.apparmor}/bin.transmission-daemon"
'';
security.apparmor.includes."local/bin.transmission-daemon" = ''
r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE},
${pkgs.transmission}/bin/transmission-daemon {
include <abstractions/base>
include <abstractions/nameservice>
owner rw ${cfg.home}/${settingsDir}/**,
rw ${cfg.settings.download-dir}/**,
${optionalString cfg.settings.incomplete-dir-enabled ''
rw ${cfg.settings.incomplete-dir}/**,
''}
${optionalString cfg.settings.watch-dir-enabled ''
rw ${cfg.settings.watch-dir}/**,
''}
profile dirs {
rw ${cfg.settings.download-dir}/**,
${optionalString cfg.settings.incomplete-dir-enabled ''
rw ${cfg.settings.incomplete-dir}/**,
''}
${optionalString cfg.settings.watch-dir-enabled ''
rw ${cfg.settings.watch-dir}/**,
''}
}
# 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.util-linuxMinimal.out}/lib/libblkid.so*,
mr ${getLib pkgs.util-linuxMinimal.out}/lib/libmount.so*,
mr ${getLib pkgs.util-linuxMinimal.out}/lib/libuuid.so*,
mr ${getLib pkgs.xz}/lib/liblzma*.so*,
mr ${getLib pkgs.zlib}/lib/libz*.so*,
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}/mounts,
rwk /tmp/tr_session_id_*,
r /run/systemd/resolve/stub-resolv.conf,
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}/**,
${optionalString cfg.settings.incomplete-dir-enabled ''
rw ${cfg.settings.incomplete-dir}/**,
''}
${optionalString cfg.settings.watch-dir-enabled ''
rw ${cfg.settings.watch-dir}/**,
''}
profile dirs {
rw ${cfg.settings.download-dir}/**,
${optionalString cfg.settings.incomplete-dir-enabled ''
rw ${cfg.settings.incomplete-dir}/**,
''}
${optionalString cfg.settings.watch-dir-enabled ''
rw ${cfg.settings.watch-dir}/**,
''}
}
${optionalString (cfg.settings.script-torrent-done-enabled &&
cfg.settings.script-torrent-done-filename != "") ''
# Stack transmission_directories profile on top of
# any existing profile for script-torrent-done-filename
# FIXME: to be tested as I'm not sure it works well with NoNewPrivileges=
# 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>
}
'')
];
${optionalString (cfg.settings.script-torrent-done-enabled &&
cfg.settings.script-torrent-done-filename != "") ''
# Stack transmission_directories profile on top of
# any existing profile for script-torrent-done-filename
# FIXME: to be tested as I'm not sure it works well with NoNewPrivileges=
# https://gitlab.com/apparmor/apparmor/-/wikis/AppArmorStacking#seccomp-and-no_new_privs
px ${cfg.settings.script-torrent-done-filename} -> &@{dirs},
''}
'';
};
meta.maintainers = with lib.maintainers; [ julm ];

View File

@ -1111,6 +1111,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

@ -97,11 +97,17 @@ in {
# does a bunch of unrelated things.
systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
security.apparmor.packages = [ cfg.lxcPackage ];
security.apparmor.profiles = [
"${cfg.lxcPackage}/etc/apparmor.d/lxc-containers"
"${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start"
];
security.apparmor = {
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
'';
};
};
# TODO: remove once LXD gets proper support for cgroupsv2
# (currently most of the e.g. CPU accounting stuff doesn't work)

View File

@ -25,6 +25,7 @@ in
acme = handleTest ./acme.nix {};
agda = handleTest ./agda.nix {};
ammonite = handleTest ./ammonite.nix {};
apparmor = handleTest ./apparmor.nix {};
atd = handleTest ./atd.nix {};
avahi = handleTest ./avahi.nix {};
avahi-with-resolved = handleTest ./avahi.nix { networkd = true; };

82
nixos/tests/apparmor.nix Normal file
View File

@ -0,0 +1,82 @@
import ./make-test-python.nix ({ pkgs, ... } : {
name = "apparmor";
meta = with pkgs.lib.maintainers; {
maintainers = [ julm ];
};
machine =
{ lib, pkgs, config, ... }:
with lib;
{
security.apparmor.enable = mkDefault true;
};
testScript =
''
machine.wait_for_unit("multi-user.target")
with subtest("AppArmor profiles are loaded"):
machine.succeed("systemctl status apparmor.service")
# AppArmor securityfs
with subtest("AppArmor securityfs is mounted"):
machine.succeed("mountpoint -q /sys/kernel/security")
machine.succeed("cat /sys/kernel/security/apparmor/profiles")
# Test apparmorRulesFromClosure by:
# 1. Prepending a string of the relevant packages' name and version on each line.
# 2. Sorting according to those strings.
# 3. Removing those prepended strings.
# 4. Using `diff` against the expected output.
with subtest("apparmorRulesFromClosure"):
machine.succeed(
"${pkgs.diffutils}/bin/diff ${pkgs.writeText "expected.rules" ''
mr ${pkgs.bash}/lib/**.so*,
r ${pkgs.bash},
r ${pkgs.bash}/etc/**,
r ${pkgs.bash}/lib/**,
r ${pkgs.bash}/share/**,
x ${pkgs.bash}/foo/**,
mr ${pkgs.glibc}/lib/**.so*,
r ${pkgs.glibc},
r ${pkgs.glibc}/etc/**,
r ${pkgs.glibc}/lib/**,
r ${pkgs.glibc}/share/**,
x ${pkgs.glibc}/foo/**,
mr ${pkgs.libcap}/lib/**.so*,
r ${pkgs.libcap},
r ${pkgs.libcap}/etc/**,
r ${pkgs.libcap}/lib/**,
r ${pkgs.libcap}/share/**,
x ${pkgs.libcap}/foo/**,
mr ${pkgs.libcap.lib}/lib/**.so*,
r ${pkgs.libcap.lib},
r ${pkgs.libcap.lib}/etc/**,
r ${pkgs.libcap.lib}/lib/**,
r ${pkgs.libcap.lib}/share/**,
x ${pkgs.libcap.lib}/foo/**,
mr ${pkgs.libidn2.out}/lib/**.so*,
r ${pkgs.libidn2.out},
r ${pkgs.libidn2.out}/etc/**,
r ${pkgs.libidn2.out}/lib/**,
r ${pkgs.libidn2.out}/share/**,
x ${pkgs.libidn2.out}/foo/**,
mr ${pkgs.libunistring}/lib/**.so*,
r ${pkgs.libunistring},
r ${pkgs.libunistring}/etc/**,
r ${pkgs.libunistring}/lib/**,
r ${pkgs.libunistring}/share/**,
x ${pkgs.libunistring}/foo/**,
''} ${pkgs.runCommand "actual.rules" { preferLocalBuild = true; } ''
${pkgs.gnused}/bin/sed -e 's:^[^ ]* ${builtins.storeDir}/[^,/-]*-\([^/,]*\):\1 \0:' ${
pkgs.apparmorRulesFromClosure {
name = "ping";
additionalRules = ["x $path/foo/**"];
} [ pkgs.libcap ]
} |
${pkgs.coreutils}/bin/sort -n -k1 |
${pkgs.gnused}/bin/sed -e 's:^[^ ]* ::' >$out
''}"
)
'';
})

View File

@ -21,6 +21,7 @@
, enableDaemon ? true
, enableCli ? true
, installLib ? false
, apparmorRulesFromClosure
}:
let
@ -38,6 +39,8 @@ in stdenv.mkDerivation {
fetchSubmodules = true;
};
outputs = [ "out" "apparmor" ];
cmakeFlags =
let
mkFlag = opt: if opt then "ON" else "OFF";
@ -74,6 +77,30 @@ in stdenv.mkDerivation {
NIX_LDFLAGS = lib.optionalString stdenv.isDarwin "-framework CoreFoundation";
postInstall = ''
install -D -m 644 /dev/stdin $apparmor/bin.transmission-daemon <<EOF
include <tunables/global>
$out/bin/transmission-daemon {
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/ssl_certs>
include "${apparmorRulesFromClosure { name = "transmission-daemon"; } ([
curl libevent openssl pcre zlib
] ++ lib.optionals enableSystemd [ systemd ]
++ lib.optionals stdenv.isLinux [ inotify-tools ]
)}"
r @{PROC}/sys/kernel/random/uuid,
r @{PROC}/sys/vm/overcommit_memory,
r @{PROC}/@{pid}/environ,
r @{PROC}/@{pid}/mounts,
rwk /tmp/tr_session_id_*,
r /run/systemd/resolve/stub-resolv.conf,
include <local/bin.transmission-daemon>
}
EOF
'';
meta = {
description = "A fast, easy and free BitTorrent client";
longDescription = ''

View File

@ -10,26 +10,37 @@
, pam
, libnotify
, buildPackages
, coreutils
, gnugrep
, gnused
, kmod
, writeShellScript
, closureInfo
, runCommand
}:
let
apparmor-series = "2.13";
apparmor-patchver = "6";
apparmor-version = apparmor-series + "." + apparmor-patchver;
apparmor-version = "3.0.1";
apparmor-meta = component: with lib; {
homepage = "https://apparmor.net/";
description = "A mandatory access control system - ${component}";
license = licenses.gpl2;
maintainers = with maintainers; [ phreedom thoughtpolice joachifm ];
maintainers = with maintainers; [ joachifm julm phreedom thoughtpolice ];
platforms = platforms.linux;
};
apparmor-sources = fetchurl {
url = "https://launchpad.net/apparmor/${apparmor-series}/${apparmor-version}/+download/apparmor-${apparmor-version}.tar.gz";
sha256 = "13xshy7905d9q9n8d8i0jmdi9m36wr525g4wlsp8k21n7yvvh9j4";
url = "https://launchpad.net/apparmor/${lib.versions.majorMinor apparmor-version}/${apparmor-version}/+download/apparmor-${apparmor-version}.tar.gz";
sha256 = "096zbg3v7b51x7f1ly61mzd3iy9alad6sd4lam98j2d6v5ragbcg";
};
aa-teardown = writeShellScript "aa-teardown" ''
PATH="${lib.makeBinPath [coreutils gnused gnugrep]}:$PATH"
. ${apparmor-parser}/lib/apparmor/rc.apparmor.functions
remove_profiles
'';
prePatchCommon = ''
chmod a+x ./common/list_capabilities.sh ./common/list_af_names.sh
patchShebangs ./common/list_capabilities.sh ./common/list_af_names.sh
@ -45,12 +56,6 @@ let
name = "0003-Added-missing-typedef-definitions-on-parser.patch";
sha256 = "0yyaqz8jlmn1bm37arggprqz0njb4lhjni2d9c8qfqj0kll0bam0";
})
(fetchpatch {
url = "https://git.alpinelinux.org/aports/plain/testing/apparmor/0007-Do-not-build-install-vim-file-with-utils-package.patch?id=74b8427cc21f04e32030d047ae92caa618105b53";
name = "0007-Do-not-build-install-vim-file-with-utils-package.patch";
sha256 = "1m4dx901biqgnr4w4wz8a2z9r9dxyw7wv6m6mqglqwf2lxinqmp4";
})
# (alpine patches {1,4,5,6,8} are needed for apparmor 2.11, but not 2.12)
];
# Set to `true` after the next FIXME gets fixed or this gets some
@ -121,7 +126,11 @@ let
libapparmor.python
];
prePatch = prePatchCommon + ''
prePatch = prePatchCommon +
# Do not build vim file
lib.optionalString stdenv.hostPlatform.isMusl ''
sed -i ./utils/Makefile -e "/\<vim\>/d"
'' + ''
substituteInPlace ./utils/apparmor/easyprof.py --replace "/sbin/apparmor_parser" "${apparmor-parser}/bin/apparmor_parser"
substituteInPlace ./utils/apparmor/aa.py --replace "/sbin/apparmor_parser" "${apparmor-parser}/bin/apparmor_parser"
substituteInPlace ./utils/logprof.conf --replace "/sbin/apparmor_parser" "${apparmor-parser}/bin/apparmor_parser"
@ -132,13 +141,21 @@ let
installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" "VIM_INSTALL_PATH=$(out)/share" "PYPREFIX=" ];
postInstall = ''
for prog in aa-audit aa-autodep aa-cleanprof aa-complain aa-disable aa-enforce aa-genprof aa-logprof aa-mergeprof aa-status aa-unconfined ; do
sed -i $out/bin/aa-unconfined -e "/my_env\['PATH'\]/d"
for prog in aa-audit aa-autodep aa-cleanprof aa-complain aa-disable aa-enforce aa-genprof aa-logprof aa-mergeprof aa-unconfined ; do
wrapProgram $out/bin/$prog --prefix PYTHONPATH : "$out/lib/${python.libPrefix}/site-packages:$PYTHONPATH"
done
substituteInPlace $out/bin/aa-notify \
--replace /usr/bin/notify-send ${libnotify}/bin/notify-send \
--replace /usr/bin/perl "${perl}/bin/perl -I ${libapparmor}/${perl.libPrefix}"
substituteInPlace $out/bin/aa-remove-unknown \
--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;
@ -166,7 +183,7 @@ let
prePatch = prePatchCommon;
postPatch = "cd ./binutils";
makeFlags = [ "LANGS=" "USE_SYSTEM=1" ];
installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" ];
installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" "SBINDIR=$(out)/bin" ];
inherit doCheck;
@ -187,6 +204,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";
@ -248,8 +268,35 @@ 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/**"
]
, name ? ""
}: rootPaths: runCommand
( "apparmor-closure-rules"
+ lib.optionalString (name != "") "-${name}" ) {} ''
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
@ -258,5 +305,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 @@
{ lib, stdenv, fetchFromGitHub
, meson, ninja, pkg-config, gettext, libxslt, docbook_xsl_ns
, libcap, libidn2
, apparmorRulesFromClosure
}:
let
@ -20,6 +21,8 @@ in stdenv.mkDerivation rec {
sha256 = "08j2hfgnfh31vv9rn1ml7090j2lsvm9wdpdz13rz60rmyzrx9dq3";
};
outputs = ["out" "apparmor"];
mesonFlags = [
"-DBUILD_RARPD=true"
"-DBUILD_TRACEROUTE6=true"
@ -34,6 +37,25 @@ in stdenv.mkDerivation rec {
nativeBuildInputs = [ meson ninja pkg-config gettext libxslt.bin docbook_xsl_ns ];
buildInputs = [ libcap ]
++ lib.optional (!stdenv.hostPlatform.isMusl) libidn2;
postInstall = ''
install -D -m 644 /dev/stdin $apparmor/bin.ping <<EOF
include <tunables/global>
$out/bin/ping {
include <abstractions/base>
include <abstractions/consoles>
include <abstractions/nameservice>
include "${apparmorRulesFromClosure { name = "ping"; }
([libcap] ++ lib.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 = with lib; {
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 -m 644 /dev/stdin $apparmor/bin.ping <<EOF
$out/bin/ping {
include <abstractions/base>
include <abstractions/consoles>
include <abstractions/nameservice>
include "${apparmorRulesFromClosure { name = "ping"; } [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

@ -19503,7 +19503,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;
aseq2json = callPackage ../os-specific/linux/aseq2json {};