Compare commits

...

11 Commits

Author SHA1 Message Date
Austin Seipp
26fa60ac55 Refactor grsecurity support.
Nota bene: this probably does not work! Caveat emptor, etc.

This inverts the grsecurity builder, making it much simpler. Instead,
users just give a full description of the type of kernel they want to
build, and the result is an attribute set containing kernel and
kernelPackages results.

Now, in order to build a custom grsecurity kernel, you do something more
like:

    let
      kver  = "4.0.4";
      grver = "3.1-${kver}-201505222222";

      kernel = rec
        { version  = kver;
          localver = "-grsec";
          src      = fetchurl rec {
            name  = "linux-${kver}.tar.xz";
            url   = "mirror://kernel/linux/kernel/v4.x/${name}.tar.xz";
            sha256 = "1j5l87z6gd05cqzg680id0x1nk38kd6sjffd2lifl0fz5k6iqr9h";
        };
      };

      patches =
        [ fetchurl rec {
            name   = "grsecurity-${grver}.patch";
            url    = "https://grsecurity.net/test/grsecurity-${grver}.patch";
            sha256 = "0ampby10y3kr36f7rvzm5fdk9f2gcfmcdgkzf67b5kj78y52ypfz";
          }
        ];

      customGrsecKern = customGrsecKernelPackages { inherit kernel patches; };
    in
    {
      ...
      boot.kernelPackages = customGrsecKern.kernelPackages;
    }

Which is far more flexible and easier to think about; plus, it gives
full control over the kernel localver and modDirVer, as well as support
for other patches (because you may have other patches to apply on-top of
grsec, or you may bundle grsec with some other distribution, and still
need the builder support.) It also gives you full control of the kernel
tarball, in case you want to use e.g. libre-linux.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-05-25 10:58:26 -05:00
Austin Seipp
74d867e95c nixpkgs: stop building grsec packages
They're useless right now.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
9bee9c3e0e nixpkgs: dramatically simplify kernel expression
This patch does a lot of cleanup on the kernel expressions to make them
easier to maintain and streamline them for the future.

Really, we shouldn't have 30 different kernels under the sun with 20
various versions of each and random patches for them all. We should
officially have, like, a handful of versions, at best, with supported
configurations and guidelines. Ideally, simply the latest
mainline/testing as well as the most recent -stable branch - which is
exactly what this patch does. Including any needed patches.

The writing was pretty much on the wall for this one, honestly. Post
kernel 4.1, we're likely to move to kdbus, which will quickly mean
dropping support for older kernels in systemd. Plus, there really
*isn't* a need for things like the 3.2 or 3.4 kernel, even if they're
technically still mainline. These were part of old NixOS releases months
ago; there's little reason to hang on.

Finally, random experiments in the tree (MIPS FPU patches, TuxOnIce,
xsave, etc) are fun to commit, but ultimately not very fun to maintain
as very few people are going to test them at all, they're probably
broken with newer kernels (several of these were commited 2-3 years
ago), and it's unclear what benefit we get from building them when
nobody (or like 2 people, which is below epsilon) uses it.

Now, if we include our own patches that *users are likely to use*, *are
on by default* and *broadly useful*, that's probably a different story.
For example, I have a WIP patch to add a switch to randomize MAC
addresses via a kernel patch when an interface goes online, without the
need for macchanger. You can simply flip it on and off. This patch isn't
upstream, and its value in the default build is arguable - but is still
probably more useful to NixOS users than what we have now. Another
example is the BFQ scheduler patches, which could be broadly useful.

This dramatically simplifies keeping the kernels up to date, relieves
Hydra of a lot of packages it otherwise needed to build, and makes the
world a more pleasurable place to live.

In detail:

  - Get rid of all old -stable kernels, including 3.{2,4,10,12,14}.
  - Remove apparmor patches, as they're no longer needed post 3.6+.
  - Remove xsave, crc-regression, TuxOnIce and MIPS patches.
  - Tighten up patches.nix, and put patches back under a ./patches dir.
  - Drop old perf patches, and old linux.upstream.template

If anyone wants to recover these features, they can do so: by adding
them to their own system derivations or forks, which is where a lot of
this belonged in the first place.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
f717395756 nixpkgs: systemd - add some more dependencies
Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
945cffdeec nixpkgs: apparmor - remove dbus dependency
This was untested and didn't function without a dbus patch which wasn't
applied to the system dbus package, so it wasn't used at all.

Also, it creates a weird cyclic dependency if we want systemd to depend
on libapparmor (for AppArmorProfiles= support), because libapparmor then
wants dbus, and dbus wants systemd. Oof.

