summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/include/context.h6
-rw-r--r--security/apparmor/include/policy.h4
-rw-r--r--security/apparmor/lsm.c8
-rw-r--r--security/apparmor/policy.c25
4 files changed, 35 insertions, 8 deletions
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h
index a0acc2390fae..d378bff47ccd 100644
--- a/security/apparmor/include/context.h
+++ b/security/apparmor/include/context.h
@@ -20,6 +20,7 @@
#include <linux/sched.h>
#include "policy.h"
+#include "policy_ns.h"
#define cred_cxt(X) (X)->security
#define current_cxt() cred_cxt(current_cred())
@@ -162,6 +163,11 @@ static inline struct aa_profile *aa_current_profile(void)
return cxt->profile;
}
+static inline struct aa_ns *aa_get_current_ns(void)
+{
+ return aa_get_ns(__aa_current_profile()->ns);
+}
+
/**
* aa_clear_task_cxt_trans - clear transition tracking info from the cxt
* @cxt: task context to clear (NOT NULL)
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 8fcfb3c78d21..b0b65c525bcc 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -33,6 +33,8 @@
struct aa_ns;
+extern int unprivileged_userns_apparmor_policy;
+
extern const char *const aa_profile_mode_names[];
#define APPARMOR_MODE_NAMES_MAX_INDEX 4
@@ -297,7 +299,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
return profile->audit;
}
-bool policy_view_capable(void);
+bool policy_view_capable(struct aa_ns *ns);
bool policy_admin_capable(void);
bool aa_may_manage_policy(int op);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index f852cd626f2e..f83ba33651a0 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -745,7 +745,7 @@ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp
static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
{
- if (!policy_view_capable())
+ if (!policy_view_capable(NULL))
return -EPERM;
return param_get_bool(buffer, kp);
}
@@ -759,7 +759,7 @@ static int param_set_aabool(const char *val, const struct kernel_param *kp)
static int param_get_aabool(char *buffer, const struct kernel_param *kp)
{
- if (!policy_view_capable())
+ if (!policy_view_capable(NULL))
return -EPERM;
return param_get_bool(buffer, kp);
}
@@ -773,14 +773,14 @@ static int param_set_aauint(const char *val, const struct kernel_param *kp)
static int param_get_aauint(char *buffer, const struct kernel_param *kp)
{
- if (!policy_view_capable())
+ if (!policy_view_capable(NULL))
return -EPERM;
return param_get_uint(buffer, kp);
}
static int param_get_audit(char *buffer, struct kernel_param *kp)
{
- if (!policy_view_capable())
+ if (!policy_view_capable(NULL))
return -EPERM;
if (!apparmor_enabled)
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 0125de6061fd..f092c04c7c4e 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -76,6 +76,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/user_namespace.h>
#include "include/apparmor.h"
#include "include/capability.h"
@@ -89,6 +90,7 @@
#include "include/policy_unpack.h"
#include "include/resource.h"
+int unprivileged_userns_apparmor_policy = 1;
const char *const aa_profile_mode_names[] = {
"enforce",
@@ -607,20 +609,37 @@ static int audit_policy(struct aa_profile *profile, int op, gfp_t gfp,
&sa, NULL);
}
-bool policy_view_capable(void)
+/**
+ * policy_view_capable - check if viewing policy in at @ns is allowed
+ * ns: namespace being viewed by current task (may be NULL)
+ * Returns: true if viewing policy is allowed
+ *
+ * If @ns is NULL then the namespace being viewed is assumed to be the
+ * tasks current namespace.
+ */
+bool policy_view_capable(struct aa_ns *ns)
{
struct user_namespace *user_ns = current_user_ns();
+ struct aa_ns *view_ns = aa_get_current_ns();
+ bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) ||
+ in_egroup_p(make_kgid(user_ns, 0));
bool response = false;
+ if (!ns)
+ ns = view_ns;
- if (ns_capable(user_ns, CAP_MAC_ADMIN))
+ if (root_in_user_ns && aa_ns_visible(view_ns, ns, true) &&
+ (user_ns == &init_user_ns ||
+ (unprivileged_userns_apparmor_policy != 0 &&
+ user_ns->level == view_ns->level)))
response = true;
+ aa_put_ns(view_ns);
return response;
}
bool policy_admin_capable(void)
{
- return policy_view_capable() && !aa_g_lock_policy;
+ return policy_view_capable(NULL) && !aa_g_lock_policy;
}
/**