summaryrefslogtreecommitdiff
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.h444
1 files changed, 276 insertions, 168 deletions
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index b25491a3046a..4c50875c9d13 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AppArmor security module
*
@@ -5,11 +6,6 @@
*
* 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_POLICY_H
@@ -18,6 +14,7 @@
#include <linux/capability.h>
#include <linux/cred.h>
#include <linux/kref.h>
+#include <linux/rhashtable.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/socket.h>
@@ -27,10 +24,20 @@
#include "capability.h"
#include "domain.h"
#include "file.h"
+#include "lib.h"
+#include "label.h"
+#include "net.h"
+#include "perms.h"
#include "resource.h"
-extern const char *const profile_mode_names[];
-#define APPARMOR_NAMES_MAX_INDEX 3
+
+struct aa_ns;
+
+extern int unprivileged_userns_apparmor_policy;
+extern int aa_unprivileged_unconfined_restricted;
+
+extern const char *const aa_profile_mode_names[];
+#define APPARMOR_MODE_NAMES_MAX_INDEX 4
#define PROFILE_MODE(_profile, _mode) \
((aa_g_profile_mode == (_mode)) || \
@@ -38,9 +45,24 @@ extern const char *const profile_mode_names[];
#define COMPLAIN_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_COMPLAIN)
+#define USER_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_USER)
+
#define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL)
-#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
+#define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT)
+
+#define CHECK_DEBUG1(_profile) ((_profile)->label.flags & FLAG_DEBUG1)
+
+#define CHECK_DEBUG2(_profile) ((_profile)->label.flags & FLAG_DEBUG2)
+
+#define profile_is_stale(_profile) (label_is_stale(&(_profile)->label))
+
+#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
+
+/* flags in the dfa accept2 table */
+enum dfa_accept_flags {
+ ACCEPT_FLAG_OWNER = 1,
+};
/*
* FIXME: currently need a clean way to replace and remove profiles as a
@@ -52,122 +74,156 @@ enum profile_mode {
APPARMOR_ENFORCE, /* enforce access rules */
APPARMOR_COMPLAIN, /* allow and log access violations */
APPARMOR_KILL, /* kill task on access violation */
+ APPARMOR_UNCONFINED, /* profile set to unconfined */
+ APPARMOR_USER, /* modified complain mode to userspace */
};
-enum profile_flags {
- PFLAG_HAT = 1, /* profile is a hat */
- PFLAG_UNCONFINED = 2, /* profile is an unconfined profile */
- PFLAG_NULL = 4, /* profile is null learning profile */
- PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */
- PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */
- 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 */
-
- /* These flags must correspond with PATH_flags */
- PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
-};
-struct aa_profile;
-
-/* struct aa_policy - common part of both namespaces and profiles
- * @name: name of the object
- * @hname - The hierarchical name
- * @count: reference count of the obj
- * @list: list policy object is on
- * @profiles: head of the profiles list contained in the object
+/* struct aa_policydb - match engine for a policy
+ * count: refcount for the pdb
+ * dfa: dfa pattern match
+ * perms: table of permissions
+ * strs: table of strings, index by x
+ * start: set of start states for the different classes of data
*/
-struct aa_policy {
- char *name;
- char *hname;
+struct aa_policydb {
struct kref count;
- struct list_head list;
- struct list_head profiles;
+ struct aa_dfa *dfa;
+ struct {
+ struct aa_perms *perms;
+ u32 size;
+ };
+ struct aa_str_table trans;
+ aa_state_t start[AA_CLASS_LAST + 1];
};
-/* struct aa_ns_acct - accounting of profiles in namespace
- * @max_size: maximum space allowed for all profiles in namespace
- * @max_count: maximum number of profiles that can be in this namespace
- * @size: current size of profiles
- * @count: current count of profiles (includes null profiles)
- */
-struct aa_ns_acct {
- int max_size;
- int max_count;
- int size;
- int count;
-};
+extern struct aa_policydb *nullpdb;
-/* struct aa_namespace - namespace for a set of profiles
- * @base: common policy
- * @parent: parent of namespace
- * @lock: lock for modifying the object
- * @acct: accounting for the namespace
- * @unconfined: special unconfined profile for the namespace
- * @sub_ns: list of namespaces under the current namespace.
- * @uniq_null: uniq value used for null learning profiles
- *
- * An aa_namespace defines the set profiles that are searched to determine
- * which profile to attach to a task. Profiles can not be shared between
- * aa_namespaces and profile names within a namespace are guaranteed to be
- * unique. When profiles in separate namespaces have the same name they
- * are NOT considered to be equivalent.
- *
- * Namespaces are hierarchical and only namespaces and profiles below the
- * current namespace are visible.
+struct aa_policydb *aa_alloc_pdb(gfp_t gfp);
+void aa_pdb_free_kref(struct kref *kref);
+
+/**
+ * aa_get_pdb - increment refcount on @pdb
+ * @pdb: policydb (MAYBE NULL)
*
- * Namespace names must be unique and can not contain the characters :/\0
+ * Returns: pointer to @pdb if @pdb is NULL will return NULL
+ * Requires: @pdb must be held with valid refcount when called
+ */
+static inline struct aa_policydb *aa_get_pdb(struct aa_policydb *pdb)
+{
+ if (pdb)
+ kref_get(&(pdb->count));
+
+ return pdb;
+}
+
+/**
+ * aa_put_pdb - put a pdb refcount
+ * @pdb: pdb to put refcount (MAYBE NULL)
*
- * FIXME TODO: add vserver support of namespaces (can it all be done in
- * userspace?)
+ * Requires: if @pdb != NULL that a valid refcount be held
*/
-struct aa_namespace {
- struct aa_policy base;
- struct aa_namespace *parent;
- rwlock_t lock;
- struct aa_ns_acct acct;
- struct aa_profile *unconfined;
- struct list_head sub_ns;
- atomic_t uniq_null;
+static inline void aa_put_pdb(struct aa_policydb *pdb)
+{
+ if (pdb)
+ kref_put(&pdb->count, aa_pdb_free_kref);
+}
+
+/* lookup perm that doesn't have and object conditional */
+static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy,
+ aa_state_t state)
+{
+ unsigned int index = ACCEPT_TABLE(policy->dfa)[state];
+
+ if (!(policy->perms))
+ return &default_perms;
+
+ return &(policy->perms[index]);
+}
+
+/* struct aa_data - generic data structure
+ * key: name for retrieving this data
+ * size: size of data in bytes
+ * data: binary data
+ * head: reserved for rhashtable
+ */
+struct aa_data {
+ char *key;
+ u32 size;
+ char *data;
+ struct rhash_head head;
};
-/* struct aa_policydb - match engine for a policy
- * dfa: dfa pattern match
- * start: set of start states for the different classes of data
+/* struct aa_ruleset - data covering mediation rules
+ * @list: list the rule is on
+ * @size: the memory consumed by this ruleset
+ * @policy: general match rules governing policy
+ * @file: The set of rules governing basic file access and domain transitions
+ * @caps: capabilities for the profile
+ * @rlimits: rlimits for the profile
+ * @secmark_count: number of secmark entries
+ * @secmark: secmark label match info
*/
-struct aa_policydb {
- /* Generic policy DFA specific rule types will be subsections of it */
- struct aa_dfa *dfa;
- unsigned int start[AA_CLASS_LAST + 1];
+struct aa_ruleset {
+ int size;
+ /* TODO: merge policy and file */
+ struct aa_policydb *policy;
+ struct aa_policydb *file;
+ struct aa_caps caps;
+
+ struct aa_rlimit rlimits;
+
+ int secmark_count;
+ struct aa_secmark *secmark;
+};
+
+
+/* struct aa_attachment - data and rules for a profiles attachment
+ * @list:
+ * @xmatch_str: human readable attachment string
+ * @xmatch: optional extended matching for unconfined executables names
+ * @xmatch_len: xmatch prefix len, used to determine xmatch priority
+ * @xattr_count: number of xattrs in table
+ * @xattrs: table of xattrs
+ */
+struct aa_attachment {
+ const char *xmatch_str;
+ struct aa_policydb *xmatch;
+ unsigned int xmatch_len;
+ int xattr_count;
+ char **xattrs;
};
/* struct aa_profile - basic confinement data
* @base - base components of the profile (name, refcount, lists, lock ...)
* @parent: parent of profile
* @ns: namespace the profile is in
- * @replacedby: is set to the profile that replaced this profile
* @rename: optional profile name that this profile renamed
- * @xmatch: optional extended matching for unconfined executables names
- * @xmatch_len: xmatch prefix len, used to determine xmatch priority
+ *
* @audit: the auditing mode of the profile
* @mode: the enforcement mode of the profile
- * @flags: flags controlling profile behavior
* @path_flags: flags controlling path generation behavior
- * @size: the memory consumed by this profiles rules
- * @policy: general match rules governing policy
- * @file: The set of rules governing basic file access and domain transitions
- * @caps: capabilities for the profile
- * @rlimits: rlimits for the profile
+ * @signal: the signal that should be used when kill is used
+ * @disconnected: what to prepend if attach_disconnected is specified
+ * @attach: attachment rules for the profile
+ * @rules: rules to be enforced
+ *
+ * learning_cache: the accesses learned in complain mode
+ * raw_data: rawdata of the loaded profile policy
+ * hash: cryptographic hash of the profile
+ * @dents: dentries for the profiles file entries in apparmorfs
+ * @dirname: name of the profile dir in apparmorfs
+ * @dents: set of dentries associated with the profile
+ * @data: hashtable for free-form policy aa_data
+ * @label - label this profile is an extension of
+ * @rules - label with the rule vec on its end
*
* The AppArmor profile contains the basic confinement data. Each profile
* has a name, and exists in a namespace. The @name and @exec_match are
* 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, and are done without locking.
- *
* Profiles have a hierarchy where hats and children profiles keep
* a reference to their parent.
*
@@ -177,107 +233,116 @@ struct aa_policydb {
*/
struct aa_profile {
struct aa_policy base;
- struct aa_profile *parent;
+ struct aa_profile __rcu *parent;
- struct aa_namespace *ns;
- struct aa_profile *replacedby;
+ struct aa_ns *ns;
const char *rename;
- struct aa_dfa *xmatch;
- int xmatch_len;
enum audit_mode audit;
- enum profile_mode mode;
- u32 flags;
+ long mode;
u32 path_flags;
- int size;
+ int signal;
+ const char *disconnected;
- struct aa_policydb policy;
- struct aa_file_rules file;
- struct aa_caps caps;
- struct aa_rlimit rlimits;
-};
+ struct aa_attachment attach;
-extern struct aa_namespace *root_ns;
-extern enum profile_mode aa_g_profile_mode;
+ struct aa_loaddata *rawdata;
+ unsigned char *hash;
+ char *dirname;
+ struct dentry *dents[AAFS_PROF_SIZEOF];
+ struct rhashtable *data;
-void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
+ int n_rules;
+ /* special - variable length must be last entry in profile */
+ struct aa_label label;
+};
-bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view);
-const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child);
-int aa_alloc_root_ns(void);
-void aa_free_root_ns(void);
-void aa_free_namespace_kref(struct kref *kref);
+extern enum profile_mode aa_g_profile_mode;
-struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
- const char *name);
+#define AA_MAY_LOAD_POLICY AA_MAY_APPEND
+#define AA_MAY_REPLACE_POLICY AA_MAY_WRITE
+#define AA_MAY_REMOVE_POLICY AA_MAY_DELETE
+
+#define profiles_ns(P) ((P)->ns)
+#define name_is_shared(A, B) ((A)->hname && (A)->hname == (B)->hname)
+
+struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp);
+struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy,
+ gfp_t gfp);
+struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
+ gfp_t gfp);
+struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
+ const char *base, gfp_t gfp);
+void aa_free_profile(struct aa_profile *profile);
+struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
+struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
+ size_t n);
+struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
+ const char *fqname, size_t n);
-static inline struct aa_policy *aa_get_common(struct aa_policy *c)
-{
- if (c)
- kref_get(&c->count);
+ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_label *label,
+ u32 mask, struct aa_loaddata *udata);
+ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label,
+ char *name, size_t size);
+void __aa_profile_list_release(struct list_head *head);
- return c;
-}
+#define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
/**
- * aa_get_namespace - increment references count on @ns
- * @ns: namespace to increment reference count of (MAYBE NULL)
+ * aa_get_newest_profile - simple wrapper fn to wrap the label version
+ * @p: profile (NOT NULL)
+ *
+ * Returns refcount to newest version of the profile (maybe @p)
*
- * Returns: pointer to @ns, if @ns is NULL returns NULL
- * Requires: @ns must be held with valid refcount when called
+ * Requires: @p must be held with a valid refcount
*/
-static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
+static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
{
- if (ns)
- kref_get(&(ns->base.count));
+ return labels_profile(aa_get_newest_label(&p->label));
+}
- return ns;
+static inline aa_state_t RULE_MEDIATES(struct aa_ruleset *rules,
+ unsigned char class)
+{
+ if (class <= AA_CLASS_LAST)
+ return rules->policy->start[class];
+ else
+ return aa_dfa_match_len(rules->policy->dfa,
+ rules->policy->start[0], &class, 1);
}
-/**
- * aa_put_namespace - decrement refcount on @ns
- * @ns: namespace to put reference of
- *
- * Decrement reference count of @ns and if no longer in use free it
- */
-static inline void aa_put_namespace(struct aa_namespace *ns)
+static inline aa_state_t RULE_MEDIATES_v9NET(struct aa_ruleset *rules)
{
- if (ns)
- kref_put(&ns->base.count, aa_free_namespace_kref);
+ return RULE_MEDIATES(rules, AA_CLASS_NETV9);
}
-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);
-struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
-struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
-struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name);
+static inline aa_state_t RULE_MEDIATES_NET(struct aa_ruleset *rules)
+{
+ /* can not use RULE_MEDIATE_v9AF here, because AF match fail
+ * can not be distiguished from class match fail, and we only
+ * fallback to checking older class on class match failure
+ */
+ aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NETV9);
-ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
-ssize_t aa_remove_profiles(char *name, size_t size);
+ /* fallback and check v7/8 if v9 is NOT mediated */
+ if (!state)
+ state = RULE_MEDIATES(rules, AA_CLASS_NET);
-#define PROF_ADD 1
-#define PROF_REPLACE 0
+ return state;
+}
-#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)
+void aa_compute_profile_mediates(struct aa_profile *profile);
+static inline bool profile_mediates(struct aa_profile *profile,
+ unsigned char class)
{
- while (profile->replacedby)
- profile = profile->replacedby;
+ return label_mediates(&profile->label, class);
+}
- return profile;
+static inline bool profile_mediates_safe(struct aa_profile *profile,
+ unsigned char class)
+{
+ return label_mediates_safe(&profile->label, class);
}
/**
@@ -290,19 +355,54 @@ static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
{
if (p)
- kref_get(&(p->base.count));
+ kref_get(&(p->label.count));
return p;
}
/**
+ * aa_get_profile_not0 - increment refcount on profile @p found via lookup
+ * @p: profile (MAYBE NULL)
+ *
+ * Returns: pointer to @p if @p is NULL will return NULL
+ * Requires: @p must be held with valid refcount when called
+ */
+static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
+{
+ if (p && kref_get_unless_zero(&p->label.count))
+ return p;
+
+ return NULL;
+}
+
+/**
+ * aa_get_profile_rcu - increment a refcount profile that can be replaced
+ * @p: pointer to profile that can be replaced (NOT NULL)
+ *
+ * Returns: pointer to a refcounted profile.
+ * else NULL if no profile
+ */
+static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
+{
+ struct aa_profile *c;
+
+ rcu_read_lock();
+ do {
+ c = rcu_dereference(*p);
+ } while (c && !kref_get_unless_zero(&c->label.count));
+ rcu_read_unlock();
+
+ return c;
+}
+
+/**
* aa_put_profile - decrement refcount on profile @p
* @p: profile (MAYBE NULL)
*/
static inline void aa_put_profile(struct aa_profile *p)
{
if (p)
- kref_put(&p->base.count, aa_free_profile_kref);
+ kref_put(&p->label.count, aa_label_kref);
}
static inline int AUDIT_MODE(struct aa_profile *profile)
@@ -313,6 +413,14 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
return profile->audit;
}
-bool aa_may_manage_policy(int op);
+bool aa_policy_view_capable(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns);
+bool aa_policy_admin_capable(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns);
+int aa_may_manage_policy(const struct cred *subj_cred,
+ struct aa_label *label, struct aa_ns *ns,
+ u32 mask);
+bool aa_current_policy_view_capable(struct aa_ns *ns);
+bool aa_current_policy_admin_capable(struct aa_ns *ns);
#endif /* __AA_POLICY_H */