Luckily, this feature and whatnot will probably all be irrelevant in the
glorious kdbus-based future, and the dbus patches aren't even upstream I
think. So we can just drop it.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
c8bbb586c7 nixos: uptimed - rewrite and harden a bit (#7220)
Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
9b91027b7e nixos: update-locatedb - harden via systemd (#7220)
Also, use systemd timers as well.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
4f722fff87 nixos: transmission - remove needless apparmor boilerplate (#7220)
Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
94b34d82ba nixos: dnscrypt-proxy - remove needless apparmor boilerplate (#7220)
Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
d2e4e4f56a nixos: enable AppArmor by default (#7220)
Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
Austin Seipp
7da9352bc5 nixpkgs: default to apparmor 2.9 (#7220)
Signed-off-by: Austin Seipp <aseipp@pobox.com>
2015-04-13 20:06:49 -05:00
38 changed files with 363 additions and 4535 deletions

View File

@ -124,9 +124,7 @@ let locatedb = "/var/cache/locatedb"; in
{ {
options = { options = {
services.locate = { services.locate = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@ -138,20 +136,21 @@ let locatedb = "/var/cache/locatedb"; in
period = mkOption { period = mkOption {
type = types.str; type = types.str;
default = "15 02 * * *"; default = "02:15";
example = "hourly";
description = '' description = ''
This option defines (in the format used by cron) when the Update the locate database at this interval. Updates by
locate database is updated. The default is to update at default at 2:15 AM every day.
02:15 at night every day.
The format is described in
<citerefentry><refentrytitle>systemd.time</refentrytitle>
<manvolnum>7</manvolnum></citerefentry>.
''; '';
}; };
}; };
}; };
config = { config = {
systemd.services.update-locatedb = systemd.services.update-locatedb =
{ description = "Update Locate Database"; { description = "Update Locate Database";
path = [ pkgs.su ]; path = [ pkgs.su ];
@ -162,9 +161,12 @@ let locatedb = "/var/cache/locatedb"; in
''; '';
}; };
services.cron.systemCronJobs = optional config.services.locate.enable systemd.timers.update-locatedb =
"${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service"; { description = "Update timer for locate database";
partOf = [ "update-locatedb.service" ];
wantedBy = [ "timers.target" ];
timerConfig.OnCalendar = cfg.period;
};
}; };
}</programlisting> }</programlisting>
</example> </example>

View File

@ -6,12 +6,8 @@ let
cfg = config.services.locate; cfg = config.services.locate;
in { in {
###### interface
options = { options = {
services.locate = { services.locate = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@ -23,11 +19,15 @@ in {
period = mkOption { period = mkOption {
type = types.str; type = types.str;
default = "15 02 * * *"; default = "02:15";
example = "hourly";
description = '' description = ''
This option defines (in the format used by cron) when the Update the locate database at this interval. Updates by
locate database is updated. default at 2:15 AM every day.
The default is to update at 02:15 at night every day.
The format is described in
<citerefentry><refentrytitle>systemd.time</refentrytitle>
<manvolnum>7</manvolnum></citerefentry>.
''; '';
}; };
@ -55,15 +55,10 @@ in {
<command>su</command>. <command>su</command>.
''; '';
}; };
}; };
}; };
###### implementation
config = { config = {
systemd.services.update-locatedb = systemd.services.update-locatedb =
{ description = "Update Locate Database"; { description = "Update Locate Database";
path = [ pkgs.su ]; path = [ pkgs.su ];
@ -76,11 +71,18 @@ in {
''; '';
serviceConfig.Nice = 19; serviceConfig.Nice = 19;
serviceConfig.IOSchedulingClass = "idle"; serviceConfig.IOSchedulingClass = "idle";
serviceConfig.PrivateTmp = "yes";
serviceConfig.PrivateNetwork = "yes";
serviceConfig.NoNewPrivileges = "yes";
serviceConfig.ReadOnlyDirectories = "/";
serviceConfig.ReadWriteDirectories = cfg.output;
}; };
services.cron.systemCronJobs = optional config.services.locate.enable systemd.timers.update-locatedb =
"${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service"; { description = "Update timer for locate database";
partOf = [ "update-locatedb.service" ];
wantedBy = [ "timers.target" ];
timerConfig.OnCalendar = cfg.period;
};
}; };
} }

View File

@ -10,7 +10,7 @@ in
security.apparmor = { security.apparmor = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = true;
description = "Enable the AppArmor Mandatory Access Control system."; description = "Enable the AppArmor Mandatory Access Control system.";
}; };
profiles = mkOption { profiles = mkOption {

View File

@ -4,12 +4,6 @@ with lib;
let let
cfg = config.security.grsecurity; cfg = config.security.grsecurity;
customGrsecPkg =
(import ../../../pkgs/build-support/grsecurity {
grsecOptions = cfg;
inherit pkgs lib;
}).grsecPackage;
in in
{ {
options = { options = {
@ -18,14 +12,24 @@ in
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
Enable grsecurity support. This enables advanced exploit Enable grsecurity support system-wide. This enables advanced exploit
hardening for the Linux kernel, and adds support for hardening for the Linux kernel, and adds support for
administrative Role-Based Acess Control (RBAC) via administrative Role-Based Acess Control (RBAC) via
<literal>gradm</literal>. It also includes traditional <literal>gradm</literal>. It also includes traditional
utilities for PaX. utilities for PaX, and more.
''; '';
}; };
kernelPackages = mkOption {
type = types.package;
description = ''
The kernel package set to use. In order to
understand how to set this option appropriately, please see
the NixOS wiki: TODO FIXME.
'';
};
/*
stable = mkOption { stable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@ -214,10 +218,12 @@ in
description = "Extra kernel configuration parameters."; description = "Extra kernel configuration parameters.";
}; };
}; };
*/
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
/*
assertions = assertions =
[ { assertion = cfg.stable || cfg.testing; [ { assertion = cfg.stable || cfg.testing;
message = '' message = ''
@ -246,6 +252,7 @@ in
message = "grsecurity configured for virtualisation but no virtualisation software specified"; message = "grsecurity configured for virtualisation but no virtualisation software specified";
} }
]; ];
*/
systemd.services.grsec-lock = mkIf cfg.config.sysctl { systemd.services.grsec-lock = mkIf cfg.config.sysctl {
description = "grsecurity sysctl-lock Service"; description = "grsecurity sysctl-lock Service";
@ -287,10 +294,9 @@ in
chmod -R 0600 /etc/grsec chmod -R 0600 /etc/grsec
''; }; ''; };
# Enable AppArmor, gradm udev rules, and utilities # Enable gradm udev rules and utilities
security.apparmor.enable = true; boot.kernelPackages = cfg.kernelPackages;
boot.kernelPackages = customGrsecPkg; services.udev.packages = [ pkgs.gradm ];
services.udev.packages = lib.optional (!cfg.config.disableRBAC) pkgs.gradm; environment.systemPackages = [ pkgs.paxctl pkgs.pax-utils pkgs.gradm ];
environment.systemPackages = [ pkgs.paxctl pkgs.pax-utils ] ++ lib.optional (!cfg.config.disableRBAC) pkgs.gradm;
}; };
} }

View File

@ -2,7 +2,6 @@
with lib; with lib;
let let
apparmorEnabled = config.security.apparmor.enable;
dnscrypt-proxy = pkgs.dnscrypt-proxy; dnscrypt-proxy = pkgs.dnscrypt-proxy;
cfg = config.services.dnscrypt-proxy; cfg = config.services.dnscrypt-proxy;
uid = config.ids.uids.dnscrypt-proxy; uid = config.ids.uids.dnscrypt-proxy;
@ -84,8 +83,7 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
### AppArmor profile ### AppArmor profile
security.apparmor.profiles = [
security.apparmor.profiles = mkIf apparmorEnabled [
(pkgs.writeText "apparmor-dnscrypt-proxy" '' (pkgs.writeText "apparmor-dnscrypt-proxy" ''
${dnscrypt-proxy}/bin/dnscrypt-proxy { ${dnscrypt-proxy}/bin/dnscrypt-proxy {
@ -126,8 +124,8 @@ in
systemd.services.dnscrypt-proxy = { systemd.services.dnscrypt-proxy = {
description = "dnscrypt-proxy daemon"; description = "dnscrypt-proxy daemon";
after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service"; after = [ "network.target" "apparmor.service" ];
requires = mkIf apparmorEnabled [ "apparmor.service" ]; requires = [ "apparmor.service" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig = { serviceConfig = {
Type = "forking"; Type = "forking";

View File

@ -1,68 +1,56 @@
{pkgs, config, lib, ...}: { config, lib, pkgs, ... }:
with lib;
let let
cfg = config.services.uptimed;
inherit (lib) mkOption mkIf singleton;
inherit (pkgs) uptimed;
stateDir = "/var/spool/uptimed";
uptimedUser = "uptimed";
in in
{ {
###### interface
options = { options = {
services.uptimed = { services.uptimed = {
enable = mkOption { enable = mkOption {
default = false; default = false;
description = '' description = ''
Uptimed allows you to track your highest uptimes. Enable <literal>uptimed</literal>, allowing you to track
your highest uptimes.
''; '';
}; };
};
}; };
}; config = mkIf cfg.enable {
users.extraUsers.uptimed = {
###### implementation
config = mkIf config.services.uptimed.enable {
environment.systemPackages = [ uptimed ];
users.extraUsers = singleton
{ name = uptimedUser;
uid = config.ids.uids.uptimed;
description = "Uptimed daemon user"; description = "Uptimed daemon user";
home = stateDir; home = "/var/spool/uptimed";
createHome = true;
uid = config.ids.uids.uptimed;
}; };
jobs.uptimed = systemd.services.uptimed = {
{ description = "Uptimed daemon"; unitConfig.Documentation = "man:uptimed(8) man:uprecords(1)";
description = "uptimed service";
wantedBy = [ "multi-user.target" ];
startOn = "startup"; serviceConfig.Restart = "on-failure";
serviceConfig.User = "uptimed";
serviceConfig.Nice = 19;
serviceConfig.IOSchedulingClass = "idle";
serviceConfig.PrivateTmp = "yes";
serviceConfig.PrivateNetwork = "yes";
serviceConfig.NoNewPrivileges = "yes";
serviceConfig.ReadWriteDirectories = "/var/spool/uptimed";
serviceConfig.InaccessibleDirectories = "/home";
preStart = preStart = ''
'' mkdir -m 0755 -p /var/spool/uptimed
mkdir -m 0755 -p ${stateDir} chown uptimed /var/spool/uptimed
chown ${uptimedUser} ${stateDir}
if ! test -f ${stateDir}/bootid ; then if ! test -f /var/spool/uptimed/bootid ; then
${uptimed}/sbin/uptimed -b ${pkgs.uptimed}/sbin/uptimed -b
fi fi
''; '';
serviceConfig.ExecStart =
exec = "${uptimed}/sbin/uptimed"; "${pkgs.uptimed}/sbin/uptimed -f -p /var/spool/uptimed/pid";
}; };
}; };
} }

View File

@ -4,7 +4,6 @@ with lib;
let let
cfg = config.services.transmission; cfg = config.services.transmission;
apparmor = config.security.apparmor.enable;
homeDir = "/var/lib/transmission"; homeDir = "/var/lib/transmission";
downloadDir = "${homeDir}/Downloads"; downloadDir = "${homeDir}/Downloads";
@ -76,8 +75,8 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd.services.transmission = { systemd.services.transmission = {
description = "Transmission BitTorrent Service"; description = "Transmission BitTorrent Service";
after = [ "local-fs.target" "network.target" ] ++ optional apparmor "apparmor.service"; after = [ "local-fs.target" "network.target" "apparmor.service" ];
requires = mkIf apparmor [ "apparmor.service" ]; requires = [ "apparmor.service" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
# 1) Only the "transmission" user and group have access to torrents. # 1) Only the "transmission" user and group have access to torrents.
@ -105,7 +104,7 @@ in
}; };
# AppArmor profile # AppArmor profile
security.apparmor.profiles = mkIf apparmor [ security.apparmor.profiles = [
(pkgs.writeText "apparmor-transmission-daemon" '' (pkgs.writeText "apparmor-transmission-daemon" ''
#include <tunables/global> #include <tunables/global>

View File

@ -1,126 +1,38 @@
{ grsecOptions, lib, pkgs }: { pkgs, lib, ... }:
with pkgs;
with lib; with lib;
let let
cfg = { grsec_path_patch = { name "grsec-path"; patch = ./grsec-path.patch; };
stable = grsecOptions.stable or false; genericKernelBuilder = import ../../os-specific/linux/kernel/generic.nix;
testing = grsecOptions.testing or false; in
config = { {
mode = "auto"; customGrsecKernelPackages = p:
sysctl = false; let
denyChrootChmod = false; version = p.kernel.version;
denyUSB = false; localver = p.kernel.localver or "";
restrictProc = false; modDirVersion = p.kernel.modDirVersion or (version+localver);
restrictProcWithGroup = true; features = p.kernel.features or {};
unrestrictProcGid = 121; # Ugh, an awful hack. See grsecurity NixOS gid src = with p.kernel; fetchurl { inherit url sha256; };
disableRBAC = false;
verboseVersion = false;
kernelExtraConfig = "";
} // grsecOptions.config;
};
vals = rec { kernel = overrideDerivation (genericKernelBuilder (rec {
inherit version modDirVersion src;
mkKernel = kernel: patch: /* Add any 'quirky' patches (like bridge_stp_helper and
assert patch.kversion == kernel.version; * grsec_path_patch, which fix NixOS-specific quirks) plus the ones
{ inherit kernel patch; * the user specified. */
inherit (patch) grversion revision; kernelPatches = [ grsec_path_patch
}; kernelPatches.bridge_stp_helper
] ++ (map fetchurl p.patches);
test-patch = with pkgs.kernelPatches; grsecurity_unstable; /* Default features */
stable-patch = with pkgs.kernelPatches; grsecurity_stable; features.iwlwifi = true;
features.efiBootStub = true;
grKernel = if cfg.stable features.needsCifsUtils = true;
then mkKernel pkgs.linux_3_14 stable-patch features.canDisableNetfilterConntrackHelpers = true;
else mkKernel pkgs.linux_3_19 test-patch; features.netfilterRPFilter = true;
})) (args: {
## -- grsecurity configuration ---------------------------------------------
grsecPrioCfg =
if cfg.config.priority == "security" then
"GRKERNSEC_CONFIG_PRIORITY_SECURITY y"
else
"GRKERNSEC_CONFIG_PRIORITY_PERF y";
grsecSystemCfg =
if cfg.config.system == "desktop" then
"GRKERNSEC_CONFIG_DESKTOP y"
else
"GRKERNSEC_CONFIG_SERVER y";
grsecVirtCfg =
if cfg.config.virtualisationConfig == null then
"GRKERNSEC_CONFIG_VIRT_NONE y"
else if cfg.config.virtualisationConfig == "host" then
"GRKERNSEC_CONFIG_VIRT_HOST y"
else
"GRKERNSEC_CONFIG_VIRT_GUEST y";
grsecHwvirtCfg = if cfg.config.virtualisationConfig == null then "" else
if cfg.config.hardwareVirtualisation == true then
"GRKERNSEC_CONFIG_VIRT_EPT y"
else
"GRKERNSEC_CONFIG_VIRT_SOFT y";
grsecVirtswCfg =
let virtCfg = opt: "GRKERNSEC_CONFIG_VIRT_"+opt+" y";
in
if cfg.config.virtualisationConfig == null then ""
else if cfg.config.virtualisationSoftware == "xen" then virtCfg "XEN"
else if cfg.config.virtualisationSoftware == "kvm" then virtCfg "KVM"
else if cfg.config.virtualisationSoftware == "vmware" then virtCfg "VMWARE"
else virtCfg "VIRTUALBOX";
grsecMainConfig = if cfg.config.mode == "custom" then "" else ''
GRKERNSEC_CONFIG_AUTO y
${grsecPrioCfg}
${grsecSystemCfg}
${grsecVirtCfg}
${grsecHwvirtCfg}
${grsecVirtswCfg}
'';
grsecConfig =
let boolToKernOpt = b: if b then "y" else "n";
# Disable RANDSTRUCT under virtualbox, as it has some kind of
# breakage with the vbox guest drivers
#randstruct = optionalString config.services.virtualboxGuest.enable
# "GRKERNSEC_RANDSTRUCT n";
# Disable restricting links under the testing kernel, as something
# has changed causing it to fail miserably during boot.
restrictLinks = optionalString cfg.testing
"GRKERNSEC_LINK n";
in ''
GRKERNSEC y
${grsecMainConfig}
${if cfg.config.restrictProc then
"GRKERNSEC_PROC_USER y"
else
optionalString cfg.config.restrictProcWithGroup ''
GRKERNSEC_PROC_USERGROUP y
GRKERNSEC_PROC_GID ${toString cfg.config.unrestrictProcGid}
''
}
GRKERNSEC_SYSCTL ${boolToKernOpt cfg.config.sysctl}
GRKERNSEC_CHROOT_CHMOD ${boolToKernOpt cfg.config.denyChrootChmod}
GRKERNSEC_DENYUSB ${boolToKernOpt cfg.config.denyUSB}
GRKERNSEC_NO_RBAC ${boolToKernOpt cfg.config.disableRBAC}
${restrictLinks}
${cfg.config.kernelExtraConfig}
'';
## -- grsecurity kernel packages -------------------------------------------
localver = grkern:
"-grsec" + optionalString cfg.config.verboseVersion
"-${grkern.grversion}-${grkern.revision}";
grsecurityOverrider = args: grkern: {
# Apparently as of gcc 4.6, gcc-plugin headers (which are needed by PaX plugins) # Apparently as of gcc 4.6, gcc-plugin headers (which are needed by PaX plugins)
# include libgmp headers, so we need these extra tweaks # include libgmp headers, so we need these extra tweaks
buildInputs = args.buildInputs ++ [ pkgs.gmp ]; buildInputs = args.buildInputs ++ [ pkgs.gmp ];
@ -130,25 +42,15 @@ let
sed -i 's|HOST_EXTRACFLAGS +=|HOST_EXTRACFLAGS += -I${pkgs.gmp}/include|' tools/gcc/Makefile sed -i 's|HOST_EXTRACFLAGS +=|HOST_EXTRACFLAGS += -I${pkgs.gmp}/include|' tools/gcc/Makefile
sed -i 's|HOST_EXTRACXXFLAGS +=|HOST_EXTRACXXFLAGS += -I${pkgs.gmp}/include|' tools/gcc/Makefile sed -i 's|HOST_EXTRACXXFLAGS +=|HOST_EXTRACXXFLAGS += -I${pkgs.gmp}/include|' tools/gcc/Makefile
rm localversion-grsec rm localversion-grsec
echo ${localver grkern} > localversion-grsec ${if localver == "" then "" else ''
echo ${localver} > localversion-nix
''}
''; '';
}) // features;
kernelPackages = let self = linuxPackagesFor kernel self; in recurseIntoAttrs self;
in {
inherit kernel;
inherit kernelPackages;
}; };
}
mkGrsecKern = grkern:
lowPrio (overrideDerivation (grkern.kernel.override (args: {
kernelPatches = args.kernelPatches ++ [ grkern.patch pkgs.kernelPatches.grsec_fix_path ];
argsOverride = {
modDirVersion = "${grkern.kernel.modDirVersion}${localver grkern}";
};
extraConfig = grsecConfig;
features.grsecurity = true;
})) (args: grsecurityOverrider args grkern));
mkGrsecPkg = grkern: pkgs.linuxPackagesFor grkern (mkGrsecPkg grkern);
## -- Kernel packages ------------------------------------------------------
grsecKernel = mkGrsecKern grKernel;
grsecPackage = mkGrsecPkg grsecKernel;
};
in vals

View File

@ -1,183 +0,0 @@
{ stdenv, fetchurl, autoconf, automake, libtool, pkgconfig, perl, which
, glibc, flex, bison, python27, swig, dbus, pam
}:
let
apparmor-series = "2.9";
apparmor-patchver = "1";
apparmor-version = "${apparmor-series}.${apparmor-patchver}";
apparmor-meta = component: with stdenv.lib; {
homepage = http://apparmor.net/;
description = "Linux application security system - ${component}";
license = licenses.gpl2;
maintainers = with maintainers; [ phreedom thoughtpolice joachifm ];
platforms = platforms.linux;
};
apparmor-sources = fetchurl {
url = "https://launchpad.net/apparmor/${apparmor-series}/${apparmor-version}/+download/apparmor-${apparmor-version}.tar.gz";
sha256 = "08ha7aigl40vm80f742rljcckdpfpw1s8g4yii1ysabcqcj8ffx6";
};
prePatchCommon = ''
substituteInPlace ./common/Make.rules --replace "/usr/bin/pod2man" "${perl}/bin/pod2man"
substituteInPlace ./common/Make.rules --replace "/usr/bin/pod2html" "${perl}/bin/pod2html"
substituteInPlace ./common/Make.rules --replace "/usr/include/linux/capability.h" "${glibc}/include/linux/capability.h"
substituteInPlace ./common/Make.rules --replace "/usr/share/man" "share/man"
'';
libapparmor = stdenv.mkDerivation {
name = "libapparmor-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
autoconf
automake
bison
flex
dbus # requires patch to dbus ...
glibc
libtool
perl
pkgconfig
python27
swig
which
];
prePatch = prePatchCommon + ''
substituteInPlace ./libraries/libapparmor/src/Makefile.am --replace "/usr/include/netinet/in.h" "${glibc}/include/netinet/in.h"
substituteInPlace ./libraries/libapparmor/src/Makefile.in --replace "/usr/include/netinet/in.h" "${glibc}/include/netinet/in.h"
'';
buildPhase = ''
cd ./libraries/libapparmor
./autogen.sh
./configure --prefix="$out" --with-python --with-perl
make
'';
installPhase = ''
make install
'';
meta = apparmor-meta "library";
};
apparmor-utils = stdenv.mkDerivation {
name = "apparmor-utils-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
python27
libapparmor
which
];
prePatch = prePatchCommon;
buildPhase = ''
cd ./utils
make LANGS=""
'';
installPhase = ''
make install LANGS="" DESTDIR="$out" BINDIR="$out/bin" VIM_INSTALL_PATH="$out/share" PYPREFIX=""
'';
meta = apparmor-meta "user-land utilities";
};
apparmor-parser = stdenv.mkDerivation {
name = "apparmor-parser-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
libapparmor
bison
flex
which
];
prePatch = prePatchCommon + ''
substituteInPlace ./parser/Makefile --replace "/usr/bin/bison" "${bison}/bin/bison"
substituteInPlace ./parser/Makefile --replace "/usr/bin/flex" "${flex}/bin/flex"
substituteInPlace ./parser/Makefile --replace "/usr/include/linux/capability.h" "${glibc}/include/linux/capability.h"
## techdoc.pdf still doesn't build ...
substituteInPlace ./parser/Makefile --replace "manpages htmlmanpages pdf" "manpages htmlmanpages"
'';
buildPhase = ''
cd ./parser
make LANGS="" USE_SYSTEM=1 INCLUDEDIR=${libapparmor}/include
'';
installPhase = ''
make install LANGS="" USE_SYSTEM=1 INCLUDEDIR=${libapparmor}/include DESTDIR="$out" DISTRO="unknown"
'';
meta = apparmor-meta "rule parser";
};
apparmor-pam = stdenv.mkDerivation {
name = "apparmor-pam-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
libapparmor
pam
pkgconfig
which
];
buildPhase = ''
cd ./changehat/pam_apparmor
make USE_SYSTEM=1
'';
installPhase = ''
make install DESTDIR="$out"
'';
meta = apparmor-meta "PAM service";
};
apparmor-profiles = stdenv.mkDerivation {
name = "apparmor-profiles-${apparmor-version}";
src = apparmor-sources;
buildInputs = [ which ];
buildPhase = ''
cd ./profiles
make
'';
installPhase = ''
make install DESTDIR="$out" EXTRAS_DEST="$out/share/apparmor/extra-profiles"
'';
meta = apparmor-meta "profiles";
};
apparmor-kernel-patches = stdenv.mkDerivation {
name = "apparmor-kernel-patches-${apparmor-version}";
src = apparmor-sources;
phases = ''unpackPhase installPhase'';
installPhase = ''
mkdir "$out"
cp -R ./kernel-patches "$out"
'';
meta = apparmor-meta "kernel patches";
};
in
{
inherit libapparmor apparmor-utils apparmor-parser apparmor-pam
apparmor-profiles apparmor-kernel-patches;
}

View File

@ -1,16 +0,0 @@
Description: allow parser to build even when not on Linux.
Author: Kees Cook <kees@debian.org>
Index: apparmor-debian/common/Make.rules
===================================================================
--- apparmor-debian.orig/common/Make.rules 2012-05-05 14:41:25.967259523 -0700
+++ apparmor-debian/common/Make.rules 2012-05-05 14:41:28.451291053 -0700
@@ -160,7 +160,7 @@
CAPABILITIES=$(shell echo "\#include <linux/capability.h>" | cpp -dM | LC_ALL=C sed -n -e '/CAP_EMPTY_SET/d' -e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$$/CAP_\1/p' | sort)
.PHONY: list_capabilities
-list_capabilities: /usr/include/linux/capability.h
+list_capabilities:
@echo "$(CAPABILITIES)"
# =====================

View File

@ -1,98 +1,182 @@
{ stdenv, fetchurl { stdenv, fetchurl, autoconf, automake, libtool, pkgconfig, perl, which
, autoconf, automake, libtool, makeWrapper , glibc, flex, bison, python27, swig, pam
, perl, bison, flex, glibc, gettext, which, rpm, tetex, LocaleGettext }:
, bash, pam, TermReadKey, RpcXML, swig, python}:
stdenv.mkDerivation rec {
name = "apparmor-${version}"; let
version = "2.8.4"; apparmor-series = "2.9";
apparmor-patchver = "1";
apparmor-version = "${apparmor-series}.${apparmor-patchver}";
src = fetchurl { apparmor-meta = component: with stdenv.lib; {
url = "http://launchpad.net/apparmor/2.8/${version}/+download/${name}.tar.gz";
sha256 = "1mki4c44ljmr7dpn55grzn33929kdjx149jx00s80yp1war83jwq";
};
buildInputs = [
autoconf automake libtool perl bison flex gettext which rpm tetex
LocaleGettext pam TermReadKey RpcXML swig makeWrapper python ];
prePatch = ''
substituteInPlace libraries/libapparmor/src/Makefile.in --replace "/usr/include" "${glibc}/include"
substituteInPlace libraries/libapparmor/src/Makefile.am --replace "/usr/include" "${glibc}/include"
substituteInPlace common/Make.rules --replace "/usr/bin/pod2man" "${perl}/bin/pod2man"
substituteInPlace common/Make.rules --replace "/usr/bin/pod2html" "${perl}/bin/pod2html"
substituteInPlace common/Make.rules --replace "cpp -dM" "cpp -dM -I${glibc}/include"
substituteInPlace parser/Makefile --replace "/usr/bin/bison" "${bison}/bin/bison"
substituteInPlace parser/Makefile --replace "/usr/bin/flex" "${flex}/bin/flex"
substituteInPlace parser/Makefile --replace "/usr/include/bits/socket.h" "${glibc}/include/bits/socket.h"
substituteInPlace parser/Makefile --replace "/usr/include/linux/capability.h" "${glibc}/include/linux/capability.h"
#substituteInPlace parser/utils/vim/Makefile --replace "/usr/include/linux/capability.h" "${glibc}/include/linux/capability.h"
# for some reason pdf documentation doesn't build
substituteInPlace parser/Makefile --replace "manpages htmlmanpages pdf" "manpages htmlmanpages"
substituteInPlace parser/tst/gen-xtrans.pl --replace "/usr/bin/perl" "${perl}/bin/perl"
substituteInPlace parser/tst/Makefile --replace "/usr/bin/prove" "${perl}/bin/prove"
substituteInPlace parser/tst/Makefile --replace "./caching.sh" "${bash}/bin/bash ./caching.sh"
'';
patches = ./capability.patch;
buildPhase =''
PERL5LIB=$PERL5LIB:$out/lib/perl5/site_perl:$out/lib
cd libraries/libapparmor
./autogen.sh
./configure --prefix=$out --with-perl # see below
make
make check
make install
mkdir -p $out/lib/perl5/site_perl/
cp swig/perl/LibAppArmor.pm $out/lib/perl5/site_perl/
cp swig/perl/LibAppArmor.bs $out/lib/perl5/site_perl/
# this is automatically copied elsewhere....
cd ../../utils
make
make install DESTDIR=$out BINDIR=$out/bin VENDOR_PERL=/lib/perl5/site_perl
cd ../parser
make
make install DESTDIR=$out DISTRO=unknown
# cd ../changehat/mod_apparmor
# make # depends on libapparmor having been built first
# make install
cd ../changehat/pam_apparmor
make # depends on libapparmor having been built first
make install DESTDIR=$out
cd ../../profiles
LD_LIBRARY_PATH=$out/lib make
#LD_LIBRARY_PATH=$out/lib make check # depends on the parser having been built first
make install DESTDIR=$out
cd ..
cp -r kernel-patches $out
'';
installPhase = let
perlVersion = (builtins.parseDrvName perl.name).version;
in ''
for i in $out/bin/*; do
wrapProgram $i --prefix PERL5LIB : \
"$PERL5LIB:$out/lib/perl5/${perlVersion}/${stdenv.system}-thread-multi/"
done
'';
meta = with stdenv.lib; {
homepage = http://apparmor.net/; homepage = http://apparmor.net/;
description = "Linux application security system"; description = "Linux application security system - ${component}";
license = licenses.gpl2; license = licenses.gpl2;
maintainers = [ maintainers.phreedom maintainers.thoughtpolice ]; maintainers = with maintainers; [ phreedom thoughtpolice joachifm ];
platforms = platforms.linux; platforms = platforms.linux;
}; };
}
apparmor-sources = fetchurl {
url = "https://launchpad.net/apparmor/${apparmor-series}/${apparmor-version}/+download/apparmor-${apparmor-version}.tar.gz";
sha256 = "08ha7aigl40vm80f742rljcckdpfpw1s8g4yii1ysabcqcj8ffx6";
};
prePatchCommon = ''
substituteInPlace ./common/Make.rules --replace "/usr/bin/pod2man" "${perl}/bin/pod2man"
substituteInPlace ./common/Make.rules --replace "/usr/bin/pod2html" "${perl}/bin/pod2html"
substituteInPlace ./common/Make.rules --replace "/usr/include/linux/capability.h" "${glibc}/include/linux/capability.h"
substituteInPlace ./common/Make.rules --replace "/usr/share/man" "share/man"
'';
libapparmor = stdenv.mkDerivation {
name = "libapparmor-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
autoconf
automake
bison
flex
glibc
libtool
perl
pkgconfig
python27
swig
which
];
prePatch = prePatchCommon + ''
substituteInPlace ./libraries/libapparmor/src/Makefile.am --replace "/usr/include/netinet/in.h" "${glibc}/include/netinet/in.h"
substituteInPlace ./libraries/libapparmor/src/Makefile.in --replace "/usr/include/netinet/in.h" "${glibc}/include/netinet/in.h"
'';
buildPhase = ''
cd ./libraries/libapparmor
./autogen.sh
./configure --prefix="$out" --with-python --with-perl
make
'';
installPhase = ''
make install
'';
meta = apparmor-meta "library";
};
apparmor-utils = stdenv.mkDerivation {
name = "apparmor-utils-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
python27
libapparmor
which
];
prePatch = prePatchCommon;
buildPhase = ''
cd ./utils
make LANGS=""
'';
installPhase = ''
make install LANGS="" DESTDIR="$out" BINDIR="$out/bin" VIM_INSTALL_PATH="$out/share" PYPREFIX=""
'';
meta = apparmor-meta "user-land utilities";
};
apparmor-parser = stdenv.mkDerivation {
name = "apparmor-parser-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
libapparmor
bison
flex
which
];
prePatch = prePatchCommon + ''
substituteInPlace ./parser/Makefile --replace "/usr/bin/bison" "${bison}/bin/bison"
substituteInPlace ./parser/Makefile --replace "/usr/bin/flex" "${flex}/bin/flex"
substituteInPlace ./parser/Makefile --replace "/usr/include/linux/capability.h" "${glibc}/include/linux/capability.h"
## techdoc.pdf still doesn't build ...
substituteInPlace ./parser/Makefile --replace "manpages htmlmanpages pdf" "manpages htmlmanpages"
'';
buildPhase = ''
cd ./parser
make LANGS="" USE_SYSTEM=1 INCLUDEDIR=${libapparmor}/include
'';
installPhase = ''
make install LANGS="" USE_SYSTEM=1 INCLUDEDIR=${libapparmor}/include DESTDIR="$out" DISTRO="unknown"
'';
meta = apparmor-meta "rule parser";
};
apparmor-pam = stdenv.mkDerivation {
name = "apparmor-pam-${apparmor-version}";
src = apparmor-sources;
buildInputs = [
libapparmor
pam
pkgconfig
which
];
buildPhase = ''
cd ./changehat/pam_apparmor
make USE_SYSTEM=1
'';
installPhase = ''
make install DESTDIR="$out"
'';
meta = apparmor-meta "PAM service";
};
apparmor-profiles = stdenv.mkDerivation {
name = "apparmor-profiles-${apparmor-version}";
src = apparmor-sources;
buildInputs = [ which ];
buildPhase = ''
cd ./profiles
make
'';
installPhase = ''
make install DESTDIR="$out" EXTRAS_DEST="$out/share/apparmor/extra-profiles"
'';
meta = apparmor-meta "profiles";
};
apparmor-kernel-patches = stdenv.mkDerivation {
name = "apparmor-kernel-patches-${apparmor-version}";
src = apparmor-sources;
phases = ''unpackPhase installPhase'';
installPhase = ''
mkdir "$out"
cp -R ./kernel-patches "$out"
'';
meta = apparmor-meta "kernel patches";
};
in
{
inherit libapparmor apparmor-utils apparmor-parser apparmor-pam
apparmor-profiles apparmor-kernel-patches;
}

View File

@ -1,553 +0,0 @@
From 125fccb600288968aa3395883c0a394c47176fcd Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 10 Aug 2011 22:02:39 -0700
Subject: [PATCH 1/3] AppArmor: compatibility patch for v5 network controll
Add compatibility for v5 network rules.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
include/linux/lsm_audit.h | 4 +
security/apparmor/Makefile | 19 +++-
security/apparmor/include/net.h | 40 +++++++++
security/apparmor/include/policy.h | 3 +
security/apparmor/lsm.c | 112 ++++++++++++++++++++++++
security/apparmor/net.c | 170 ++++++++++++++++++++++++++++++++++++
security/apparmor/policy.c | 1 +
security/apparmor/policy_unpack.c | 48 +++++++++-
8 files changed, 394 insertions(+), 3 deletions(-)
create mode 100644 security/apparmor/include/net.h
create mode 100644 security/apparmor/net.c
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 88e78de..c63979a 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -124,6 +124,10 @@ struct common_audit_data {
u32 denied;
uid_t ouid;
} fs;
+ struct {
+ int type, protocol;
+ struct sock *sk;
+ } net;
};
} apparmor_audit_data;
#endif
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index 2dafe50..7cefef9 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
- resource.o sid.o file.o
+ resource.o sid.o file.o net.o
-clean-files := capability_names.h rlim_names.h
+clean-files := capability_names.h rlim_names.h af_names.h
# Build a lower case string table of capability names
@@ -44,9 +44,24 @@ cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\
sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\
echo "};" >> $@
+# Build a lower case string table of address family names.
+# Transform lines from
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# [2] = "inet",
+quiet_cmd_make-af = GEN $@
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
+ sed $< >> $@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+).*/[\2] = "\L\1",/p';\
+ echo "};" >> $@
+
+
$(obj)/capability.o : $(obj)/capability_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
+$(obj)/net.o : $(obj)/af_names.h
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
$(call cmd,make-caps)
$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
$(call cmd,make-rlim)
+$(obj)/af_names.h : $(srctree)/include/linux/socket.h
+ $(call cmd,make-af)
\ No newline at end of file
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
new file mode 100644
index 0000000..3c7d599
--- /dev/null
+++ b/security/apparmor/include/net.h
@@ -0,0 +1,40 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_NET_H
+#define __AA_NET_H
+
+#include <net/sock.h>
+
+/* struct aa_net - network confinement data
+ * @allowed: basic network families permissions
+ * @audit_network: which network permissions to force audit
+ * @quiet_network: which network permissions to quiet rejects
+ */
+struct aa_net {
+ u16 allow[AF_MAX];
+ u16 audit[AF_MAX];
+ u16 quiet[AF_MAX];
+};
+
+extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
+ int type, int protocol, struct sock *sk);
+extern int aa_revalidate_sk(int op, struct sock *sk);
+
+static inline void aa_free_net_rules(struct aa_net *new)
+{
+ /* NOP */
+}
+
+#endif /* __AA_NET_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index aeda5cf..6776929 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -27,6 +27,7 @@
#include "capability.h"
#include "domain.h"
#include "file.h"
+#include "net.h"
#include "resource.h"
extern const char *profile_mode_names[];
@@ -145,6 +146,7 @@ struct aa_namespace {
* @size: the memory consumed by this profiles rules
* @file: The set of rules governing basic file access and domain transitions
* @caps: capabilities for the profile
+ * @net: network controls for the profile
* @rlimits: rlimits for the profile
*
* The AppArmor profile contains the basic confinement data. Each profile
@@ -181,6 +183,7 @@ struct aa_profile {
struct aa_file_rules file;
struct aa_caps caps;
+ struct aa_net net;
struct aa_rlimit rlimits;
};
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 3783202..7459547 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -32,6 +32,7 @@
#include "include/context.h"
#include "include/file.h"
#include "include/ipc.h"
+#include "include/net.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/procattr.h"
@@ -621,6 +622,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (kern)
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
+ NULL);
+ return error;
+}
+
+static int apparmor_socket_bind(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_BIND, sk);
+}
+
+static int apparmor_socket_connect(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_CONNECT, sk);
+}
+
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_LISTEN, sk);
+}
+
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_ACCEPT, sk);
+}
+
+static int apparmor_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg, int size)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SENDMSG, sk);
+}
+
+static int apparmor_socket_recvmsg(struct socket *sock,
+ struct msghdr *msg, int size, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_RECVMSG, sk);
+}
+
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
+}
+
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
+}
+
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
+}
+
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
+}
+
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
+}
+
static struct security_operations apparmor_ops = {
.name = "apparmor",
@@ -652,6 +751,19 @@ static struct security_operations apparmor_ops = {
.getprocattr = apparmor_getprocattr,
.setprocattr = apparmor_setprocattr,
+ .socket_create = apparmor_socket_create,
+ .socket_bind = apparmor_socket_bind,
+ .socket_connect = apparmor_socket_connect,
+ .socket_listen = apparmor_socket_listen,
+ .socket_accept = apparmor_socket_accept,
+ .socket_sendmsg = apparmor_socket_sendmsg,
+ .socket_recvmsg = apparmor_socket_recvmsg,
+ .socket_getsockname = apparmor_socket_getsockname,
+ .socket_getpeername = apparmor_socket_getpeername,
+ .socket_getsockopt = apparmor_socket_getsockopt,
+ .socket_setsockopt = apparmor_socket_setsockopt,
+ .socket_shutdown = apparmor_socket_shutdown,
+
.cred_alloc_blank = apparmor_cred_alloc_blank,
.cred_free = apparmor_cred_free,
.cred_prepare = apparmor_cred_prepare,
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
new file mode 100644
index 0000000..1765901
--- /dev/null
+++ b/security/apparmor/net.c
@@ -0,0 +1,170 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/net.h"
+#include "include/policy.h"
+
+#include "af_names.h"
+
+static const char *sock_type_names[] = {
+ "unknown(0)",
+ "stream",
+ "dgram",
+ "raw",
+ "rdm",
+ "seqpacket",
+ "dccp",
+ "unknown(7)",
+ "unknown(8)",
+ "unknown(9)",
+ "packet",
+};
+
+/* audit callback for net specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ audit_log_format(ab, " family=");
+ if (address_family_names[sa->u.net.family]) {
+ audit_log_string(ab, address_family_names[sa->u.net.family]);
+ } else {
+ audit_log_format(ab, " \"unknown(%d)\"", sa->u.net.family);
+ }
+
+ audit_log_format(ab, " sock_type=");
+ if (sock_type_names[sa->aad.net.type]) {
+ audit_log_string(ab, sock_type_names[sa->aad.net.type]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad.net.type);
+ }
+
+ audit_log_format(ab, " protocol=%d", sa->aad.net.protocol);
+}
+
+/**
+ * audit_net - audit network access
+ * @profile: profile being enforced (NOT NULL)
+ * @op: operation being checked
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ * @sk: socket auditing is being applied to
+ * @error: error code for failure else 0
+ *
+ * Returns: %0 or sa->error else other errorcode on failure
+ */
+static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
+ int protocol, struct sock *sk, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ struct common_audit_data sa;
+ if (sk) {
+ COMMON_AUDIT_DATA_INIT(&sa, NET);
+ } else {
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ }
+ /* todo fill in socket addr info */
+
+ sa.aad.op = op,
+ sa.u.net.family = family;
+ sa.u.net.sk = sk;
+ sa.aad.net.type = type;
+ sa.aad.net.protocol = protocol;
+ sa.aad.error = error;
+
+ if (likely(!sa.aad.error)) {
+ u16 audit_mask = profile->net.audit[sa.u.net.family];
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+ !(1 << sa.aad.net.type & audit_mask)))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ u16 quiet_mask = profile->net.quiet[sa.u.net.family];
+ u16 kill_mask = 0;
+ u16 denied = (1 << sa.aad.net.type) & ~quiet_mask;
+
+ if (denied & kill_mask)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ if ((denied & quiet_mask) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
+ }
+
+ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
+}
+
+/**
+ * aa_net_perm - very course network access check
+ * @op: operation being checked
+ * @profile: profile being enforced (NOT NULL)
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
+ int protocol, struct sock *sk)
+{
+ u16 family_mask;
+ int error;
+
+ if ((family < 0) || (family >= AF_MAX))
+ return -EINVAL;
+
+ if ((type < 0) || (type >= SOCK_MAX))
+ return -EINVAL;
+
+ /* unix domain and netlink sockets are handled by ipc */
+ if (family == AF_UNIX || family == AF_NETLINK)
+ return 0;
+
+ family_mask = profile->net.allow[family];
+
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+ return audit_net(profile, op, family, type, protocol, sk, error);
+}
+
+/**
+ * aa_revalidate_sk - Revalidate access to a sock
+ * @op: operation being checked
+ * @sk: sock being revalidated (NOT NULL)
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_revalidate_sk(int op, struct sock *sk)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* aa_revalidate_sk should not be called from interrupt context
+ * don't mediate these calls as they are not task related
+ */
+ if (in_interrupt())
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
+ sk->sk_protocol, sk);
+
+ return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 4f0eade..4d5ce13 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile)
aa_free_file_rules(&profile->file);
aa_free_cap_rules(&profile->caps);
+ aa_free_net_rules(&profile->net);
aa_free_rlimit_rules(&profile->rlimits);
aa_free_sid(profile->sid);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 741dd13..ee8043e 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -190,6 +190,19 @@ fail:
return 0;
}
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
+{
+ if (unpack_nameX(e, AA_U16, name)) {
+ if (!inbounds(e, sizeof(u16)))
+ return 0;
+ if (data)
+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
+ e->pos += sizeof(u16);
+ return 1;
+ }
+ return 0;
+}
+
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
{
if (unpack_nameX(e, AA_U32, name)) {
@@ -468,7 +481,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
{
struct aa_profile *profile = NULL;
const char *name = NULL;
- int error = -EPROTO;
+ size_t size = 0;
+ int i, error = -EPROTO;
kernel_cap_t tmpcap;
u32 tmp;
@@ -559,6 +573,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
if (!unpack_rlimits(e, profile))
goto fail;
+ size = unpack_array(e, "net_allowed_af");
+ if (size) {
+
+ for (i = 0; i < size; i++) {
+ /* discard extraneous rules that this kernel will
+ * never request
+ */
+ if (i >= AF_MAX) {
+ u16 tmp;
+ if (!unpack_u16(e, &tmp, NULL) ||
+ !unpack_u16(e, &tmp, NULL) ||
+ !unpack_u16(e, &tmp, NULL))
+ goto fail;
+ continue;
+ }
+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
+ goto fail;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ /*
+ * allow unix domain and netlink sockets they are handled
+ * by IPC
+ */
+ }
+ profile->net.allow[AF_UNIX] = 0xffff;
+ profile->net.allow[AF_NETLINK] = 0xffff;
+
/* get file rules */
profile->file.dfa = unpack_dfa(e);
if (IS_ERR(profile->file.dfa)) {
--
1.7.9.5

View File

@ -1,391 +0,0 @@
From 004192fb5223c7b81a949e36a080a5da56132826 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 10 Aug 2011 22:02:40 -0700
Subject: [PATCH 2/3] AppArmor: compatibility patch for v5 interface
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/Kconfig | 9 +
security/apparmor/Makefile | 1 +
security/apparmor/apparmorfs-24.c | 287 ++++++++++++++++++++++++++++++++
security/apparmor/apparmorfs.c | 18 +-
security/apparmor/include/apparmorfs.h | 6 +
5 files changed, 319 insertions(+), 2 deletions(-)
create mode 100644 security/apparmor/apparmorfs-24.c
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index 9b9013b..51ebf96 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -29,3 +29,12 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
boot.
If you are unsure how to answer this question, answer 1.
+
+config SECURITY_APPARMOR_COMPAT_24
+ bool "Enable AppArmor 2.4 compatability"
+ depends on SECURITY_APPARMOR
+ default y
+ help
+ This option enables compatability with AppArmor 2.4. It is
+ recommended if compatability with older versions of AppArmor
+ is desired.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index 7cefef9..0bb604b 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
resource.o sid.o file.o net.o
+apparmor-$(CONFIG_SECURITY_APPARMOR_COMPAT_24) += apparmorfs-24.o
clean-files := capability_names.h rlim_names.h af_names.h
diff --git a/security/apparmor/apparmorfs-24.c b/security/apparmor/apparmorfs-24.c
new file mode 100644
index 0000000..dc8c744
--- /dev/null
+++ b/security/apparmor/apparmorfs-24.c
@@ -0,0 +1,287 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /sys/kernel/secrutiy/apparmor interface functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ *
+ * This file contain functions providing an interface for <= AppArmor 2.4
+ * compatibility. It is dependent on CONFIG_SECURITY_APPARMOR_COMPAT_24
+ * being set (see Makefile).
+ */
+
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/policy.h"
+
+
+/* apparmor/matching */
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ const char matching[] = "pattern=aadfa audit perms=crwxamlk/ "
+ "user::other";
+
+ return simple_read_from_buffer(buf, size, ppos, matching,
+ sizeof(matching) - 1);
+}
+
+const struct file_operations aa_fs_matching_fops = {
+ .read = aa_matching_read,
+};
+
+/* apparmor/features */
+static ssize_t aa_features_read(struct file *file, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ const char features[] = "file=3.1 capability=2.0 network=1.0 "
+ "change_hat=1.5 change_profile=1.1 " "aanamespaces=1.1 rlimit=1.1";
+
+ return simple_read_from_buffer(buf, size, ppos, features,
+ sizeof(features) - 1);
+}
+
+const struct file_operations aa_fs_features_fops = {
+ .read = aa_features_read,
+};
+
+/**
+ * __next_namespace - find the next namespace to list
+ * @root: root namespace to stop search at (NOT NULL)
+ * @ns: current ns position (NOT NULL)
+ *
+ * Find the next namespace from @ns under @root and handle all locking needed
+ * while switching current namespace.
+ *
+ * Returns: next namespace or NULL if at last namespace under @root
+ * NOTE: will not unlock root->lock
+ */
+static struct aa_namespace *__next_namespace(struct aa_namespace *root,
+ struct aa_namespace *ns)
+{
+ struct aa_namespace *parent;
+
+ /* is next namespace a child */
+ if (!list_empty(&ns->sub_ns)) {
+ struct aa_namespace *next;
+ next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
+ read_lock(&next->lock);
+ return next;
+ }
+
+ /* check if the next ns is a sibling, parent, gp, .. */
+ parent = ns->parent;
+ while (parent) {
+ read_unlock(&ns->lock);
+ list_for_each_entry_continue(ns, &parent->sub_ns, base.list) {
+ read_lock(&ns->lock);
+ return ns;
+ }
+ if (parent == root)
+ return NULL;
+ ns = parent;
+ parent = parent->parent;
+ }
+
+ return NULL;
+}
+
+/**
+ * __first_profile - find the first profile in a namespace
+ * @root: namespace that is root of profiles being displayed (NOT NULL)
+ * @ns: namespace to start in (NOT NULL)
+ *
+ * Returns: unrefcounted profile or NULL if no profile
+ */
+static struct aa_profile *__first_profile(struct aa_namespace *root,
+ struct aa_namespace *ns)
+{
+ for ( ; ns; ns = __next_namespace(root, ns)) {
+ if (!list_empty(&ns->base.profiles))
+ return list_first_entry(&ns->base.profiles,
+ struct aa_profile, base.list);
+ }
+ return NULL;
+}
+
+/**
+ * __next_profile - step to the next profile in a profile tree
+ * @profile: current profile in tree (NOT NULL)
+ *
+ * Perform a depth first taversal on the profile tree in a namespace
+ *
+ * Returns: next profile or NULL if done
+ * Requires: profile->ns.lock to be held
+ */
+static struct aa_profile *__next_profile(struct aa_profile *p)
+{
+ struct aa_profile *parent;
+ struct aa_namespace *ns = p->ns;
+
+ /* is next profile a child */
+ if (!list_empty(&p->base.profiles))
+ return list_first_entry(&p->base.profiles, typeof(*p),
+ base.list);
+
+ /* is next profile a sibling, parent sibling, gp, subling, .. */
+ parent = p->parent;
+ while (parent) {
+ list_for_each_entry_continue(p, &parent->base.profiles,
+ base.list)
+ return p;
+ p = parent;
+ parent = parent->parent;
+ }
+
+ /* is next another profile in the namespace */
+ list_for_each_entry_continue(p, &ns->base.profiles, base.list)
+ return p;
+
+ return NULL;
+}
+
+/**
+ * next_profile - step to the next profile in where ever it may be
+ * @root: root namespace (NOT NULL)
+ * @profile: current profile (NOT NULL)
+ *
+ * Returns: next profile or NULL if there isn't one
+ */
+static struct aa_profile *next_profile(struct aa_namespace *root,
+ struct aa_profile *profile)
+{
+ struct aa_profile *next = __next_profile(profile);
+ if (next)
+ return next;
+
+ /* finished all profiles in namespace move to next namespace */
+ return __first_profile(root, __next_namespace(root, profile->ns));
+}
+
+/**
+ * p_start - start a depth first traversal of profile tree
+ * @f: seq_file to fill
+ * @pos: current position
+ *
+ * Returns: first profile under current namespace or NULL if none found
+ *
+ * acquires first ns->lock
+ */
+static void *p_start(struct seq_file *f, loff_t *pos)
+ __acquires(root->lock)
+{
+ struct aa_profile *profile = NULL;
+ struct aa_namespace *root = aa_current_profile()->ns;
+ loff_t l = *pos;
+ f->private = aa_get_namespace(root);
+
+
+ /* find the first profile */
+ read_lock(&root->lock);
+ profile = __first_profile(root, root);
+
+ /* skip to position */
+ for (; profile && l > 0; l--)
+ profile = next_profile(root, profile);
+
+ return profile;
+}
+
+/**
+ * p_next - read the next profile entry
+ * @f: seq_file to fill
+ * @p: profile previously returned
+ * @pos: current position
+ *
+ * Returns: next profile after @p or NULL if none
+ *
+ * may acquire/release locks in namespace tree as necessary
+ */
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
+{
+ struct aa_profile *profile = p;
+ struct aa_namespace *root = f->private;
+ (*pos)++;
+
+ return next_profile(root, profile);
+}
+
+/**
+ * p_stop - stop depth first traversal
+ * @f: seq_file we are filling
+ * @p: the last profile writen
+ *
+ * Release all locking done by p_start/p_next on namespace tree
+ */
+static void p_stop(struct seq_file *f, void *p)
+ __releases(root->lock)
+{
+ struct aa_profile *profile = p;
+ struct aa_namespace *root = f->private, *ns;
+
+ if (profile) {
+ for (ns = profile->ns; ns && ns != root; ns = ns->parent)
+ read_unlock(&ns->lock);
+ }
+ read_unlock(&root->lock);
+ aa_put_namespace(root);
+}
+
+/**
+ * seq_show_profile - show a profile entry
+ * @f: seq_file to file
+ * @p: current position (profile) (NOT NULL)
+ *
+ * Returns: error on failure
+ */
+static int seq_show_profile(struct seq_file *f, void *p)
+{
+ struct aa_profile *profile = (struct aa_profile *)p;
+ struct aa_namespace *root = f->private;
+
+ if (profile->ns != root)
+ seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
+ seq_printf(f, "%s (%s)\n", profile->base.hname,
+ COMPLAIN_MODE(profile) ? "complain" : "enforce");
+
+ return 0;
+}
+
+static const struct seq_operations aa_fs_profiles_op = {
+ .start = p_start,
+ .next = p_next,
+ .stop = p_stop,
+ .show = seq_show_profile,
+};
+
+static int profiles_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &aa_fs_profiles_op);
+}
+
+static int profiles_release(struct inode *inode, struct file *file)
+{
+ return seq_release(inode, file);
+}
+
+const struct file_operations aa_fs_profiles_fops = {
+ .open = profiles_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = profiles_release,
+};
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 69ddb47..867995c 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -187,7 +187,11 @@ void __init aa_destroy_aafs(void)
aafs_remove(".remove");
aafs_remove(".replace");
aafs_remove(".load");
-
+#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
+ aafs_remove("profiles");
+ aafs_remove("matching");
+ aafs_remove("features");
+#endif
securityfs_remove(aa_fs_dentry);
aa_fs_dentry = NULL;
}
@@ -218,7 +222,17 @@ static int __init aa_create_aafs(void)
aa_fs_dentry = NULL;
goto error;
}
-
+#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
+ error = aafs_create("matching", 0444, &aa_fs_matching_fops);
+ if (error)
+ goto error;
+ error = aafs_create("features", 0444, &aa_fs_features_fops);
+ if (error)
+ goto error;
+#endif
+ error = aafs_create("profiles", 0440, &aa_fs_profiles_fops);
+ if (error)
+ goto error;
error = aafs_create(".load", 0640, &aa_fs_profile_load);
if (error)
goto error;
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index cb1e93a..14f955c 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -17,4 +17,10 @@
extern void __init aa_destroy_aafs(void);
+#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
+extern const struct file_operations aa_fs_matching_fops;
+extern const struct file_operations aa_fs_features_fops;
+extern const struct file_operations aa_fs_profiles_fops;
+#endif
+
#endif /* __AA_APPARMORFS_H */
--
1.7.9.5

