int type, int protocol,
struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
aa_state_t state;
AA_BUG(!profile);
struct apparmor_audit_data *ad,
u32 request, struct sock *sk, struct path *path)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules),
- list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms *p = NULL;
aa_state_t state;
static int profile_bind_perm(struct aa_profile *profile, struct sock *sk,
struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms *p = NULL;
aa_state_t state;
static int profile_listen_perm(struct aa_profile *profile, struct sock *sk,
int backlog, struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms *p = NULL;
aa_state_t state;
struct sock *sk,
struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms *p = NULL;
aa_state_t state;
struct sock *sk, int optname,
struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms *p = NULL;
aa_state_t state;
struct aa_label *peer_label,
struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms *p = NULL;
aa_state_t state;
static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
const char *match_str, size_t match_len)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms tmp = { };
aa_state_t state = DFA_NOMATCH;
{
const u64 AUDIT_CACHE_TIMEOUT_NS = 1000*1000*1000; /* 1 second */
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO;
static int profile_capable(struct aa_profile *profile, int cap,
unsigned int opts, struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
aa_state_t state;
int error;
kernel_cap_t aa_profile_capget(struct aa_profile *profile)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
aa_state_t state;
state = RULE_MEDIATES(rules, AA_CLASS_CAP);
struct aa_profile *tp,
bool stack, aa_state_t state)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
const char *ns_name;
if (stack)
aa_state_t state, bool subns, u32 request,
struct aa_perms *perms)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_profile *tp;
struct label_it i;
struct path_cond cond = { };
aa_state_t start, bool subns, u32 request,
struct aa_perms *perms)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_profile *tp;
struct label_it i;
struct aa_perms tmp;
struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
const char **name)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_label *label = NULL;
u32 xtype = xindex & AA_X_TYPE_MASK;
int index = xindex & AA_X_INDEX_MASK;
const char **lookupname,
const char **info)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
struct aa_label *new = NULL;
struct aa_label *stack = NULL;
struct aa_ns *ns = profile->ns;
char *buffer, struct path_cond *cond,
bool *secure_exec)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_label *new = NULL;
struct aa_profile *new_profile = NULL;
const char *info = NULL, *name = NULL, *target = NULL;
char *buffer, struct path_cond *cond,
bool *secure_exec)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
aa_state_t state = rules->file->start[AA_CLASS_FILE];
struct aa_perms perms = {};
const char *xname = NULL, *info = "change_profile onexec";
struct aa_label *target, bool stack,
u32 request, struct aa_perms *perms)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
const char *info = NULL;
int error = 0;
u32 request, struct path_cond *cond, int flags,
struct aa_perms *perms)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
int e = 0;
if (profile_unconfined(profile) ||
const struct path *target, char *buffer2,
struct path_cond *cond)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
const char *lname, *tname = NULL;
struct aa_perms lperms = {}, perms;
const char *info = NULL;
#include "lib.h"
struct aa_ns;
+struct aa_ruleset;
#define LOCAL_VEC_ENTRIES 8
#define DEFINE_VEC(T, V) \
int i, j;
};
-/* struct aa_label - lazy labeling struct
+/* struct aa_label_base - base info of label
* @count: ref count of active users
* @node: rbtree position
* @rcu: rcu callback struct
* @flags: stale and other flags - values may change under label set lock
* @secid: secid that references this label
* @size: number of entries in @ent[]
- * @ent: set of profiles for label, actual size determined by @size
+ * @mediates: bitmask for label_mediates
+ * profile: label vec when embedded in a profile FLAG_PROFILE is set
+ * rules: variable length rules in a profile FLAG_PROFILE is set
+ * vec: vector of profiles comprising the compound label
*/
struct aa_label {
struct kref count;
u32 secid;
int size;
u64 mediates;
- struct aa_profile *vec[];
+ union {
+ struct {
+ /* only used is the label is a profile, size of
+ * rules[] is determined by the profile
+ * profile[1] is poison or null as guard
+ */
+ struct aa_profile *profile[2];
+ DECLARE_FLEX_ARRAY(struct aa_ruleset *, rules);
+ };
+ DECLARE_FLEX_ARRAY(struct aa_profile *, vec);
+ };
};
#define last_error(E, FN) \
* @secmark: secmark label match info
*/
struct aa_ruleset {
- struct list_head list;
-
int size;
/* TODO: merge policy and file */
struct aa_secmark *secmark;
};
+
/* struct aa_attachment - data and rules for a profiles attachment
* @list:
* @xmatch_str: human readable attachment string
* @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
const char *disconnected;
struct aa_attachment attach;
- struct list_head rules;
struct aa_loaddata *rawdata;
unsigned char *hash;
struct dentry *dents[AAFS_PROF_SIZEOF];
struct rhashtable *data;
+ int n_rules;
/* special - variable length must be last entry in profile */
struct aa_label label;
};
}
-static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
- unsigned char class)
-{
- struct aa_ruleset *rule;
-
- /* TODO: change to list walk */
- rule = list_first_entry(head, typeof(*rule), list);
- return RULE_MEDIATES(rule, class);
-}
-
void aa_compute_profile_mediates(struct aa_profile *profile);
static inline bool profile_mediates(struct aa_profile *profile,
unsigned char class)
struct aa_label *peer, u32 request,
struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms perms;
aa_state_t state;
struct aa_ruleset *rules;
kernel_cap_t allowed;
- rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ rules = profile->label.rules[0];
allowed = aa_profile_capget(profile);
*effective = cap_intersect(*effective, allowed);
*permitted = cap_intersect(*permitted, allowed);
AA_BUG(!profile);
- rules = list_first_entry(&profile->rules, typeof(*rules), list);
+ rules = profile->label.rules[0];
state = RULE_MEDIATES(rules, AA_CLASS_IO_URING);
if (state) {
struct aa_perms perms = { };
{
struct aa_perms perms = { };
const char *mntpnt = NULL, *info = NULL;
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
int pos, error;
AA_BUG(!profile);
bool binary)
{
const char *devname = NULL, *info = NULL;
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
int error = -EACCES;
AA_BUG(!profile);
struct aa_profile *profile, const struct path *path,
char *buffer)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms perms = { };
const char *name = NULL, *info = NULL;
aa_state_t state;
const struct path *old_path,
char *old_buffer)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
const char *old_name, *new_name = NULL, *info = NULL;
const char *trans_name = NULL;
struct aa_perms perms = { };
struct apparmor_audit_data *ad, u32 request, u16 family,
int type, int protocol)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms *p = NULL;
aa_state_t state;
{
int i, ret;
struct aa_perms perms = { };
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
if (rules->secmark_count == 0)
return 0;
struct aa_ruleset *rules;
rules = kzalloc(sizeof(*rules), gfp);
- if (rules)
- INIT_LIST_HEAD(&rules->list);
return rules;
}
*/
void aa_free_profile(struct aa_profile *profile)
{
- struct aa_ruleset *rule, *tmp;
struct rhashtable *rht;
AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, profile);
* at this point there are no tasks that can have a reference
* to rules
*/
- list_for_each_entry_safe(rule, tmp, &profile->rules, list) {
- list_del_init(&rule->list);
- free_ruleset(rule);
- }
+ for (int i = 0; i < profile->n_rules; i++)
+ free_ruleset(profile->label.rules[i]);
+
kfree_sensitive(profile->dirname);
if (profile->data) {
gfp_t gfp)
{
struct aa_profile *profile;
- struct aa_ruleset *rules;
- /* freed by free_profile - usually through aa_put_profile */
- profile = kzalloc(struct_size(profile, label.vec, 2), gfp);
+ /* freed by free_profile - usually through aa_put_profile
+ * this adds space for a single ruleset in the rules section of the
+ * label
+ */
+ profile = kzalloc(struct_size(profile, label.rules, 1), gfp);
if (!profile)
return NULL;
+ profile->n_rules = 1;
if (!aa_policy_init(&profile->base, NULL, hname, gfp))
goto fail;
if (!aa_label_init(&profile->label, 1, gfp))
goto fail;
- INIT_LIST_HEAD(&profile->rules);
-
/* allocate the first ruleset, but leave it empty */
- rules = aa_alloc_ruleset(gfp);
- if (!rules)
+ profile->label.rules[0] = aa_alloc_ruleset(gfp);
+ if (!profile->label.rules[0])
goto fail;
- list_add(&rules->list, &profile->rules);
/* update being set needed by fs interface */
if (!proxy) {
return NULL;
}
+static inline bool ANY_RULE_MEDIATES(struct aa_profile *profile,
+ unsigned char class)
+{
+ int i;
+
+ for (i = 0; i < profile->n_rules; i++) {
+ if (RULE_MEDIATES(profile->label.rules[i], class))
+ return true;
+ }
+ return false;
+}
+
/* set of rules that are mediated by unconfined */
static int unconfined_mediates[] = { AA_CLASS_NS, AA_CLASS_IO_URING, 0 };
int *pos;
for (pos = unconfined_mediates; *pos; pos++) {
- if (ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_NS) !=
- DFA_NOMATCH)
+ if (ANY_RULE_MEDIATES(profile, *pos))
profile->label.mediates |= ((u64) 1) << AA_CLASS_NS;
}
return;
}
for (c = 0; c <= AA_CLASS_LAST; c++) {
- if (ANY_RULE_MEDIATES(&profile->rules, c) != DFA_NOMATCH)
+ if (ANY_RULE_MEDIATES(profile, c))
profile->label.mediates |= ((u64) 1) << c;
}
}
/* TODO: ideally we should inherit abi from parent */
profile->label.flags |= FLAG_NULL;
profile->attach.xmatch = aa_get_pdb(nullpdb);
- rules = list_first_entry(&profile->rules, typeof(*rules), list);
+ rules = profile->label.rules[0];
rules->file = aa_get_pdb(nullpdb);
rules->policy = aa_get_pdb(nullpdb);
aa_compute_profile_mediates(profile);
error = -ENOMEM;
goto fail;
}
- rules = list_first_entry(&profile->rules, typeof(*rules), list);
+ rules = profile->label.rules[0];
/* profile renaming is optional */
(void) aa_unpack_str(e, &profile->rename, "rename");
*/
static int verify_profile(struct aa_profile *profile)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
+
if (!rules)
return 0;
struct aa_profile *profile, unsigned int resource,
struct rlimit *new_rlim)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
int e = 0;
if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max >
* to the lesser of the tasks hard limit and the init tasks soft limit
*/
label_for_each_confined(i, old_l, old) {
- struct aa_ruleset *rules = list_first_entry(&old->rules,
- typeof(*rules),
- list);
+ struct aa_ruleset *rules = old->label.rules[0];
if (rules->rlimits.mask) {
int j;
/* set any new hard limits as dictated by the new profile */
label_for_each_confined(i, new_l, new) {
- struct aa_ruleset *rules = list_first_entry(&new->rules,
- typeof(*rules),
- list);
+ struct aa_ruleset *rules = new->label.rules[0];
int j;
if (!rules->rlimits.mask)
struct aa_label *peer, u32 request,
struct apparmor_audit_data *ad)
{
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules), list);
+ struct aa_ruleset *rules = profile->label.rules[0];
struct aa_perms perms = { };
ad->subj_cred = cred;
struct apparmor_audit_data *ad)
{
if (profile_unconfined(tracee) || unconfined(tracer) ||
- !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
+ !label_mediates(&tracee->label, AA_CLASS_PTRACE))
return 0;
return profile_ptrace_perm(cred, tracee, tracer, request, ad);
if (profile_unconfined(tracer))
return 0;
- if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE))
+ if (label_mediates(&tracer->label, AA_CLASS_PTRACE))
return profile_ptrace_perm(cred, tracer, tracee, request, ad);
/* profile uses the old style capability check for ptrace */
ad->request = request;
if (!profile_unconfined(profile)) {
- struct aa_ruleset *rules = list_first_entry(&profile->rules,
- typeof(*rules),
- list);
+ struct aa_ruleset *rules = profile->label.rules[0];
aa_state_t state;
state = RULE_MEDIATES(rules, ad->class);