]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.apparmor/apparmor-rlimits.diff
Revert "Move xen patchset to new version's subdir."
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.apparmor / apparmor-rlimits.diff
diff --git a/src/patches/suse-2.6.27.31/patches.apparmor/apparmor-rlimits.diff b/src/patches/suse-2.6.27.31/patches.apparmor/apparmor-rlimits.diff
deleted file mode 100644 (file)
index f3912fd..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-From: John Johansen <jjohansen@suse.de>
-Subject: AppArmor: per profile controls for system rlimits
-
-Provide contol of rlimits on a per profile basis.  Each profile provides
-a per limit contol and corresponding hard limit value, such that when a
-profile becomes attached to a task it sets the tasks limits to be <= to
-the profiles specified limits.  Note: the profile limit value will not
-raise a tasks limit if it is already less than the profile mandates.
-
-In addition to setting a tasks limits, the ability to set limits on
-a confined task are controlled.  AppArmor only controls the raising
-of a tasks limits Tasks with CAP_SYS_RESOURCE can have their hard limits
-raised up to the value specified by the profile.  AppArmor does not
-prevent a task for lowering its hard limits, nor does it provide
-additional control on soft limits.
-
-AppArmor only controls the limits specified in a profile so that
-any limit not specified is free to be modified subject to standard
-linux limitations.
-
----
- security/apparmor/apparmor.h         |   23 ++++++
- security/apparmor/apparmorfs.c       |    2 
- security/apparmor/lsm.c              |   16 ++++
- security/apparmor/main.c             |  132 +++++++++++++++++++++++++++++++----
- security/apparmor/module_interface.c |   56 ++++++++++++++
- 5 files changed, 215 insertions(+), 14 deletions(-)
-
---- a/security/apparmor/apparmor.h
-+++ b/security/apparmor/apparmor.h
-@@ -16,6 +16,7 @@
- #include <linux/fs.h>
- #include <linux/binfmts.h>
- #include <linux/rcupdate.h>
-+#include <linux/resource.h>
- #include <linux/socket.h>
- #include <net/sock.h>
-@@ -139,6 +140,18 @@ extern unsigned int apparmor_path_max;
- #define AA_ERROR(fmt, args...)        printk(KERN_ERR "AppArmor: " fmt, ##args)
-+/* struct aa_rlimit - rlimits settings for the profile
-+ * @mask: which hard limits to set
-+ * @limits: rlimit values that override task limits
-+ *
-+ * AppArmor rlimits are used to set confined task rlimits.  Only the
-+ * limits specified in @mask will be controlled by apparmor.
-+ */
-+struct aa_rlimit {
-+      unsigned int mask;
-+      struct rlimit limits[RLIM_NLIMITS];
-+};
-+
- struct aa_profile;
- /* struct aa_namespace - namespace for a set of profiles
-@@ -173,6 +186,8 @@ struct aa_namespace {
-  * @audit_caps: caps that are to be audited
-  * @quiet_caps: caps that should not be audited
-  * @capabilities: capabilities granted by the process
-+ * @rlimits: rlimits for the profile
-+ * @task_count: how many tasks the profile is attached to
-  * @count: reference count of the profile
-  * @task_contexts: list of tasks confined by profile
-  * @lock: lock for the task_contexts list
-@@ -210,6 +225,9 @@ struct aa_profile {
-       kernel_cap_t audit_caps;
-       kernel_cap_t quiet_caps;
-+      struct aa_rlimit rlimits;
-+      unsigned int task_count;
-+
-       struct kref count;
-       struct list_head task_contexts;
-       spinlock_t lock;
-@@ -261,6 +279,7 @@ struct aa_audit {
-       const char *name2;
-       const char *name3;
-       int request_mask, denied_mask, audit_mask;
-+      int rlimit;
-       struct iattr *iattr;
-       pid_t task, parent;
-       int family, type, protocol;
-@@ -328,6 +347,10 @@ extern int aa_may_ptrace(struct aa_task_
- extern int aa_net_perm(struct aa_profile *profile, char *operation,
-                       int family, int type, int protocol);
- extern int aa_revalidate_sk(struct sock *sk, char *operation);
-+extern int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
-+                           struct rlimit *new_rlim);
-+extern void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile);
-+
- /* lsm.c */
- extern int apparmor_initialized;
---- a/security/apparmor/apparmorfs.c
-+++ b/security/apparmor/apparmorfs.c
-@@ -106,7 +106,7 @@ static ssize_t aa_features_read(struct f
- {
-       const char *features = "file=3.0 capability=2.0 network=1.0 "
-                              "change_hat=1.5 change_profile=1.0 "
--                             "aanamespaces=1.0";
-+                             "aanamespaces=1.0 rlimit=1.0";
-       return simple_read_from_buffer(buf, size, ppos, features,
-                                      strlen(features));
---- a/security/apparmor/lsm.c
-+++ b/security/apparmor/lsm.c
-@@ -883,6 +883,21 @@ static int apparmor_setprocattr(struct t
-       return error;
- }
-+static int apparmor_task_setrlimit(unsigned int resource,
-+                                 struct rlimit *new_rlim)
-+{
-+      struct aa_profile *profile;
-+      int error = 0;
-+
-+      profile = aa_get_profile(current);
-+      if (profile) {
-+              error = aa_task_setrlimit(profile, resource, new_rlim);
-+      }
-+      aa_put_profile(profile);
-+
-+      return error;
-+}
-+
- struct security_operations apparmor_ops = {
-       .ptrace =                       apparmor_ptrace,
-       .capget =                       cap_capget,
-@@ -926,6 +941,7 @@ struct security_operations apparmor_ops
-       .task_free_security =           apparmor_task_free_security,
-       .task_post_setuid =             cap_task_post_setuid,
-       .task_reparent_to_init =        cap_task_reparent_to_init,
-+      .task_setrlimit =               apparmor_task_setrlimit,
-       .getprocattr =                  apparmor_getprocattr,
-       .setprocattr =                  apparmor_setprocattr,
---- a/security/apparmor/main.c
-+++ b/security/apparmor/main.c
-@@ -177,6 +177,9 @@ static int aa_audit_base(struct aa_profi
-       if (sa->request_mask)
-               audit_log_format(ab, " fsuid=%d", current->fsuid);
-+      if (sa->rlimit)
-+              audit_log_format(ab, " rlimit=%d", sa->rlimit - 1);
-+
-       if (sa->iattr) {
-               struct iattr *iattr = sa->iattr;
-@@ -872,6 +875,79 @@ int aa_revalidate_sk(struct sock *sk, ch
-       return error;
- }
-+/**
-+ * aa_task_setrlimit - test permission to set an rlimit
-+ * @profile - profile confining the task
-+ * @resource - the resource being set
-+ * @new_rlim - the new resource limit
-+ *
-+ * Control raising the processes hard limit.
-+ */
-+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
-+                    struct rlimit *new_rlim)
-+{
-+      struct aa_audit sa;
-+      int error = 0;
-+
-+      memset(&sa, 0, sizeof(sa));
-+      sa.operation = "setrlimit";
-+      sa.gfp_mask = GFP_KERNEL;
-+      sa.rlimit = resource + 1;
-+
-+      if (profile->rlimits.mask & (1 << resource) &&
-+          new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max) {
-+              sa.error_code = -EACCES;
-+
-+              error = aa_audit(profile, &sa);
-+      }
-+
-+      return error;
-+}
-+
-+static int aa_rlimit_nproc(struct aa_profile *profile) {
-+      if (profile && (profile->rlimits.mask & (1 << RLIMIT_NPROC)) &&
-+          profile->task_count >= profile->rlimits.limits[RLIMIT_NPROC].rlim_max)
-+              return -EAGAIN;
-+      return 0;
-+}
-+
-+void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile)
-+{
-+      int i, mask;
-+
-+      if (!profile)
-+              return;
-+
-+      if (!profile->rlimits.mask)
-+              return;
-+
-+      task_lock(task->group_leader);
-+      mask = 1;
-+      for (i = 0; i < RLIM_NLIMITS; i++, mask <<= 1) {
-+              struct rlimit new_rlim, *old_rlim;
-+
-+              /* check to see if NPROC which is per profile and handled
-+               * in clone/exec or whether this is a limit to be set
-+               * can't set cpu limit either right now
-+               */
-+              if (i == RLIMIT_NPROC || i == RLIMIT_CPU)
-+                      continue;
-+
-+              old_rlim = task->signal->rlim + i;
-+              new_rlim = *old_rlim;
-+
-+              if (mask & profile->rlimits.mask &&
-+                  profile->rlimits.limits[i].rlim_max < new_rlim.rlim_max) {
-+                      new_rlim.rlim_max = profile->rlimits.limits[i].rlim_max;
-+                      /* soft limit should not exceed hard limit */
-+                      if (new_rlim.rlim_cur > new_rlim.rlim_max)
-+                              new_rlim.rlim_cur = new_rlim.rlim_max;
-+              }
-+
-+              *old_rlim = new_rlim;
-+      }
-+      task_unlock(task->group_leader);
-+}
- /*******************************
-  * Global task related functions
-@@ -885,6 +961,7 @@ int aa_revalidate_sk(struct sock *sk, ch
-  */
- int aa_clone(struct task_struct *child)
- {
-+      struct aa_audit sa;
-       struct aa_task_context *cxt, *child_cxt;
-       struct aa_profile *profile;
-@@ -894,6 +971,11 @@ int aa_clone(struct task_struct *child)
-       if (!child_cxt)
-               return -ENOMEM;
-+      memset(&sa, 0, sizeof(sa));
-+      sa.operation = "clone";
-+      sa.task = child->pid;
-+      sa.gfp_mask = GFP_KERNEL;
-+
- repeat:
-       profile = aa_get_profile(current);
-       if (profile) {
-@@ -910,18 +992,22 @@ repeat:
-                       goto repeat;
-               }
-+              if (aa_rlimit_nproc(profile)) {
-+                      sa.info = "rlimit nproc limit exceeded";
-+                      unlock_profile(profile);
-+                      aa_audit_reject(profile, &sa);
-+                      aa_put_profile(profile);
-+                      return -EAGAIN;
-+              }
-+
-               /* No need to grab the child's task lock here. */
-               aa_change_task_context(child, child_cxt, profile,
-                                      cxt->cookie, cxt->previous_profile);
-+
-               unlock_profile(profile);
-               if (APPARMOR_COMPLAIN(child_cxt) &&
-                   profile == profile->ns->null_complain_profile) {
--                      struct aa_audit sa;
--                      memset(&sa, 0, sizeof(sa));
--                      sa.operation = "clone";
--                      sa.gfp_mask = GFP_KERNEL;
--                      sa.task = child->pid;
-                       aa_audit_hint(profile, &sa);
-               }
-               aa_put_profile(profile);
-@@ -1156,6 +1242,10 @@ repeat:
-                       sa.task = current->parent->pid;
-                       aa_audit_reject(profile, &sa);
-               }
-+              if (PTR_ERR(old_profile) == -EAGAIN) {
-+                      sa.info = "rlimit nproc limit exceeded";
-+                      aa_audit_reject(profile, &sa);
-+              }
-               new_profile = old_profile;
-               goto cleanup;
-       }
-@@ -1303,6 +1393,12 @@ static int do_change_profile(struct aa_p
-               goto out;
-       }
-+      if ((error = aa_rlimit_nproc(new_profile))) {
-+              sa->info = "rlimit nproc limit exceeded";
-+              aa_audit_reject(cxt->profile, sa);
-+              goto out;
-+      }
-+
-       if (new_profile == ns->null_complain_profile)
-               aa_audit_hint(cxt->profile, sa);
-@@ -1481,17 +1577,18 @@ struct aa_profile *__aa_replace_profile(
-       cxt = lock_task_and_profiles(task, profile);
-       if (unlikely(profile && profile->isstale)) {
--              task_unlock(task);
--              unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
--              aa_free_task_context(new_cxt);
--              return ERR_PTR(-ESTALE);
-+              old_profile = ERR_PTR(-ESTALE);
-+              goto error;
-       }
-       if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, profile)) {
--              task_unlock(task);
--              unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
--              aa_free_task_context(new_cxt);
--              return ERR_PTR(-EPERM);
-+              old_profile = ERR_PTR(-EPERM);
-+              goto error;
-+      }
-+
-+      if (aa_rlimit_nproc(profile)) {
-+              old_profile = ERR_PTR(-EAGAIN);
-+              goto error;
-       }
-       if (cxt)
-@@ -1499,8 +1596,15 @@ struct aa_profile *__aa_replace_profile(
-       aa_change_task_context(task, new_cxt, profile, 0, NULL);
-       task_unlock(task);
-+      aa_set_rlimits(task, profile);
-       unlock_both_profiles(profile, old_profile);
-       return old_profile;
-+
-+error:
-+      task_unlock(task);
-+      unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
-+      aa_free_task_context(new_cxt);
-+      return old_profile;
- }
- /**
-@@ -1565,6 +1669,7 @@ void aa_change_task_context(struct task_
-       if (old_cxt) {
-               list_del_init(&old_cxt->list);
-+              old_cxt->profile->task_count--;
-               call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
-       }
-       if (new_cxt) {
-@@ -1576,6 +1681,7 @@ void aa_change_task_context(struct task_
-               new_cxt->cookie = cookie;
-               new_cxt->task = task;
-               new_cxt->profile = aa_dup_profile(profile);
-+              profile->task_count++;
-               new_cxt->previous_profile = aa_dup_profile(previous_profile);
-               list_move(&new_cxt->list, &profile->task_contexts);
-       }
---- a/security/apparmor/module_interface.c
-+++ b/security/apparmor/module_interface.c
-@@ -177,6 +177,22 @@ fail:
-       return 0;
- }
-+static int aa_is_u64(struct aa_ext *e, u64 *data, const char *name)
-+{
-+      void *pos = e->pos;
-+      if (aa_is_nameX(e, AA_U64, name)) {
-+              if (!aa_inbounds(e, sizeof(u64)))
-+                      goto fail;
-+              if (data)
-+                      *data = le64_to_cpu(get_unaligned((u64 *)e->pos));
-+              e->pos += sizeof(u64);
-+              return 1;
-+      }
-+fail:
-+      e->pos = pos;
-+      return 0;
-+}
-+
- static size_t aa_is_array(struct aa_ext *e, const char *name)
- {
-       void *pos = e->pos;
-@@ -312,6 +328,39 @@ fail:
-       return 0;
- }
-+int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
-+{
-+      void *pos = e->pos;
-+
-+      /* rlimits are optional */
-+      if (aa_is_nameX(e, AA_STRUCT, "rlimits")) {
-+              int i, size;
-+              u32 tmp = 0;
-+              if (!aa_is_u32(e, &tmp, NULL))
-+                      goto fail;
-+              profile->rlimits.mask = tmp;
-+
-+              size = aa_is_array(e, NULL);
-+              if (size > RLIM_NLIMITS)
-+                      goto fail;
-+              for (i = 0; i < size; i++) {
-+                      u64 tmp = 0;
-+                      if (!aa_is_u64(e, &tmp, NULL))
-+                              goto fail;
-+                      profile->rlimits.limits[i].rlim_max = tmp;
-+              }
-+              if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
-+                      goto fail;
-+              if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
-+                      goto fail;
-+      }
-+      return 1;
-+
-+fail:
-+      e->pos = pos;
-+      return 0;
-+}
-+
- /**
-  * aa_unpack_profile - unpack a serialized profile
-  * @e: serialized data extent information
-@@ -355,6 +404,9 @@ static struct aa_profile *aa_unpack_prof
-       if (!aa_is_u32(e, &(profile->set_caps), NULL))
-               goto fail;
-+      if (!aa_unpack_rlimits(e, profile))
-+              goto fail;
-+
-       size = aa_is_array(e, "net_allowed_af");
-       if (size) {
-               if (size > AF_MAX)
-@@ -614,6 +666,8 @@ ssize_t aa_replace_profile(void *udata,
-               sa.operation = "profile_load";
-               goto out;
-       }
-+      /* do not fail replacement based off of profile's NPROC rlimit */
-+
-       /*
-        * Replacement needs to allocate a new aa_task_context for each
-        * task confined by old_profile.  To do this the profile locks
-@@ -634,6 +688,7 @@ ssize_t aa_replace_profile(void *udata,
-                       task_lock(task);
-                       task_replace(task, new_cxt, new_profile);
-                       task_unlock(task);
-+                      aa_set_rlimits(task, new_profile);
-                       new_cxt = NULL;
-               }
-               unlock_both_profiles(old_profile, new_profile);
-@@ -656,6 +711,7 @@ out:
-  *
-  * remove a profile from the profile list and all aa_task_context references
-  * to said profile.
-+ * NOTE: removing confinement does not restore rlimits to preconfinemnet values
-  */
- ssize_t aa_remove_profile(char *name, size_t size)
- {