View File

@ -1,69 +0,0 @@
From e5d90918aa31f948ecec2f3c088567dbab30c90b Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 10 Aug 2011 22:02:41 -0700
Subject: [PATCH 3/3] AppArmor: Allow dfa backward compatibility with broken
userspace
The apparmor_parser when compiling policy could generate invalid dfas
that did not have sufficient padding to avoid invalid references, when
used by the kernel. The kernels check to verify the next/check table
size was broken meaning invalid dfas were being created by userspace
and not caught.
To remain compatible with old tools that are not fixed, pad the loaded
dfas next/check table. The dfa's themselves are valid except for the
high padding for potentially invalid transitions (high bounds error),
which have a maximimum is 256 entries. So just allocate an extra null filled
256 entries for the next/check tables. This will guarentee all bounds
are good and invalid transitions go to the null (0) state.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/match.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index 94de6b4..081491e 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -57,8 +57,17 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
if (bsize < tsize)
goto out;
+ /* Pad table allocation for next/check by 256 entries to remain
+ * backwards compatible with old (buggy) tools and remain safe without
+ * run time checks
+ */
+ if (th.td_id == YYTD_ID_NXT || th.td_id == YYTD_ID_CHK)
+ tsize += 256 * th.td_flags;
+
table = kvmalloc(tsize);
if (table) {
+ /* ensure the pad is clear, else there will be errors */
+ memset(table, 0, tsize);
*table = th;
if (th.td_flags == YYTD_DATA8)
UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
@@ -134,11 +143,19 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
goto out;
if (flags & DFA_FLAG_VERIFY_STATES) {
+ int warning = 0;
for (i = 0; i < state_count; i++) {
if (DEFAULT_TABLE(dfa)[i] >= state_count)
goto out;
/* TODO: do check that DEF state recursion terminates */
if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
+ if (warning)
+ continue;
+ printk(KERN_WARNING "AppArmor DFA next/check "
+ "upper bounds error fixed, upgrade "
+ "user space tools \n");
+ warning = 1;
+ } else if (BASE_TABLE(dfa)[i] >= trans_count) {
printk(KERN_ERR "AppArmor DFA next/check upper "
"bounds error\n");
goto out;
--
1.7.9.5

View File

@ -1,264 +0,0 @@
From 8de755e4dfdbc40bfcaca848ae6b5aeaf0ede0e8 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Thu, 22 Jul 2010 02:32:02 -0700
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: Add profile introspection file
to interface
Add the dynamic profiles file to the interace, to allow load policy
introspection.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Kees Cook <kees@ubuntu.com>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
security/apparmor/apparmorfs.c | 227 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 227 insertions(+)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 16c15ec..89bdc62 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -182,6 +182,232 @@ const struct file_operations aa_fs_seq_file_ops = {
.release = single_release,
};
+/**
+ * __next_namespace - find the next namespace to list
+ * @root: root namespace to stop search at (NOT NULL)
+ * @ns: current ns position (NOT NULL)
+ *
+ * Find the next namespace from @ns under @root and handle all locking needed
+ * while switching current namespace.
+ *
+ * Returns: next namespace or NULL if at last namespace under @root
+ * NOTE: will not unlock root->lock
+ */
+static struct aa_namespace *__next_namespace(struct aa_namespace *root,
+ struct aa_namespace *ns)
+{
+ struct aa_namespace *parent;
+
+ /* is next namespace a child */
+ if (!list_empty(&ns->sub_ns)) {
+ struct aa_namespace *next;
+ next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
+ read_lock(&next->lock);
+ return next;
+ }
+
+ /* check if the next ns is a sibling, parent, gp, .. */
+ parent = ns->parent;
+ while (parent) {
+ read_unlock(&ns->lock);
+ list_for_each_entry_continue(ns, &parent->sub_ns, base.list) {
+ read_lock(&ns->lock);
+ return ns;
+ }
+ if (parent == root)
+ return NULL;
+ ns = parent;
+ parent = parent->parent;
+ }
+
+ return NULL;
+}
+
+/**
+ * __first_profile - find the first profile in a namespace
+ * @root: namespace that is root of profiles being displayed (NOT NULL)
+ * @ns: namespace to start in (NOT NULL)
+ *
+ * Returns: unrefcounted profile or NULL if no profile
+ */
+static struct aa_profile *__first_profile(struct aa_namespace *root,
+ struct aa_namespace *ns)
+{
+ for ( ; ns; ns = __next_namespace(root, ns)) {
+ if (!list_empty(&ns->base.profiles))
+ return list_first_entry(&ns->base.profiles,
+ struct aa_profile, base.list);
+ }
+ return NULL;
+}
+
+/**
+ * __next_profile - step to the next profile in a profile tree
+ * @profile: current profile in tree (NOT NULL)
+ *
+ * Perform a depth first taversal on the profile tree in a namespace
+ *
+ * Returns: next profile or NULL if done
+ * Requires: profile->ns.lock to be held
+ */
+static struct aa_profile *__next_profile(struct aa_profile *p)
+{
+ struct aa_profile *parent;
+ struct aa_namespace *ns = p->ns;
+
+ /* is next profile a child */
+ if (!list_empty(&p->base.profiles))
+ return list_first_entry(&p->base.profiles, typeof(*p),
+ base.list);
+
+ /* is next profile a sibling, parent sibling, gp, subling, .. */
+ parent = p->parent;
+ while (parent) {
+ list_for_each_entry_continue(p, &parent->base.profiles,
+ base.list)
+ return p;
+ p = parent;
+ parent = parent->parent;
+ }
+
+ /* is next another profile in the namespace */
+ list_for_each_entry_continue(p, &ns->base.profiles, base.list)
+ return p;
+
+ return NULL;
+}
+
+/**
+ * next_profile - step to the next profile in where ever it may be
+ * @root: root namespace (NOT NULL)
+ * @profile: current profile (NOT NULL)
+ *
+ * Returns: next profile or NULL if there isn't one
+ */
+static struct aa_profile *next_profile(struct aa_namespace *root,
+ struct aa_profile *profile)
+{
+ struct aa_profile *next = __next_profile(profile);
+ if (next)
+ return next;
+
+ /* finished all profiles in namespace move to next namespace */
+ return __first_profile(root, __next_namespace(root, profile->ns));
+}
+
+/**
+ * p_start - start a depth first traversal of profile tree
+ * @f: seq_file to fill
+ * @pos: current position
+ *
+ * Returns: first profile under current namespace or NULL if none found
+ *
+ * acquires first ns->lock
+ */
+static void *p_start(struct seq_file *f, loff_t *pos)
+ __acquires(root->lock)
+{
+ struct aa_profile *profile = NULL;
+ struct aa_namespace *root = aa_current_profile()->ns;
+ loff_t l = *pos;
+ f->private = aa_get_namespace(root);
+
+
+ /* find the first profile */
+ read_lock(&root->lock);
+ profile = __first_profile(root, root);
+
+ /* skip to position */
+ for (; profile && l > 0; l--)
+ profile = next_profile(root, profile);
+
+ return profile;
+}
+
+/**
+ * p_next - read the next profile entry
+ * @f: seq_file to fill
+ * @p: profile previously returned
+ * @pos: current position
+ *
+ * Returns: next profile after @p or NULL if none
+ *
+ * may acquire/release locks in namespace tree as necessary
+ */
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
+{
+ struct aa_profile *profile = p;
+ struct aa_namespace *root = f->private;
+ (*pos)++;
+
+ return next_profile(root, profile);
+}
+
+/**
+ * p_stop - stop depth first traversal
+ * @f: seq_file we are filling
+ * @p: the last profile writen
+ *
+ * Release all locking done by p_start/p_next on namespace tree
+ */
+static void p_stop(struct seq_file *f, void *p)
+ __releases(root->lock)
+{
+ struct aa_profile *profile = p;
+ struct aa_namespace *root = f->private, *ns;
+
+ if (profile) {
+ for (ns = profile->ns; ns && ns != root; ns = ns->parent)
+ read_unlock(&ns->lock);
+ }
+ read_unlock(&root->lock);
+ aa_put_namespace(root);
+}
+
+/**
+ * seq_show_profile - show a profile entry
+ * @f: seq_file to file
+ * @p: current position (profile) (NOT NULL)
+ *
+ * Returns: error on failure
+ */
+static int seq_show_profile(struct seq_file *f, void *p)
+{
+ struct aa_profile *profile = (struct aa_profile *)p;
+ struct aa_namespace *root = f->private;
+
+ if (profile->ns != root)
+ seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
+ seq_printf(f, "%s (%s)\n", profile->base.hname,
+ COMPLAIN_MODE(profile) ? "complain" : "enforce");
+
+ return 0;
+}
+
+static const struct seq_operations aa_fs_profiles_op = {
+ .start = p_start,
+ .next = p_next,
+ .stop = p_stop,
+ .show = seq_show_profile,
+};
+
+static int profiles_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &aa_fs_profiles_op);
+}
+
+static int profiles_release(struct inode *inode, struct file *file)
+{
+ return seq_release(inode, file);
+}
+
+const struct file_operations aa_fs_profiles_fops = {
+ .open = profiles_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = profiles_release,
+};
+
/** Base file system setup **/
static struct aa_fs_entry aa_fs_entry_file[] = {
@@ -210,6 +436,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = {
AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
+ AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
AA_FS_DIR("features", aa_fs_entry_features),
{ }
};
--
1.7.9.5

View File

@ -1,603 +0,0 @@
From 423e2cb454d75d6185eecd0c1b5cf6ccc2d8482d Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Mon, 4 Oct 2010 15:03:36 -0700
Subject: [PATCH 2/3] UBUNTU: SAUCE: AppArmor: basic networking rules
Base support for network mediation.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/.gitignore | 2 +-
security/apparmor/Makefile | 42 +++++++++-
security/apparmor/apparmorfs.c | 1 +
security/apparmor/include/audit.h | 4 +
security/apparmor/include/net.h | 44 ++++++++++
security/apparmor/include/policy.h | 3 +
security/apparmor/lsm.c | 112 +++++++++++++++++++++++++
security/apparmor/net.c | 162 ++++++++++++++++++++++++++++++++++++
security/apparmor/policy.c | 1 +
security/apparmor/policy_unpack.c | 46 ++++++++++
10 files changed, 414 insertions(+), 3 deletions(-)
create mode 100644 security/apparmor/include/net.h
create mode 100644 security/apparmor/net.c
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
index 4d995ae..d5b291e 100644
--- a/security/apparmor/.gitignore
+++ b/security/apparmor/.gitignore
@@ -1,6 +1,6 @@
#
# Generated include files
#
-af_names.h
+net_names.h
capability_names.h
rlim_names.h
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index 806bd19..19daa85 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,9 +4,9 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
- resource.o sid.o file.o
+ resource.o sid.o file.o net.o
-clean-files := capability_names.h rlim_names.h
+clean-files := capability_names.h rlim_names.h net_names.h
# Build a lower case string table of capability names
@@ -20,6 +20,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
echo "};" >> $@
+# Build a lower case string table of address family names
+# Transform lines from
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# [1] = "local",
+# [2] = "inet",
+#
+# and build the securityfs entries for the mapping.
+# Transforms lines from
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# #define AA_FS_AF_MASK "local inet"
+quiet_cmd_make-af = GEN $@
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@ ;\
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+
+# Build a lower case string table of sock type names
+# Transform lines from
+# SOCK_STREAM = 1,
+# to
+# [1] = "stream",
+quiet_cmd_make-sock = GEN $@
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
+ sed $^ >>$@ -r -n \
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@
# Build a lower case string table of rlimit names.
# Transforms lines from
@@ -56,6 +88,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
$(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/net.o : $(obj)/net_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
$(src)/Makefile
@@ -63,3 +96,8 @@ $(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \
$(src)/Makefile
$(call cmd,make-rlim)
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
+ $(srctree)/include/linux/net.h \
+ $(src)/Makefile
+ $(call cmd,make-af)
+ $(call cmd,make-sock)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 89bdc62..c66315d 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -427,6 +427,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
+ AA_FS_DIR("network", aa_fs_entry_network),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
{ }
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 3868b1e..c1ff09c 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -126,6 +126,10 @@ struct apparmor_audit_data {
u32 denied;
uid_t ouid;
} fs;
+ struct {
+ int type, protocol;
+ struct sock *sk;
+ } net;
};
};
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
new file mode 100644
index 0000000..cb8a121
--- /dev/null
+++ b/security/apparmor/include/net.h
@@ -0,0 +1,44 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_NET_H
+#define __AA_NET_H
+
+#include <net/sock.h>
+
+#include "apparmorfs.h"
+
+/* struct aa_net - network confinement data
+ * @allowed: basic network families permissions
+ * @audit_network: which network permissions to force audit
+ * @quiet_network: which network permissions to quiet rejects
+ */
+struct aa_net {
+ u16 allow[AF_MAX];
+ u16 audit[AF_MAX];
+ u16 quiet[AF_MAX];
+};
+
+extern struct aa_fs_entry aa_fs_entry_network[];
+
+extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
+ int type, int protocol, struct sock *sk);
+extern int aa_revalidate_sk(int op, struct sock *sk);
+
+static inline void aa_free_net_rules(struct aa_net *new)
+{
+ /* NOP */
+}
+
+#endif /* __AA_NET_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index bda4569..eb13a73 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -27,6 +27,7 @@
#include "capability.h"
#include "domain.h"
#include "file.h"
+#include "net.h"
#include "resource.h"
extern const char *const profile_mode_names[];
@@ -157,6 +158,7 @@ struct aa_policydb {
* @policy: general match rules governing policy
* @file: The set of rules governing basic file access and domain transitions
* @caps: capabilities for the profile
+ * @net: network controls for the profile
* @rlimits: rlimits for the profile
*
* The AppArmor profile contains the basic confinement data. Each profile
@@ -194,6 +196,7 @@ struct aa_profile {
struct aa_policydb policy;
struct aa_file_rules file;
struct aa_caps caps;
+ struct aa_net net;
struct aa_rlimit rlimits;
};
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index ad05d39..3cde194 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -32,6 +32,7 @@
#include "include/context.h"
#include "include/file.h"
#include "include/ipc.h"
+#include "include/net.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/procattr.h"
@@ -622,6 +623,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (kern)
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
+ NULL);
+ return error;
+}
+
+static int apparmor_socket_bind(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_BIND, sk);
+}
+
+static int apparmor_socket_connect(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_CONNECT, sk);
+}
+
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_LISTEN, sk);
+}
+
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_ACCEPT, sk);
+}
+
+static int apparmor_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg, int size)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SENDMSG, sk);
+}
+
+static int apparmor_socket_recvmsg(struct socket *sock,
+ struct msghdr *msg, int size, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_RECVMSG, sk);
+}
+
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
+}
+
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
+}
+
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
+}
+
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
+}
+
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
+}
+
static struct security_operations apparmor_ops = {
.name = "apparmor",
@@ -653,6 +752,19 @@ static struct security_operations apparmor_ops = {
.getprocattr = apparmor_getprocattr,
.setprocattr = apparmor_setprocattr,
+ .socket_create = apparmor_socket_create,
+ .socket_bind = apparmor_socket_bind,
+ .socket_connect = apparmor_socket_connect,
+ .socket_listen = apparmor_socket_listen,
+ .socket_accept = apparmor_socket_accept,
+ .socket_sendmsg = apparmor_socket_sendmsg,
+ .socket_recvmsg = apparmor_socket_recvmsg,
+ .socket_getsockname = apparmor_socket_getsockname,
+ .socket_getpeername = apparmor_socket_getpeername,
+ .socket_getsockopt = apparmor_socket_getsockopt,
+ .socket_setsockopt = apparmor_socket_setsockopt,
+ .socket_shutdown = apparmor_socket_shutdown,
+
.cred_alloc_blank = apparmor_cred_alloc_blank,
.cred_free = apparmor_cred_free,
.cred_prepare = apparmor_cred_prepare,
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
new file mode 100644
index 0000000..084232b
--- /dev/null
+++ b/security/apparmor/net.c
@@ -0,0 +1,162 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/net.h"
+#include "include/policy.h"
+
+#include "net_names.h"
+
+struct aa_fs_entry aa_fs_entry_network[] = {
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
+ { }
+};
+
+/* audit callback for net specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ audit_log_format(ab, " family=");
+ if (address_family_names[sa->u.net->family]) {
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
+ }
+ audit_log_format(ab, " sock_type=");
+ if (sock_type_names[sa->aad->net.type]) {
+ audit_log_string(ab, sock_type_names[sa->aad->net.type]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
+ }
+ audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
+}
+
+/**
+ * audit_net - audit network access
+ * @profile: profile being enforced (NOT NULL)
+ * @op: operation being checked
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ * @sk: socket auditing is being applied to
+ * @error: error code for failure else 0
+ *
+ * Returns: %0 or sa->error else other errorcode on failure
+ */
+static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
+ int protocol, struct sock *sk, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ struct common_audit_data sa;
+ struct apparmor_audit_data aad = { };
+ struct lsm_network_audit net = { };
+ if (sk) {
+ COMMON_AUDIT_DATA_INIT(&sa, NET);
+ } else {
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ }
+ /* todo fill in socket addr info */
+ sa.aad = &aad;
+ sa.u.net = &net;
+ sa.aad->op = op,
+ sa.u.net->family = family;
+ sa.u.net->sk = sk;
+ sa.aad->net.type = type;
+ sa.aad->net.protocol = protocol;
+ sa.aad->error = error;
+
+ if (likely(!sa.aad->error)) {
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+ !(1 << sa.aad->net.type & audit_mask)))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
+ u16 kill_mask = 0;
+ u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
+
+ if (denied & kill_mask)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ if ((denied & quiet_mask) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
+ }
+
+ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
+}
+
+/**
+ * aa_net_perm - very course network access check
+ * @op: operation being checked
+ * @profile: profile being enforced (NOT NULL)
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
+ int protocol, struct sock *sk)
+{
+ u16 family_mask;
+ int error;
+
+ if ((family < 0) || (family >= AF_MAX))
+ return -EINVAL;
+
+ if ((type < 0) || (type >= SOCK_MAX))
+ return -EINVAL;
+
+ /* unix domain and netlink sockets are handled by ipc */
+ if (family == AF_UNIX || family == AF_NETLINK)
+ return 0;
+
+ family_mask = profile->net.allow[family];
+
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+ return audit_net(profile, op, family, type, protocol, sk, error);
+}
+
+/**
+ * aa_revalidate_sk - Revalidate access to a sock
+ * @op: operation being checked
+ * @sk: sock being revalidated (NOT NULL)
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_revalidate_sk(int op, struct sock *sk)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* aa_revalidate_sk should not be called from interrupt context
+ * don't mediate these calls as they are not task related
+ */
+ if (in_interrupt())
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
+ sk->sk_protocol, sk);
+
+ return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index f1f7506..b8100a7 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -745,6 +745,7 @@ static void free_profile(struct aa_profile *profile)
aa_free_file_rules(&profile->file);
aa_free_cap_rules(&profile->caps);
+ aa_free_net_rules(&profile->net);
aa_free_rlimit_rules(&profile->rlimits);
aa_free_sid(profile->sid);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index deab7c7..8f8e9c1 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -193,6 +193,19 @@ fail:
return 0;
}
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
+{
+ if (unpack_nameX(e, AA_U16, name)) {
+ if (!inbounds(e, sizeof(u16)))
+ return 0;
+ if (data)
+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
+ e->pos += sizeof(u16);
+ return 1;
+ }
+ return 0;
+}
+
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
{
if (unpack_nameX(e, AA_U32, name)) {
@@ -471,6 +484,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
{
struct aa_profile *profile = NULL;
const char *name = NULL;
+ size_t size = 0;
int i, error = -EPROTO;
kernel_cap_t tmpcap;
u32 tmp;
@@ -564,6 +578,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
if (!unpack_rlimits(e, profile))
goto fail;
+ size = unpack_array(e, "net_allowed_af");
+ if (size) {
+
+ for (i = 0; i < size; i++) {
+ /* discard extraneous rules that this kernel will
+ * never request
+ */
+ if (i >= AF_MAX) {
+ u16 tmp;
+ if (!unpack_u16(e, &tmp, NULL) ||
+ !unpack_u16(e, &tmp, NULL) ||
+ !unpack_u16(e, &tmp, NULL))
+ goto fail;
+ continue;
+ }
+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
+ goto fail;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ }
+ /*
+ * allow unix domain and netlink sockets they are handled
+ * by IPC
+ */
+ profile->net.allow[AF_UNIX] = 0xffff;
+ profile->net.allow[AF_NETLINK] = 0xffff;
+
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
profile->policy.dfa = unpack_dfa(e);
--
1.7.9.5

View File

@ -1,957 +0,0 @@
From a94d5e11c0484af59e5feebf144cc48c186892ad Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 May 2012 10:58:05 -0700
Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate
mount
Add the ability for apparmor to do mediation of mount operations. Mount
rules require an updated apparmor_parser (2.8 series) for policy compilation.
The basic form of the rules are.
[audit] [deny] mount [conds]* [device] [ -> [conds] path],
[audit] [deny] remount [conds]* [path],
[audit] [deny] umount [conds]* [path],
[audit] [deny] pivotroot [oldroot=<value>] <path>
remount is just a short cut for mount options=remount
where [conds] can be
fstype=<expr>
options=<expr>
Example mount commands
mount, # allow all mounts, but not umount or pivotroot
mount fstype=procfs, # allow mounting procfs anywhere
mount options=(bind, ro) /foo -> /bar, # readonly bind mount
mount /dev/sda -> /mnt,
mount /dev/sd** -> /mnt/**,
mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
umount,
umount /m*,
See the apparmor userspace for full documentation
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Kees Cook <kees@ubuntu.com>
---
security/apparmor/Makefile | 2 +-
security/apparmor/apparmorfs.c | 13 +
security/apparmor/audit.c | 4 +
security/apparmor/domain.c | 2 +-
security/apparmor/include/apparmor.h | 3 +-
security/apparmor/include/audit.h | 11 +
security/apparmor/include/domain.h | 2 +
security/apparmor/include/mount.h | 54 +++
security/apparmor/lsm.c | 59 ++++
security/apparmor/mount.c | 620 ++++++++++++++++++++++++++++++++++
10 files changed, 767 insertions(+), 3 deletions(-)
create mode 100644 security/apparmor/include/mount.h
create mode 100644 security/apparmor/mount.c
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index 19daa85..63e0a4c 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
- resource.o sid.o file.o net.o
+ resource.o sid.o file.o net.o mount.o
clean-files := capability_names.h rlim_names.h net_names.h
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index c66315d..ff19009 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -424,10 +424,23 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
{ }
};
+static struct aa_fs_entry aa_fs_entry_mount[] = {
+ AA_FS_FILE_STRING("mask", "mount umount"),
+ { }
+};
+
+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
+ AA_FS_FILE_BOOLEAN("profile", 1),
+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
+ { }
+};
+
static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
AA_FS_DIR("network", aa_fs_entry_network),
+ AA_FS_DIR("mount", aa_fs_entry_mount),
+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
{ }
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index cc3520d..b9f5ee9 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -44,6 +44,10 @@ const char *const op_table[] = {
"file_mmap",
"file_mprotect",
+ "pivotroot",
+ "mount",
+ "umount",
+
"create",
"post_create",
"bind",
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 6327685..dfdc47b 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -242,7 +242,7 @@ static const char *next_name(int xtype, const char *name)
*
* Returns: refcounted profile, or NULL on failure (MAYBE NULL)
*/
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
{
struct aa_profile *new_profile = NULL;
struct aa_namespace *ns = profile->ns;
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 40aedd9..e243d96 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -29,8 +29,9 @@
#define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
+#define AA_CLASS_MOUNT 7
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
+#define AA_CLASS_LAST AA_CLASS_MOUNT
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index c1ff09c..7b90900c 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -73,6 +73,10 @@ enum aa_ops {
OP_FMMAP,
OP_FMPROT,
+ OP_PIVOTROOT,
+ OP_MOUNT,
+ OP_UMOUNT,
+
OP_CREATE,
OP_POST_CREATE,
OP_BIND,
@@ -121,6 +125,13 @@ struct apparmor_audit_data {
unsigned long max;
} rlim;
struct {
+ const char *src_name;
+ const char *type;
+ const char *trans;
+ const char *data;
+ unsigned long flags;
+ } mnt;
+ struct {
const char *target;
u32 request;
u32 denied;
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
index de04464..a3f70c5 100644
--- a/security/apparmor/include/domain.h
+++ b/security/apparmor/include/domain.h
@@ -23,6 +23,8 @@ struct aa_domain {
char **table;
};
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
+
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
new file mode 100644
index 0000000..bc17a53
--- /dev/null
+++ b/security/apparmor/include/mount.h
@@ -0,0 +1,54 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor file mediation function definitions.
+ *
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_MOUNT_H
+#define __AA_MOUNT_H
+
+#include <linux/fs.h>
+#include <linux/path.h>
+
+#include "domain.h"
+#include "policy.h"
+
+/* mount perms */
+#define AA_MAY_PIVOTROOT 0x01
+#define AA_MAY_MOUNT 0x02
+#define AA_MAY_UMOUNT 0x04
+#define AA_AUDIT_DATA 0x40
+#define AA_CONT_MATCH 0x40
+
+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
+
+int aa_remount(struct aa_profile *profile, struct path *path,
+ unsigned long flags, void *data);
+
+int aa_bind_mount(struct aa_profile *profile, struct path *path,
+ const char *old_name, unsigned long flags);
+
+
+int aa_mount_change_type(struct aa_profile *profile, struct path *path,
+ unsigned long flags);
+
+int aa_move_mount(struct aa_profile *profile, struct path *path,
+ const char *old_name);
+
+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
+ struct path *path, const char *type, unsigned long flags,
+ void *data);
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
+
+int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
+ struct path *new_path);
+
+#endif /* __AA_MOUNT_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 3cde194..4512cc6 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -36,6 +36,7 @@
#include "include/path.h"
#include "include/policy.h"
#include "include/procattr.h"
+#include "include/mount.h"
/* Flag indicating whether initialization completed */
int apparmor_initialized __initdata;
@@ -512,6 +513,60 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
}
+static int apparmor_sb_mount(char *dev_name, struct path *path, char *type,
+ unsigned long flags, void *data)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* Discard magic */
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
+
+ flags &= ~AA_MS_IGNORE_MASK;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile)) {
+ if (flags & MS_REMOUNT)
+ error = aa_remount(profile, path, flags, data);
+ else if (flags & MS_BIND)
+ error = aa_bind_mount(profile, path, dev_name, flags);
+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE))
+ error = aa_mount_change_type(profile, path, flags);
+ else if (flags & MS_MOVE)
+ error = aa_move_mount(profile, path, dev_name);
+ else
+ error = aa_new_mount(profile, dev_name, path, type,
+ flags, data);
+ }
+ return error;
+}
+
+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_umount(profile, mnt, flags);
+
+ return error;
+}
+
+static int apparmor_sb_pivotroot(struct path *old_path, struct path *new_path)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_pivotroot(profile, old_path, new_path);
+
+ return error;
+}
+
static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value)
{
@@ -729,6 +784,10 @@ static struct security_operations apparmor_ops = {
.capget = apparmor_capget,
.capable = apparmor_capable,
+ .sb_mount = apparmor_sb_mount,
+ .sb_umount = apparmor_sb_umount,
+ .sb_pivotroot = apparmor_sb_pivotroot,
+
.path_link = apparmor_path_link,
.path_unlink = apparmor_path_unlink,
.path_symlink = apparmor_path_symlink,
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
new file mode 100644
index 0000000..63d8493
--- /dev/null
+++ b/security/apparmor/mount.c
@@ -0,0 +1,620 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor mediation of files
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/domain.h"
+#include "include/file.h"
+#include "include/match.h"
+#include "include/mount.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+
+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
+{
+ if (flags & MS_RDONLY)
+ audit_log_format(ab, "ro");
+ else
+ audit_log_format(ab, "rw");
+ if (flags & MS_NOSUID)
+ audit_log_format(ab, ", nosuid");
+ if (flags & MS_NODEV)
+ audit_log_format(ab, ", nodev");
+ if (flags & MS_NOEXEC)
+ audit_log_format(ab, ", noexec");
+ if (flags & MS_SYNCHRONOUS)
+ audit_log_format(ab, ", sync");
+ if (flags & MS_REMOUNT)
+ audit_log_format(ab, ", remount");
+ if (flags & MS_MANDLOCK)
+ audit_log_format(ab, ", mand");
+ if (flags & MS_DIRSYNC)
+ audit_log_format(ab, ", dirsync");
+ if (flags & MS_NOATIME)
+ audit_log_format(ab, ", noatime");
+ if (flags & MS_NODIRATIME)
+ audit_log_format(ab, ", nodiratime");
+ if (flags & MS_BIND)
+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
+ if (flags & MS_MOVE)
+ audit_log_format(ab, ", move");
+ if (flags & MS_SILENT)
+ audit_log_format(ab, ", silent");
+ if (flags & MS_POSIXACL)
+ audit_log_format(ab, ", acl");
+ if (flags & MS_UNBINDABLE)
+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
+ ", unbindable");
+ if (flags & MS_PRIVATE)
+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
+ ", private");
+ if (flags & MS_SLAVE)
+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
+ ", slave");
+ if (flags & MS_SHARED)
+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
+ ", shared");
+ if (flags & MS_RELATIME)
+ audit_log_format(ab, ", relatime");
+ if (flags & MS_I_VERSION)
+ audit_log_format(ab, ", iversion");
+ if (flags & MS_STRICTATIME)
+ audit_log_format(ab, ", strictatime");
+ if (flags & MS_NOUSER)
+ audit_log_format(ab, ", nouser");
+}
+
+/**
+ * audit_cb - call back for mount specific audit fields
+ * @ab: audit_buffer (NOT NULL)
+ * @va: audit struct to audit values of (NOT NULL)
+ */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ if (sa->aad->mnt.type) {
+ audit_log_format(ab, " fstype=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.type);
+ }
+ if (sa->aad->mnt.src_name) {
+ audit_log_format(ab, " srcname=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
+ }
+ if (sa->aad->mnt.trans) {
+ audit_log_format(ab, " trans=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.trans);
+ }
+ if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
+ audit_log_format(ab, " flags=\"");
+ audit_mnt_flags(ab, sa->aad->mnt.flags);
+ audit_log_format(ab, "\"");
+ }
+ if (sa->aad->mnt.data) {
+ audit_log_format(ab, " options=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.data);
+ }
+}
+
+/**
+ * audit_mount - handle the auditing of mount operations
+ * @profile: the profile being enforced (NOT NULL)
+ * @gfp: allocation flags
+ * @op: operation being mediated (NOT NULL)
+ * @name: name of object being mediated (MAYBE NULL)
+ * @src_name: src_name of object being mediated (MAYBE_NULL)
+ * @type: type of filesystem (MAYBE_NULL)
+ * @trans: name of trans (MAYBE NULL)
+ * @flags: filesystem idependent mount flags
+ * @data: filesystem mount flags
+ * @request: permissions requested
+ * @perms: the permissions computed for the request (NOT NULL)
+ * @info: extra information message (MAYBE NULL)
+ * @error: 0 if operation allowed else failure error code
+ *
+ * Returns: %0 or error on failure
+ */
+static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
+ const char *name, const char *src_name,
+ const char *type, const char *trans,
+ unsigned long flags, const void *data, u32 request,
+ struct file_perms *perms, const char *info, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ struct common_audit_data sa;
+ struct apparmor_audit_data aad = { };
+
+ if (likely(!error)) {
+ u32 mask = perms->audit;
+
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
+ mask = 0xffff;
+
+ /* mask off perms that are not being force audited */
+ request &= mask;
+
+ if (likely(!request))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ /* only report permissions that were denied */
+ request = request & ~perms->allow;
+
+ if (request & perms->kill)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ /* quiet known rejects, assumes quiet and kill do not overlap */
+ if ((request & perms->quiet) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ request &= ~perms->quiet;
+
+ if (!request)
+ return COMPLAIN_MODE(profile) ?
+ complain_error(error) : error;
+ }
+
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad = &aad;
+ sa.aad->op = op;
+ sa.aad->name = name;
+ sa.aad->mnt.src_name = src_name;
+ sa.aad->mnt.type = type;
+ sa.aad->mnt.trans = trans;
+ sa.aad->mnt.flags = flags;
+ if (data && (perms->audit & AA_AUDIT_DATA))
+ sa.aad->mnt.data = data;
+ sa.aad->info = info;
+ sa.aad->error = error;
+
+ return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
+}
+
+/**
+ * match_mnt_flags - Do an ordered match on mount flags
+ * @dfa: dfa to match against
+ * @state: state to start in
+ * @flags: mount flags to match against
+ *
+ * Mount flags are encoded as an ordered match. This is done instead of
+ * checking against a simple bitmask, to allow for logical operations
+ * on the flags.
+ *
+ * Returns: next state after flags match
+ */
+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
+ unsigned long flags)
+{
+ unsigned int i;
+
+ for (i = 0; i <= 31 ; ++i) {
+ if ((1 << i) & flags)
+ state = aa_dfa_next(dfa, state, i + 1);
+ }
+
+ return state;
+}
+
+/**
+ * compute_mnt_perms - compute mount permission associated with @state
+ * @dfa: dfa to match against (NOT NULL)
+ * @state: state match finished in
+ *
+ * Returns: mount permissions
+ */
+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
+ unsigned int state)
+{
+ struct file_perms perms;
+
+ perms.kill = 0;
+ perms.allow = dfa_user_allow(dfa, state);
+ perms.audit = dfa_user_audit(dfa, state);
+ perms.quiet = dfa_user_quiet(dfa, state);
+ perms.xindex = dfa_user_xindex(dfa, state);
+
+ return perms;
+}
+
+static const char const *mnt_info_table[] = {
+ "match succeeded",
+ "failed mntpnt match",
+ "failed srcname match",
+ "failed type match",
+ "failed flags match",
+ "failed data match"
+};
+
+/*
+ * Returns 0 on success else element that match failed in, this is the
+ * index into the mnt_info_table above
+ */
+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
+ const char *mntpnt, const char *devname,
+ const char *type, unsigned long flags,
+ void *data, bool binary, struct file_perms *perms)
+{
+ unsigned int state;
+
+ state = aa_dfa_match(dfa, start, mntpnt);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 1;
+
+ if (devname)
+ state = aa_dfa_match(dfa, state, devname);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 2;
+
+ if (type)
+ state = aa_dfa_match(dfa, state, type);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 3;
+
+ state = match_mnt_flags(dfa, state, flags);
+ if (!state)
+ return 4;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+
+ /* only match data if not binary and the DFA flags data is expected */
+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 4;
+
+ state = aa_dfa_match(dfa, state, data);
+ if (!state)
+ return 5;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+ }
+
+ /* failed at end of flags match */
+ return 4;
+}
+
+/**
+ * match_mnt - handle path matching for mount
+ * @profile: the confining profile
+ * @mntpnt: string for the mntpnt (NOT NULL)
+ * @devname: string for the devname/src_name (MAYBE NULL)
+ * @type: string for the dev type (MAYBE NULL)
+ * @flags: mount flags to match
+ * @data: fs mount data (MAYBE NULL)
+ * @binary: whether @data is binary
+ * @perms: Returns: permission found by the match
+ * @info: Returns: infomation string about the match for logging
+ *
+ * Returns: 0 on success else error
+ */
+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
+ const char *devname, const char *type,
+ unsigned long flags, void *data, bool binary,
+ struct file_perms *perms, const char **info)
+{
+ int pos;
+
+ if (!profile->policy.dfa)
+ return -EACCES;
+
+ pos = do_match_mnt(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ mntpnt, devname, type, flags, data, binary, perms);
+ if (pos) {
+ *info = mnt_info_table[pos];
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static int path_flags(struct aa_profile *profile, struct path *path)
+{
+ return profile->path_flags |
+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
+}
+
+int aa_remount(struct aa_profile *profile, struct path *path,
+ unsigned long flags, void *data)
+{
+ struct file_perms perms = { };
+ const char *name, *info = NULL;
+ char *buffer = NULL;
+ int binary, error;
+
+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_bind_mount(struct aa_profile *profile, struct path *path,
+ const char *dev_name, unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!dev_name || !*dev_name)
+ return -EINVAL;
+
+ flags &= MS_REC | MS_BIND;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_mount_change_type(struct aa_profile *profile, struct path *path,
+ unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ /* These are the flags allowed by do_change_type() */
+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE);
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
+ &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_move_mount(struct aa_profile *profile, struct path *path,
+ const char *orig_name)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!orig_name || !*orig_name)
+ return -EINVAL;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
+ struct path *path, const char *type, unsigned long flags,
+ void *data)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *dev_buffer = NULL;
+ const char *name = NULL, *dev_name = NULL, *info = NULL;
+ int binary = 1;
+ int error;
+
+ dev_name = orig_dev_name;
+ if (type) {
+ int requires_dev;
+ struct file_system_type *fstype = get_fs_type(type);
+ if (!fstype)
+ return -ENODEV;
+
+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
+ put_filesystem(fstype);
+
+ if (requires_dev) {
+ struct path dev_path;
+
+ if (!dev_name || !*dev_name) {
+ error = -ENOENT;
+ goto out;
+ }
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&dev_path,
+ path_flags(profile, &dev_path),
+ &dev_buffer, &dev_name, &info);
+ path_put(&dev_path);
+ if (error)
+ goto audit;
+ }
+ }
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+ kfree(dev_buffer);
+
+out:
+ return error;
+
+}
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ struct path path = { mnt, mnt->mnt_root };
+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ if (!error && profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_UMOUNT & ~perms.allow)
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_pivotroot(struct aa_profile *profile, struct path *old_path,
+ struct path *new_path)
+{
+ struct file_perms perms = { };
+ struct aa_profile *target = NULL;
+ char *old_buffer = NULL, *new_buffer = NULL;
+ const char *old_name, *new_name = NULL, *info = NULL;
+ int error;
+
+ error = aa_path_name(old_path, path_flags(profile, old_path),
+ &old_buffer, &old_name, &info);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(new_path, path_flags(profile, new_path),
+ &new_buffer, &new_name, &info);
+ if (error)
+ goto audit;
+
+ if (profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ new_name);
+ state = aa_dfa_null_transition(profile->policy.dfa, state);
+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_PIVOTROOT & perms.allow) {
+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
+ target = x_table_lookup(profile, perms.xindex);
+ if (!target)
+ error = -ENOENT;
+ else
+ error = aa_replace_current_profile(target);
+ }
+ } else
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
+ old_name, NULL, target ? target->base.name : NULL,
+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
+ aa_put_profile(target);
+ kfree(old_buffer);
+ kfree(new_buffer);
+
+ return error;
+}
--
1.7.9.5

