summaryrefslogtreecommitdiffstats
path: root/security/apparmor/include/policy.h
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor/include/policy.h')
-rw-r--r--security/apparmor/include/policy.h78
1 files changed, 56 insertions, 22 deletions
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 82487a853353..e9f2baf4467e 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -42,6 +42,8 @@ extern const char *const profile_mode_names[];
#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
+#define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID)
+
#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
/*
@@ -65,6 +67,7 @@ enum profile_flags {
PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
+ PFLAG_INVALID = 0x200, /* profile replaced/removed */
/* These flags must correspond with PATH_flags */
PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
@@ -146,6 +149,12 @@ struct aa_policydb {
};
+struct aa_replacedby {
+ struct kref count;
+ struct aa_profile __rcu *profile;
+};
+
+
/* struct aa_profile - basic confinement data
* @base - base components of the profile (name, refcount, lists, lock ...)
* @parent: parent of profile
@@ -169,8 +178,7 @@ struct aa_policydb {
* used to determine profile attachment against unconfined tasks. All other
* attachments are determined by profile X transition rules.
*
- * The @replacedby field is write protected by the profile lock. Reads
- * are assumed to be atomic.
+ * The @replacedby struct is write protected by the profile lock.
*
* Profiles have a hierarchy where hats and children profiles keep
* a reference to their parent.
@@ -184,14 +192,14 @@ struct aa_profile {
struct aa_profile __rcu *parent;
struct aa_namespace *ns;
- struct aa_profile *replacedby;
+ struct aa_replacedby *replacedby;
const char *rename;
struct aa_dfa *xmatch;
int xmatch_len;
enum audit_mode audit;
enum profile_mode mode;
- u32 flags;
+ long flags;
u32 path_flags;
int size;
@@ -250,6 +258,7 @@ static inline void aa_put_namespace(struct aa_namespace *ns)
kref_put(&ns->base.count, aa_free_namespace_kref);
}
+void aa_free_replacedby_kref(struct kref *kref);
struct aa_profile *aa_alloc_profile(const char *name);
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
void aa_free_profile_kref(struct kref *kref);
@@ -265,24 +274,6 @@ ssize_t aa_remove_profiles(char *name, size_t size);
#define unconfined(X) ((X)->flags & PFLAG_UNCONFINED)
-/**
- * aa_newest_version - find the newest version of @profile
- * @profile: the profile to check for newer versions of (NOT NULL)
- *
- * Returns: newest version of @profile, if @profile is the newest version
- * return @profile.
- *
- * NOTE: the profile returned is not refcounted, The refcount on @profile
- * must be held until the caller decides what to do with the returned newest
- * version.
- */
-static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
-{
- while (profile->replacedby)
- profile = profile->replacedby;
-
- return profile;
-}
/**
* aa_get_profile - increment refcount on profile @p
@@ -335,6 +326,25 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
}
/**
+ * aa_get_newest_profile - find the newest version of @profile
+ * @profile: the profile to check for newer versions of
+ *
+ * Returns: refcounted newest version of @profile taking into account
+ * replacement, renames and removals
+ * return @profile.
+ */
+static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
+{
+ if (!p)
+ return NULL;
+
+ if (PROFILE_INVALID(p))
+ return aa_get_profile_rcu(&p->replacedby->profile);
+
+ return aa_get_profile(p);
+}
+
+/**
* aa_put_profile - decrement refcount on profile @p
* @p: profile (MAYBE NULL)
*/
@@ -344,6 +354,30 @@ static inline void aa_put_profile(struct aa_profile *p)
kref_put(&p->base.count, aa_free_profile_kref);
}
+static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p)
+{
+ if (p)
+ kref_get(&(p->count));
+
+ return p;
+}
+
+static inline void aa_put_replacedby(struct aa_replacedby *p)
+{
+ if (p)
+ kref_put(&p->count, aa_free_replacedby_kref);
+}
+
+/* requires profile list write lock held */
+static inline void __aa_update_replacedby(struct aa_profile *orig,
+ struct aa_profile *new)
+{
+ struct aa_profile *tmp = rcu_dereference(orig->replacedby->profile);
+ rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new));
+ orig->flags |= PFLAG_INVALID;
+ aa_put_profile(tmp);
+}
+
static inline int AUDIT_MODE(struct aa_profile *profile)
{
if (aa_g_audit != AUDIT_NORMAL)