View File

@ -1,24 +0,0 @@
See https://github.com/NixOS/nixpkgs/issues/6231
v3.14.31:crypto/crc32c.c is missing the MODULE_ALIAS_CRYPTO("crc32c").
That's probably because crypto/crc32c.c was renamed to
crypto/crc32c_generic.c in commit
06e5a1f29819759392239669beb2cad27059c8ec and therefore fell through
the cracks when backporting commit
5d26a105b5a73e5635eae0629b42fa0a90e07b7b.
So the affected kernels (all that backported the "crypto-" prefix
patches) need this additional patch:
diff --git a/crypto/crc32c.c b/crypto/crc32c.c
index 06f7018c9d95..aae5829eb681 100644
--- a/crypto/crc32c.c
+++ b/crypto/crc32c.c
@@ -167,6 +167,7 @@ static void __exit crc32c_mod_fini(void)
module_init(crc32c_mod_init);
module_exit(crc32c_mod_fini);
+MODULE_ALIAS_CRYPTO("crc32c");
MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c");
MODULE_LICENSE("GPL");

View File

@ -1,17 +0,0 @@
{ stdenv, fetchurl, ... } @ args:
import ./generic.nix (args // rec {
version = "3.10.73";
extraMeta.branch = "3.10";
src = fetchurl {
url = "mirror://kernel/linux/kernel/v3.x/linux-${version}.tar.xz";
sha256 = "0xy8738sdbw7lbqwkmbhr2zghva5nyfqq163r6jmjr6cfw116kin";
};
features.iwlwifi = true;
features.efiBootStub = true;
features.needsCifsUtils = true;
features.canDisableNetfilterConntrackHelpers = true;
features.netfilterRPFilter = true;
})

View File

@ -1,17 +0,0 @@
{ stdenv, fetchurl, ... } @ args:
import ./generic.nix (args // rec {
version = "3.12.40";
extraMeta.branch = "3.12";
src = fetchurl {
url = "mirror://kernel/linux/kernel/v3.x/linux-${version}.tar.xz";
sha256 = "1cdivv1n0r057y2wq38ci00im8z24jrnvyz5vwhmnzv0l4qzbhw5";
};
features.iwlwifi = true;
features.efiBootStub = true;
features.needsCifsUtils = true;
features.canDisableNetfilterConntrackHelpers = true;
features.netfilterRPFilter = true;
})

View File

@ -1,25 +0,0 @@
{ stdenv, fetchurl, ... } @ args:
import ./generic.nix (args // rec {
version = "3.14.37";
# Remember to update grsecurity!
extraMeta.branch = "3.14";
src = fetchurl {
url = "mirror://kernel/linux/kernel/v3.x/linux-${version}.tar.xz";
sha256 = "1pq4i97vys38rl8ylx4s08qgh9yz3cl840j1f70yzakmc2017byc";
};
# FIXME: remove with the next point release.
kernelPatches = args.kernelPatches ++
[ { name = "btrfs-fix-deadlock";
patch = ./btrfs-fix-deadlock.patch;
}
];
features.iwlwifi = true;
features.efiBootStub = true;
features.needsCifsUtils = true;
features.canDisableNetfilterConntrackHelpers = true;
features.netfilterRPFilter = true;
} // (args.argsOverride or {}))

View File

@ -1,5 +1,8 @@
{ stdenv, fetchurl, ... } @ args: { stdenv, fetchurl, ... } @ args:
let
patches = (import ./patches { inherit stdenv fetchurl; });
in
import ./generic.nix (args // rec { import ./generic.nix (args // rec {
version = "3.18.11"; version = "3.18.11";
extraMeta.branch = "3.18"; extraMeta.branch = "3.18";
@ -11,9 +14,7 @@ import ./generic.nix (args // rec {
# FIXME: remove with the next point release. # FIXME: remove with the next point release.
kernelPatches = args.kernelPatches ++ kernelPatches = args.kernelPatches ++
[ { name = "btrfs-fix-deadlock"; [ patches.btrfs_fix_deadlock
patch = ./btrfs-fix-deadlock.patch;
}
]; ];
features.iwlwifi = true; features.iwlwifi = true;

View File

@ -1,8 +1,10 @@
{ stdenv, fetchurl, ... } @ args: { stdenv, fetchurl, ... } @ args:
let
patches = (import ./patches { inherit stdenv fetchurl; });
in
import ./generic.nix (args // rec { import ./generic.nix (args // rec {
version = "3.19.3"; version = "3.19.3"; # Remember to update grsecurity!
# Remember to update grsecurity!
extraMeta.branch = "3.19"; extraMeta.branch = "3.19";
src = fetchurl { src = fetchurl {
@ -12,9 +14,7 @@ import ./generic.nix (args // rec {
# FIXME: remove with the next point release. # FIXME: remove with the next point release.
kernelPatches = args.kernelPatches ++ kernelPatches = args.kernelPatches ++
[ { name = "btrfs-fix-deadlock"; [ patches.btrfs_fix_deadlock
patch = ./btrfs-fix-deadlock.patch;
}
]; ];
features.iwlwifi = true; features.iwlwifi = true;

View File

@ -1,27 +0,0 @@
{ stdenv, fetchurl, ... } @ args:
import ./generic.nix (args // rec {
version = "3.2.68";
extraMeta.branch = "3.2";
src = fetchurl {
url = "mirror://kernel/linux/kernel/v3.x/linux-${version}.tar.xz";
sha256 = "0yz3k3qqr13r6fa2f8i83rryiawy4rrd7qk2zx6jxq6byfd31ba2";
};
# We don't provide these patches if grsecurity is enabled, because
# the grsec 3.2 -stable patchset already includes them.
kernelPatches = args.kernelPatches ++ (
stdenv.lib.optionals (!(args.features.grsecurity or false))
[ { name = "0001-AppArmor-compatibility-patch-for-v5-network-controll";
patch = ./apparmor-patches/3.2/0001-AppArmor-compatibility-patch-for-v5-network-controll.patch;
}
{ name = "0002-AppArmor-compatibility-patch-for-v5-interface";
patch = ./apparmor-patches/3.2/0002-AppArmor-compatibility-patch-for-v5-interface.patch;
}
{ name = "0003-AppArmor-Allow-dfa-backward-compatibility-with-broke";
patch = ./apparmor-patches/3.2/0003-AppArmor-Allow-dfa-backward-compatibility-with-broke.patch;
}]);
features.iwlwifi = true;
} // (args.argsOverride or {}))

View File

@ -1,27 +0,0 @@
{ stdenv, fetchurl, ... } @ args:
import ./generic.nix (args // rec {
version = "3.4.106";
extraMeta.branch = "3.4";
src = fetchurl {
url = "mirror://kernel/linux/kernel/v3.x/linux-${version}.tar.xz";
sha256 = "1l1k2kmlz0j12ly63w3mhvdzp5fpc22ajda4kw66fyjx96npm8sc";
};
kernelPatches = args.kernelPatches ++
[ { name = "0001-UBUNTU-SAUCE-AppArmor-Add-profile-introspection-file";
patch = ./apparmor-patches/3.4/0001-UBUNTU-SAUCE-AppArmor-Add-profile-introspection-file.patch;
}
{ name = "0002-UBUNTU-SAUCE-AppArmor-basic-networking-rules";
patch = ./apparmor-patches/3.4/0002-UBUNTU-SAUCE-AppArmor-basic-networking-rules.patch;
}
{ name = "0003-UBUNTU-SAUCE-apparmor-Add-the-ability-to-mediate-mou";
patch = ./apparmor-patches/3.4/0003-UBUNTU-SAUCE-apparmor-Add-the-ability-to-mediate-mou.patch;
}];
features.iwlwifi = true;
features.efiBootStub = true;
features.needsCifsUtils = true;
features.netfilterRPFilter = true;
})

View File

@ -1,13 +0,0 @@
url "http://www.kernel.org/pub/linux/kernel/v3.x/${LINUX_VERSION_RC:+testing/}"
version_link "linux-${LINUX_VERSION}.*tar[.]xz\$"
version '.*linux-([0-9.]+(-rc[0-9]+)?)[.]tar.*' '\1'
target "linux-${LINUX_VERSION}.nix"
name "linux_${LINUX_VERSION/./_}"
do_overwrite() {
ensure_hash
set_var_value version "$CURRENT_VERSION"
set_var_value sha256 "$CURRENT_HASH"
[ -n "$LINUX_VERSION_RC" ] && set_var_value testing true '' '' 1
[ -z "$LINUX_VERSION_RC" ] && set_var_value testing false '' '' 1
}

View File

@ -1,17 +0,0 @@
Dirty patch that makes ext3 work again on 3.5 and 3.6 kernels,
on mips n32.
http://www.linux-mips.org/archives/linux-mips/2012-11/msg00030.html
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 92490e9..bf63d7b 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -228,6 +228,7 @@ out:
static inline int is_32bit_api(void)
{
+ return 1;
#ifdef CONFIG_COMPAT
return is_compat_task();
#else

View File

@ -1,507 +0,0 @@
From bf55ef4e3c2f622ac013f196affbd11b67b59223 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Fri, 28 Oct 2011 13:24:37 -0400
Subject: [PATCH 2/4] Fix handling of prefx instruction in mips/math-emu
* The instruction is named prefx, not pfetch, and its function
field is 0x17, not 0x07.
* Recognize the prefx instruction regardless of what bits happen to be
in bits 21-25, which is the format field of the floating-point ops,
but holds the base register of the prefx instruction.
---
arch/mips/include/asm/inst.h | 4 ++--
arch/mips/math-emu/cp1emu.c | 16 +++++++---------
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
index ab84064..3048edc 100644
--- a/arch/mips/include/asm/inst.h
+++ b/arch/mips/include/asm/inst.h
@@ -161,8 +161,8 @@ enum cop1_sdw_func {
*/
enum cop1x_func {
lwxc1_op = 0x00, ldxc1_op = 0x01,
- pfetch_op = 0x07, swxc1_op = 0x08,
- sdxc1_op = 0x09, madd_s_op = 0x20,
+ swxc1_op = 0x08, sdxc1_op = 0x09,
+ prefx_op = 0x17, madd_s_op = 0x20,
madd_d_op = 0x21, madd_e_op = 0x22,
msub_s_op = 0x28, msub_d_op = 0x29,
msub_e_op = 0x2a, nmadd_s_op = 0x30,
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index dbf2f93..87ddba1 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -739,7 +739,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;
default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}
@@ -809,19 +809,17 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
goto copcsr;
default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}
- case 0x7: /* 7 */
- if (MIPSInst_FUNC(ir) != pfetch_op) {
- return SIGILL;
- }
- /* ignore prefx operation */
- break;
-
default:
+ SIGILL_unless_prefx_op:
+ if (MIPSInst_FUNC(ir) == prefx_op) {
+ /* ignore prefx operation */
+ break;
+ }
return SIGILL;
}
--
1.7.5.4
From 97a564e3eddbfb84844b8eccb3bd751c71dfb3eb Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Fri, 28 Oct 2011 13:35:27 -0400
Subject: [PATCH 3/4] Don't process empty cause flags after simple fp move on
mips
---
arch/mips/math-emu/cp1emu.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 87ddba1..fefcba2 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -912,7 +912,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
case fmov_op:
/* an easy one */
SPFROMREG(rv.s, MIPSInst_FS(ir));
- goto copcsr;
+ break;
/* binary op on handler */
scopbop:
@@ -1099,7 +1099,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
case fmov_op:
/* an easy one */
DPFROMREG(rv.d, MIPSInst_FS(ir));
- goto copcsr;
+ break;
/* binary op on handler */
dcopbop:{
--
1.7.5.4
From 4051727b3007ef3675e7258ed86fa8517f86d929 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Fri, 28 Oct 2011 13:39:10 -0400
Subject: [PATCH 4/4] Support Loongson2f floating-point instructions in
mips/math-emu
* (arch/mips/include/asm/inst.h): Add Loongson2f function field values
for madd/msub/nmadd/nmsub that use the spec2 opcode, and the
Loongson2f/MIPS-5 format field value for paired-single
floating-point operations.
* (arch/mips/math-emu/cp1emu.c): Add support for the Loongson2f
instructions for madd/msub/nmadd/nmsub, which use the spec2 opcode.
Also add support for the Loongson2f instructions that use the
paired-single floating-point format.
---
arch/mips/include/asm/inst.h | 4 +-
arch/mips/math-emu/cp1emu.c | 287 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 289 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
index 3048edc..0e8ba7c 100644
--- a/arch/mips/include/asm/inst.h
+++ b/arch/mips/include/asm/inst.h
@@ -61,6 +61,8 @@ enum spec_op {
enum spec2_op {
madd_op, maddu_op, mul_op, spec2_3_unused_op,
msub_op, msubu_op, /* more unused ops */
+ loongson_madd_op = 0x18, loongson_msub_op,
+ loongson_nmadd_op, loongson_nmsub_op,
clz_op = 0x20, clo_op,
dclz_op = 0x24, dclo_op,
sdbpp_op = 0x3f
@@ -133,7 +135,7 @@ enum cop0_com_func {
*/
enum cop1_fmt {
s_fmt, d_fmt, e_fmt, q_fmt,
- w_fmt, l_fmt
+ w_fmt, l_fmt, ps_fmt
};
/*
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index fefcba2..166b2a4 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -7,6 +7,9 @@
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc.
*
+ * Loongson instruction support
+ * Copyright (C) 2011 Mark H Weaver <mhw@netris.org>
+ *
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
@@ -57,6 +60,14 @@
#endif
#define __mips 4
+#ifdef __loongson_fp
+#undef __loongson_fp
+#endif
+#if __mips >= 4 && __mips != 32
+/* Include support for Loongson floating point instructions */
+#define __loongson_fp 1
+#endif
+
/* Function which emulates a floating point instruction. */
static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
@@ -66,6 +77,10 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
static int fpux_emu(struct pt_regs *,
struct mips_fpu_struct *, mips_instruction, void *__user *);
#endif
+#ifdef __loongson_fp
+static int loongson_spec2_emu(struct pt_regs *,
+ struct mips_fpu_struct *, mips_instruction, void *__user *);
+#endif
/* Further private data for which no space exists in mips_fpu_struct */
@@ -203,6 +218,14 @@ static inline int cop1_64bit(struct pt_regs *xcp)
#define DPFROMREG(dp, x) DIFROMREG((dp).bits, x)
#define DPTOREG(dp, x) DITOREG((dp).bits, x)
+/* Support for Loongson paired single floating-point format */
+#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \
+ (si1) = (u32)di; (si2) = (u32)(di >> 32); })
+#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x)
+
+#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x)
+#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x)
+
/*
* Emulate the single floating point instruction pointed at by EPC.
* Two instructions if the instruction is in a branch delay slot.
@@ -568,6 +591,15 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;
#endif
+#ifdef __loongson_fp
+ case spec2_op:{
+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr);
+ if (sig)
+ return sig;
+ break;
+ }
+#endif
+
default:
return SIGILL;
}
@@ -646,6 +678,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, );
DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
+#ifdef __loongson_fp
+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
+ mips_instruction ir, void *__user *fault_addr)
+{
+ int rfmt; /* resulting format */
+ unsigned rcsr = 0; /* resulting csr */
+ union {
+ ieee754dp d;
+ struct {
+ ieee754sp s;
+ ieee754sp s2;
+ };
+ } rv; /* resulting value */
+
+ /* XXX maybe add a counter for loongson spec2 fp instructions? */
+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */
+
+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
+ case s_fmt:{
+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
+ ieee754sp fd, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_sp_madd;
+ goto scoptop;
+ case loongson_msub_op:
+ handler = fpemu_sp_msub;
+ goto scoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_sp_nmadd;
+ goto scoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_sp_nmsub;
+ goto scoptop;
+
+ scoptop:
+ SPFROMREG(fd, MIPSInst_FD(ir));
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(ft, MIPSInst_FT(ir));
+ rv.s = (*handler) (fd, fs, ft);
+
+ copcsr:
+ if (ieee754_cxtest(IEEE754_INEXACT))
+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
+ if (ieee754_cxtest(IEEE754_UNDERFLOW))
+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+ if (ieee754_cxtest(IEEE754_OVERFLOW))
+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
+
+ break;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ case d_fmt:{
+ ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
+ ieee754dp fd, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_dp_madd;
+ goto dcoptop;
+ case loongson_msub_op:
+ handler = fpemu_dp_msub;
+ goto dcoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_dp_nmadd;
+ goto dcoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_dp_nmsub;
+ goto dcoptop;
+
+ dcoptop:
+ DPFROMREG(fd, MIPSInst_FD(ir));
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(ft, MIPSInst_FT(ir));
+ rv.d = (*handler) (fd, fs, ft);
+ goto copcsr;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ case ps_fmt:{
+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fd1, fs1, ft1;
+ ieee754sp fd2, fs2, ft2;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_sp_madd;
+ goto pscoptop;
+ case loongson_msub_op:
+ handler = fpemu_sp_msub;
+ goto pscoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_sp_nmadd;
+ goto pscoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_sp_nmsub;
+ goto pscoptop;
+
+ pscoptop:
+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir));
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
+ rv.s = (*handler) (fd1, fs1, ft1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler) (fd2, fs2, ft2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ default:
+ return SIGILL;
+ }
+
+ /*
+ * Update the fpu CSR register for this operation.
+ * If an exception is required, generate a tidy SIGFPE exception,
+ * without updating the result register.
+ * Note: cause exception bits do not accumulate, they are rewritten
+ * for each op; only the flag/sticky bits accumulate.
+ */
+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
+ return SIGFPE;
+ }
+
+ /*
+ * Now we can safely write the result back to the register file.
+ */
+ switch (rfmt) {
+ case d_fmt:
+ DPTOREG(rv.d, MIPSInst_FD(ir));
+ break;
+ case s_fmt:
+ SPTOREG(rv.s, MIPSInst_FD(ir));
+ break;
+ case ps_fmt:
+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
+ break;
+ default:
+ return SIGILL;
+ }
+
+ return 0;
+}
+#endif
+
static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
mips_instruction ir, void *__user *fault_addr)
{
@@ -840,7 +1038,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
unsigned cond;
union {
ieee754dp d;
- ieee754sp s;
+ struct {
+ ieee754sp s;
+#ifdef __loongson_fp
+ ieee754sp s2; /* for Loongson paired singles */
+#endif
+ };
int w;
#ifdef __mips64
s64 l;
@@ -1210,6 +1413,83 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;
}
+#ifdef __loongson_fp
+ case ps_fmt:{ /* 6 */
+ /* Support for Loongson paired single fp instructions */
+ union {
+ ieee754sp(*b) (ieee754sp, ieee754sp);
+ ieee754sp(*u) (ieee754sp);
+ } handler;
+
+ switch (MIPSInst_FUNC(ir)) {
+ /* binary ops */
+ case fadd_op:
+ handler.b = ieee754sp_add;
+ goto pscopbop;
+ case fsub_op:
+ handler.b = ieee754sp_sub;
+ goto pscopbop;
+ case fmul_op:
+ handler.b = ieee754sp_mul;
+ goto pscopbop;
+
+ /* unary ops */
+ case fabs_op:
+ handler.u = ieee754sp_abs;
+ goto pscopuop;
+ case fneg_op:
+ handler.u = ieee754sp_neg;
+ goto pscopuop;
+ case fmov_op:
+ /* an easy one */
+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir));
+ break;
+
+ pscopbop: /* paired binary op handler */
+ {
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fs1, ft1;
+ ieee754sp fs2, ft2;
+
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
+ rv.s = (*handler.b) (fs1, ft1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler.b) (fs2, ft2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+ }
+ pscopuop: /* paired unary op handler */
+ {
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fs1;
+ ieee754sp fs2;
+
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ rv.s = (*handler.u) (fs1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler.u) (fs2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+ }
+ break;
+
+ default:
+ if (MIPSInst_FUNC(ir) >= fcmp_op) {
+ /* Loongson fp hardware handles all
+ cases of fp compare insns, so we
+ shouldn't have to */
+ printk ("Loongson paired-single fp compare"
+ " unimplemented in cp1emu.c\n");
+ }
+ return SIGILL;
+ }
+ break;
+ }
+#endif
+
case w_fmt:{
ieee754sp fs;
@@ -1299,6 +1579,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
DITOREG(rv.l, MIPSInst_FD(ir));
break;
#endif
+#ifdef __loongson_fp
+ case ps_fmt:
+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
+ break;
+#endif
default:
return SIGILL;
}
--
1.7.5.4

View File

@ -1,144 +0,0 @@
From ab1ce0a6cd51ca83194a865837f3b90f366a733d Mon Sep 17 00:00:00 2001
From: Lluis Batlle i Rossell <viric@viric.name>
Date: Sat, 16 Jun 2012 00:22:53 +0200
Subject: [PATCH] MIPS: Add emulation for fpureg-mem unaligned access
To: linux-mips@linux-mips.org
Cc: loongson-dev@googlegroups.com
Reusing most of the code from lw,ld,sw,sd emulation,
I add the emulation for lwc1,ldc1,swc1,sdc1.
This avoids the direct SIGBUS sent to userspace processes that have
misaligned memory accesses.
I've tested the change in Loongson2F, with an own test program, and
WebKit 1.4.0, as both were killed by sigbus without this patch.
Signed-off: Lluis Batlle i Rossell <viric@viric.name>
---
arch/mips/kernel/unaligned.c | 43 +++++++++++++++++++++++++++++-------------
1 file changed, 30 insertions(+), 13 deletions(-)
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 9c58bdf..4531e6c 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -85,6 +85,7 @@
#include <asm/cop2.h>
#include <asm/inst.h>
#include <asm/uaccess.h>
+#include <asm/fpu.h>
#define STR(x) __STR(x)
#define __STR(x) #x
@@ -108,6 +109,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
union mips_instruction insn;
unsigned long value;
unsigned int res;
+ fpureg_t *fpuregs;
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
@@ -183,6 +185,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;
case lw_op:
+ case lwc1_op:
if (!access_ok(VERIFY_READ, addr, 4))
goto sigbus;
@@ -209,7 +212,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (res)
goto fault;
compute_return_epc(regs);
- regs->regs[insn.i_format.rt] = value;
+ if (insn.i_format.opcode == lw_op) {
+ regs->regs[insn.i_format.rt] = value;
+ } else {
+ fpuregs = get_fpu_regs(current);
+ fpuregs[insn.i_format.rt] = value;
+ }
break;
case lhu_op:
@@ -291,6 +299,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
goto sigill;
case ld_op:
+ case ldc1_op:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
@@ -325,7 +334,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (res)
goto fault;
compute_return_epc(regs);
- regs->regs[insn.i_format.rt] = value;
+ if (insn.i_format.opcode == ld_op) {
+ regs->regs[insn.i_format.rt] = value;
+ } else {
+ fpuregs = get_fpu_regs(current);
+ fpuregs[insn.i_format.rt] = value;
+ }
break;
#endif /* CONFIG_64BIT */
@@ -370,10 +384,16 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;
case sw_op:
+ case swc1_op:
if (!access_ok(VERIFY_WRITE, addr, 4))
goto sigbus;
- value = regs->regs[insn.i_format.rt];
+ if (insn.i_format.opcode == sw_op) {
+ value = regs->regs[insn.i_format.rt];
+ } else {
+ fpuregs = get_fpu_regs(current);
+ value = fpuregs[insn.i_format.rt];
+ }
__asm__ __volatile__ (
#ifdef __BIG_ENDIAN
"1:\tswl\t%1,(%2)\n"
@@ -401,6 +421,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;
case sd_op:
+ case sdc1_op:
#ifdef CONFIG_64BIT
/*
* A 32-bit kernel might be running on a 64-bit processor. But
@@ -412,7 +433,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, addr, 8))
goto sigbus;
- value = regs->regs[insn.i_format.rt];
+ if (insn.i_format.opcode == sd_op) {
+ value = regs->regs[insn.i_format.rt];
+ } else {
+ fpuregs = get_fpu_regs(current);
+ value = fpuregs[insn.i_format.rt];
+ }
__asm__ __volatile__ (
#ifdef __BIG_ENDIAN
"1:\tsdl\t%1,(%2)\n"
@@ -443,15 +469,6 @@ static void emulate_load_store_insn(struct pt_regs *regs,
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill;
- case lwc1_op:
- case ldc1_op:
- case swc1_op:
- case sdc1_op:
- /*
- * I herewith declare: this does not happen. So send SIGBUS.
- */
- goto sigbus;
-
/*
* COP2 is available to implementor for application specific use.
* It's up to applications to register a notifier chain and do
--
1.7.9.5

View File

@ -1,85 +0,0 @@
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -168,21 +168,23 @@ static void __init xen_banner(void)
xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
}
+static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
+static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
+
static void xen_cpuid(unsigned int *ax, unsigned int *bx,
unsigned int *cx, unsigned int *dx)
{
+ unsigned maskecx = ~0;
unsigned maskedx = ~0;
/*
* Mask out inconvenient features, to try and disable as many
* unsupported kernel subsystems as possible.
*/
- if (*ax == 1)
- maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */
- (1 << X86_FEATURE_ACPI) | /* disable ACPI */
- (1 << X86_FEATURE_MCE) | /* disable MCE */
- (1 << X86_FEATURE_MCA) | /* disable MCA */
- (1 << X86_FEATURE_ACC)); /* thermal monitoring */
+ if (*ax == 1) {
+ maskecx = cpuid_leaf1_ecx_mask;
+ maskedx = cpuid_leaf1_edx_mask;
+ }
asm(XEN_EMULATE_PREFIX "cpuid"
: "=a" (*ax),
@@ -190,9 +192,43 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
"=c" (*cx),
"=d" (*dx)
: "0" (*ax), "2" (*cx));
+
+ *cx &= maskecx;
*dx &= maskedx;
}
+static __init void xen_init_cpuid_mask(void)
+{
+ unsigned int ax, bx, cx, dx;
+
+ cpuid_leaf1_edx_mask =
+ ~((1 << X86_FEATURE_MCE) | /* disable MCE */
+ (1 << X86_FEATURE_MCA) | /* disable MCA */
+ (1 << X86_FEATURE_ACC)); /* thermal monitoring */
+
+ if (!xen_initial_domain())
+ cpuid_leaf1_edx_mask &=
+ ~((1 << X86_FEATURE_APIC) | /* disable local APIC */
+ (1 << X86_FEATURE_ACPI)); /* disable ACPI */
+
+ ax = 1;
+ xen_cpuid(&ax, &bx, &cx, &dx);
+
+ /* cpuid claims we support xsave; try enabling it to see what happens */
+ if (cx & (1 << (X86_FEATURE_XSAVE % 32))) {
+ unsigned long cr4;
+
+ set_in_cr4(X86_CR4_OSXSAVE);
+
+ cr4 = read_cr4();
+
+ if ((cr4 & X86_CR4_OSXSAVE) == 0)
+ cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32));
+
+ clear_in_cr4(X86_CR4_OSXSAVE);
+ }
+}
+
static void xen_set_debugreg(int reg, unsigned long val)
{
HYPERVISOR_set_debugreg(reg, val);
@@ -903,6 +939,8 @@ asmlinkage void __init xen_start_kernel(void)
xen_init_irq_ops();
+ xen_init_cpuid_mask();
+
#ifdef CONFIG_X86_LOCAL_APIC
/*
* set up the basic apic ops.

View File

@ -1,91 +1,15 @@
{ stdenv, fetchurl }: { stdenv, fetchurl }:
let let
patches = rec {
makeTuxonicePatch = { version, kernelVersion, sha256, btrfs_fix_deadlock =
url ? "http://tuxonice.nigelcunningham.com.au/downloads/all/tuxonice-for-linux-${kernelVersion}-${version}.patch.bz2" }: { name = "btrfs-fix-deadlock";
{ name = "tuxonice-${kernelVersion}"; patch = ./patches/btrfs-fix-deadlock.patch;
patch = stdenv.mkDerivation {
name = "tuxonice-${version}-for-${kernelVersion}.patch";
src = fetchurl {
inherit url sha256;
}; };
phases = [ "installPhase" ];
installPhase = ''
source $stdenv/setup
bunzip2 -c $src > $out
'';
};
};
grsecPatch = { grversion ? "3.1", kversion, revision, branch, sha256 }:
{ name = "grsecurity-${grversion}-${kversion}";
inherit grversion kversion revision;
patch = fetchurl {
url = "http://grsecurity.net/${branch}/grsecurity-${grversion}-${kversion}-${revision}.patch";
inherit sha256;
};
features.grsecurity = true;
};
in
rec {
bridge_stp_helper = bridge_stp_helper =
{ name = "bridge-stp-helper"; { name = "bridge-stp-helper";
patch = ./bridge-stp-helper.patch; patch = ./patches/bridge-stp-helper.patch;
}; };
no_xsave =
{ name = "no-xsave";
patch = ./no-xsave.patch;
features.noXsave = true;
}; };
in patches
mips_fpureg_emu =
{ name = "mips-fpureg-emulation";
patch = ./mips-fpureg-emulation.patch;
};
mips_fpu_sigill =
{ name = "mips-fpu-sigill";
patch = ./mips-fpu-sigill.patch;
};
mips_ext3_n32 =
{ name = "mips-ext3-n32";
patch = ./mips-ext3-n32.patch;
};
tuxonice_3_10 = makeTuxonicePatch {
version = "2013-11-07";
kernelVersion = "3.10.18";
sha256 = "00b1rqgd4yr206dxp4mcymr56ymbjcjfa4m82pxw73khj032qw3j";
};
grsecurity_stable = grsecPatch
{ kversion = "3.14.37";
revision = "201504051405";
branch = "stable";
sha256 = "0w1rz5g4wwd22ivii7m7qjgakdynzjwpqxiydx51kiw5j0avkzs3";
};
grsecurity_unstable = grsecPatch
{ kversion = "3.19.3";
revision = "201504021826";
branch = "test";
sha256 = "0r3gsha4x9bkzg9n4rcwzi9f3hkbqrf8yga1dd83kyd10fns4lzm";
};
grsec_fix_path =
{ name = "grsec-fix-path";
patch = ./grsec-path.patch;
};
crc_regression =
{ name = "crc-backport-regression";
patch = ./crc-regression.patch;
};
}

View File

@ -1,18 +0,0 @@
--- perf/config/utilities.mak.orig 2014-01-25 14:55:32.573320370 +0000
+++ perf/config/utilities.mak 2014-01-25 15:13:34.174337760 +0000
@@ -186,9 +186,14 @@
endif
TRY_CC_MSG=echo " CHK $(3)" 1>&2;
+define newline
+
+
+endef
+
try-cc = $(shell sh -c \
'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
$(TRY_CC_MSG) \
- echo "$(1)" | \
+ echo -e "$(subst $(newline),\\n,$(1))" | tee _test.c | \
$(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \
rm -f "$$TMP"')

View File

@ -15,7 +15,6 @@ stdenv.mkDerivation {
preConfigure = '' preConfigure = ''
cd tools/perf cd tools/perf
sed -i s,/usr/include/elfutils,$elfutils/include/elfutils, Makefile sed -i s,/usr/include/elfutils,$elfutils/include/elfutils, Makefile
${optionalString (versionOlder kernel.version "3.13") "patch -p1 < ${./perf.diff}"}
[ -f bash_completion ] && sed -i 's,^have perf,_have perf,' bash_completion [ -f bash_completion ] && sed -i 's,^have perf,_have perf,' bash_completion
export makeFlags="DESTDIR=$out $makeFlags" export makeFlags="DESTDIR=$out $makeFlags"
''; '';

View File

@ -1,7 +1,7 @@
{ stdenv, fetchurl, pkgconfig, intltool, gperf, libcap, dbus, kmod { stdenv, fetchurl, pkgconfig, intltool, gperf, libcap, dbus, kmod
, xz, pam, acl, cryptsetup, libuuid, m4, utillinux , xz, pam, acl, cryptsetup, libuuid, m4, utillinux, libapparmor
, glib, kbd, libxslt, coreutils, libgcrypt, sysvtools , glib, kbd, libxslt, coreutils, libgcrypt, sysvtools, audit
, kexectools, libmicrohttpd, linuxHeaders , kexectools, libmicrohttpd, linuxHeaders, libseccomp, lz4
, pythonPackages ? null, pythonSupport ? false , pythonPackages ? null, pythonSupport ? false
}: }:
@ -25,9 +25,9 @@ stdenv.mkDerivation rec {
]; ];
buildInputs = buildInputs =
[ pkgconfig intltool gperf libcap kmod xz pam acl [ pkgconfig intltool gperf libcap kmod xz pam acl libseccomp
/* cryptsetup */ libuuid m4 glib libxslt libgcrypt /* cryptsetup */ libuuid m4 glib libxslt libgcrypt lz4 audit
libmicrohttpd linuxHeaders libmicrohttpd linuxHeaders libapparmor
] ++ stdenv.lib.optionals pythonSupport [pythonPackages.python pythonPackages.lxml]; ] ++ stdenv.lib.optionals pythonSupport [pythonPackages.python pythonPackages.lxml];
configureFlags = configureFlags =
@ -44,6 +44,7 @@ stdenv.mkDerivation rec {
"--with-firmware-path=/root/test-firmware:/run/current-system/firmware" "--with-firmware-path=/root/test-firmware:/run/current-system/firmware"
"--with-tty-gid=3" # tty in NixOS has gid 3 "--with-tty-gid=3" # tty in NixOS has gid 3
"--enable-compat-libs" # get rid of this eventually "--enable-compat-libs" # get rid of this eventually
"--enable-lz4"
"--disable-tests" "--disable-tests"
"--disable-hostnamed" "--disable-hostnamed"

View File

@ -8743,18 +8743,12 @@ let
microcodeIntel = callPackage ../os-specific/linux/microcode/intel.nix { }; microcodeIntel = callPackage ../os-specific/linux/microcode/intel.nix { };
apparmor = callPackage ../os-specific/linux/apparmor { apparmor = callPackage ../os-specific/linux/apparmor { swig = swig2; };
inherit (perlPackages) LocaleGettext TermReadKey RpcXML; libapparmor = apparmor.libapparmor;
bison = bison2; apparmor-pam = apparmor.apparmor-pam;
perl = perl516; # ${perl}/.../CORE/handy.h:124:34: error: 'bool' undeclared apparmor-parser = apparmor.apparmor-parser;
}; apparmor-profiles = apparmor.apparmor-profiles;
apparmor-utils = apparmor.apparmor-utils;
apparmor_2_9 = callPackage ../os-specific/linux/apparmor/2.9 { swig = swig2; };
libapparmor = apparmor_2_9.libapparmor;
apparmor-pam = apparmor_2_9.apparmor-pam;
apparmor-parser = apparmor_2_9.apparmor-parser;
apparmor-profiles = apparmor_2_9.apparmor-profiles;
apparmor-utils = apparmor_2_9.apparmor-utils;
atop = callPackage ../os-specific/linux/atop { }; atop = callPackage ../os-specific/linux/atop { };
@ -9015,129 +9009,31 @@ let
kernelPatches = callPackage ../os-specific/linux/kernel/patches.nix { }; kernelPatches = callPackage ../os-specific/linux/kernel/patches.nix { };
linux_3_2 = makeOverridable (import ../os-specific/linux/kernel/linux-3.2.nix) {
inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ];
};
linux_3_4 = makeOverridable (import ../os-specific/linux/kernel/linux-3.4.nix) {
inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ]
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
];
};
linux_rpi = makeOverridable (import ../os-specific/linux/kernel/linux-rpi.nix) { linux_rpi = makeOverridable (import ../os-specific/linux/kernel/linux-rpi.nix) {
inherit fetchurl stdenv perl buildLinux; inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ]; kernelPatches = [ kernelPatches.bridge_stp_helper ];
}; };
linux_3_10 = makeOverridable (import ../os-specific/linux/kernel/linux-3.10.nix) {
inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ]
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
kernelPatches.mips_ext3_n32
];
};
linux_3_12 = makeOverridable (import ../os-specific/linux/kernel/linux-3.12.nix) {
inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper kernelPatches.crc_regression ]
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
kernelPatches.mips_ext3_n32
];
};
linux_3_14 = makeOverridable (import ../os-specific/linux/kernel/linux-3.14.nix) {
inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ]
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
kernelPatches.mips_ext3_n32
];
};
linux_3_18 = makeOverridable (import ../os-specific/linux/kernel/linux-3.18.nix) { linux_3_18 = makeOverridable (import ../os-specific/linux/kernel/linux-3.18.nix) {
inherit fetchurl stdenv perl buildLinux; inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ] kernelPatches = [ kernelPatches.bridge_stp_helper ];
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
kernelPatches.mips_ext3_n32
];
}; };
linux_3_19 = makeOverridable (import ../os-specific/linux/kernel/linux-3.19.nix) { linux_3_19 = makeOverridable (import ../os-specific/linux/kernel/linux-3.19.nix) {
inherit fetchurl stdenv perl buildLinux; inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ] kernelPatches = [ kernelPatches.bridge_stp_helper ];
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
kernelPatches.mips_ext3_n32
];
}; };
linux_4_0 = makeOverridable (import ../os-specific/linux/kernel/linux-4.0.nix) { linux_4_0 = makeOverridable (import ../os-specific/linux/kernel/linux-4.0.nix) {
inherit fetchurl stdenv perl buildLinux; inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ] kernelPatches = [ kernelPatches.bridge_stp_helper ];
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
kernelPatches.mips_ext3_n32
];
}; };
linux_testing = makeOverridable (import ../os-specific/linux/kernel/linux-testing.nix) { linux_testing = makeOverridable (import ../os-specific/linux/kernel/linux-testing.nix) {
inherit fetchurl stdenv perl buildLinux; inherit fetchurl stdenv perl buildLinux;
kernelPatches = [ kernelPatches.bridge_stp_helper ] kernelPatches = [ kernelPatches.bridge_stp_helper ];
++ lib.optionals ((platform.kernelArch or null) == "mips")
[ kernelPatches.mips_fpureg_emu
kernelPatches.mips_fpu_sigill
kernelPatches.mips_ext3_n32
];
}; };
/* grsec configuration
We build several flavors of 'default' grsec kernels. These are
built by default with Hydra. If the user selects a matching
'default' flavor, then the pre-canned package set can be
chosen. Typically, users will make very basic choices like
'security' + 'server' or 'performance' + 'desktop' with
virtualisation support. These will then be picked.
Note: Xen guest kernels are included for e.g. NixOps deployments
to EC2, where Xen is the Hypervisor.
*/
grFlavors = import ../build-support/grsecurity/flavors.nix;
mkGrsecurity = opts:
(import ../build-support/grsecurity {
grsecOptions = opts;
inherit pkgs lib;
});
grKernel = opts: (mkGrsecurity opts).grsecKernel;
grPackage = opts: recurseIntoAttrs (mkGrsecurity opts).grsecPackage;
# Stable kernels
linux_grsec_stable_desktop = grKernel grFlavors.linux_grsec_stable_desktop;
linux_grsec_stable_server = grKernel grFlavors.linux_grsec_stable_server;
linux_grsec_stable_server_xen = grKernel grFlavors.linux_grsec_stable_server_xen;
# Testing kernels
linux_grsec_testing_desktop = grKernel grFlavors.linux_grsec_testing_desktop;
linux_grsec_testing_server = grKernel grFlavors.linux_grsec_testing_server;
linux_grsec_testing_server_xen = grKernel grFlavors.linux_grsec_testing_server_xen;
/* Linux kernel modules are inherently tied to a specific kernel. So /* Linux kernel modules are inherently tied to a specific kernel. So
rather than provide specific instances of those packages for a rather than provide specific instances of those packages for a
specific kernel, we have a function that builds those packages specific kernel, we have a function that builds those packages
@ -9258,13 +9154,7 @@ let
linux_latest = linuxPackages_latest.kernel; linux_latest = linuxPackages_latest.kernel;
# Build the kernel modules for the some of the kernels. # Build the kernel modules for the some of the kernels.
linuxPackages_3_2 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_2 linuxPackages_3_2);
linuxPackages_3_4 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_4 linuxPackages_3_4);
linuxPackages_rpi = linuxPackagesFor pkgs.linux_rpi linuxPackages_rpi; linuxPackages_rpi = linuxPackagesFor pkgs.linux_rpi linuxPackages_rpi;
linuxPackages_3_10 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_10 linuxPackages_3_10);
linuxPackages_3_10_tuxonice = linuxPackagesFor pkgs.linux_3_10_tuxonice linuxPackages_3_10_tuxonice;
linuxPackages_3_12 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_12 linuxPackages_3_12);
linuxPackages_3_14 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_14 linuxPackages_3_14);
linuxPackages_3_18 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_18 linuxPackages_3_18); linuxPackages_3_18 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_18 linuxPackages_3_18);
linuxPackages_3_19 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_19 linuxPackages_3_19); linuxPackages_3_19 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_3_19 linuxPackages_3_19);
linuxPackages_4_0 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_4_0 linuxPackages_4_0); linuxPackages_4_0 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_4_0 linuxPackages_4_0);
@ -9278,17 +9168,6 @@ let
# Build a kernel for Xen dom0 # Build a kernel for Xen dom0
linuxPackages_latest_xen_dom0 = recurseIntoAttrs (linuxPackagesFor (pkgs.linux_latest.override { features.xen_dom0=true; }) linuxPackages_latest); linuxPackages_latest_xen_dom0 = recurseIntoAttrs (linuxPackagesFor (pkgs.linux_latest.override { features.xen_dom0=true; }) linuxPackages_latest);
# grsecurity flavors
# Stable kernels
linuxPackages_grsec_stable_desktop = grPackage grFlavors.linux_grsec_stable_desktop;
linuxPackages_grsec_stable_server = grPackage grFlavors.linux_grsec_stable_server;
linuxPackages_grsec_stable_server_xen = grPackage grFlavors.linux_grsec_stable_server_xen;
# Testing kernels
linuxPackages_grsec_testing_desktop = grPackage grFlavors.linux_grsec_testing_desktop;
linuxPackages_grsec_testing_server = grPackage grFlavors.linux_grsec_testing_server;
linuxPackages_grsec_testing_server_xen = grPackage grFlavors.linux_grsec_testing_server_xen;
# A function to build a manually-configured kernel # A function to build a manually-configured kernel
linuxManualConfig = pkgs.buildLinux; linuxManualConfig = pkgs.buildLinux;
buildLinux = import ../os-specific/linux/kernel/manual-config.nix { buildLinux = import ../os-specific/linux/kernel/manual-config.nix {