UBUNTU: SAUCE: apparmor4.0.0 [48/90]: Add fine grained mediation of posix mqueues

BugLink: http://bugs.launchpad.net/bugs/2028253

Add fine grained mediation of posix mqueues. Specifically this patch
adds support for differentiating mqueues based on the name in the ipc
namespace. A follow on patch will add support for implied labels, and
a third patch explicit labels. This is done in part because of
dependencies on other patches to apparmor core.

Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from https://gitlab.com/jjohansen/apparmor-kernel)
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
(cherry picked from commit 5de4e990b8c3297eebc2470c0dda6acb6c741a71
https://git.launchpad.net/~apparmor-dev/ubuntu-kernel-next)
Signed-off-by: Paolo Pisati <paolo.pisati@canonical.com>
This commit is contained in:
John Johansen
2021-12-13 15:46:09 -08:00
committed by Paolo Pisati
parent 938de00f4f
commit 863d225455
9 changed files with 503 additions and 21 deletions
+7
View File
@@ -2311,6 +2311,12 @@ static struct aa_sfs_entry aa_sfs_entry_file[] = {
{ }
};
static struct aa_sfs_entry aa_sfs_entry_ipc[] = {
AA_SFS_FILE_STRING("posix_mqueue",
"create read write open delete setattr getattr"),
{ }
};
static struct aa_sfs_entry aa_sfs_entry_ptrace[] = {
AA_SFS_FILE_STRING("mask", "read trace"),
{ }
@@ -2405,6 +2411,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("policy", aa_sfs_entry_policy),
AA_SFS_DIR("domain", aa_sfs_entry_domain),
AA_SFS_DIR("file", aa_sfs_entry_file),
AA_SFS_DIR("ipc", aa_sfs_entry_ipc),
AA_SFS_DIR("network_v8", aa_sfs_entry_network),
AA_SFS_DIR("network", aa_sfs_entry_network_compat),
AA_SFS_DIR("mount", aa_sfs_entry_mount),
+60 -1
View File
@@ -19,6 +19,7 @@
#include "include/audit.h"
#include "include/cred.h"
#include "include/file.h"
#include "include/ipc.h"
#include "include/match.h"
#include "include/net.h"
#include "include/path.h"
@@ -572,6 +573,61 @@ static int __file_sock_perm(const char *op, const struct cred *subj_cred,
return error;
}
/* TODO: combine with __file_path_perm */
static int __file_mqueue_perm(const char *op, const struct cred *subj_cred,
struct aa_label *label,
struct aa_label *flabel, struct file *file,
u32 request, u32 denied, bool in_atomic)
{
struct aa_profile *profile;
char *buffer;
int error;
DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_POSIX_MQUEUE, op);
/* revalidation due to label out of date. No revocation at this time */
if (!denied && aa_label_is_subset(flabel, label))
/* TODO: check for revocation on stale profiles */
return 0;
buffer = aa_get_buffer(in_atomic);
if (!buffer)
return -ENOMEM;
ad.subj_cred = subj_cred;
ad.request = request;
ad.peer = NULL;
ad.mq.ouid = file_inode(file)->i_uid;
/* check every profile in task label not in current cache */
error = fn_for_each_not_in_set(flabel, label, profile,
aa_profile_mqueue_perm(profile, &file->f_path,
request, buffer, &ad));
if (denied && !error) {
/*
* check every profile in file label that was not tested
* in the initial check above.
*
* TODO: cache full perms so this only happens because of
* conditionals
* TODO: don't audit here
*/
if (label == flabel)
error = fn_for_each(label, profile,
aa_profile_mqueue_perm(profile, &file->f_path,
request, buffer, &ad));
else
error = fn_for_each_not_in_set(label, flabel, profile,
aa_profile_mqueue_perm(profile, &file->f_path,
request, buffer, &ad));
}
if (!error)
update_file_ctx(file_ctx(file), label, request);
aa_put_buffer(buffer);
return error;
}
/**
* aa_file_perm - do permission revalidation check & audit for @file
* @op: operation being checked
@@ -619,7 +675,10 @@ int aa_file_perm(const char *op, const struct cred *subj_cred,
rcu_read_unlock();
/* TODO: label cross check */
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
if (is_mqueue_inode(file_inode(file))) {
error = __file_mqueue_perm(op, subj_cred, label, flabel, file,
request, denied, in_atomic);
} else if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
error = __file_path_perm(op, subj_cred, label, flabel, file,
request, denied, in_atomic);
+4
View File
@@ -142,6 +142,10 @@ struct apparmor_audit_data {
void *addr;
int addrlen;
} net;
struct {
kuid_t fsuid;
kuid_t ouid;
} mq;
};
};
struct {
+42
View File
@@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AppArmor security module
*
* This file contains AppArmor file mediation function definitions.
*
* Copyright 2022 Canonical Ltd.
*/
#ifndef __AA_INODE_H
#define __AA_INODE_H
#include <linux/spinlock.h>
#include "lib.h"
struct aa_inode_sec {
struct inode *inode; /* back pointer to inode object */
struct aa_label *label;
u16 sclass; /* security class of this object */
bool initialized; /* initialization flag */
spinlock_t lock;
};
struct aa_superblock_sec {
struct aa_label *label;
};
static inline struct aa_inode_sec *apparmor_inode(const struct inode *inode)
{
if (unlikely(!inode->i_security))
return NULL;
return inode->i_security + apparmor_blob_sizes.lbs_inode;
}
static inline struct aa_superblock_sec *apparmor_superblock(
const struct super_block *sb)
{
return sb->s_security + apparmor_blob_sizes.lbs_superblock;
}
#endif /* __AA_INODE_H */
+58
View File
@@ -11,10 +11,68 @@
#ifndef __AA_IPC_H
#define __AA_IPC_H
#include <linux/msg.h>
#include <linux/sched.h>
#include "inode.h"
#include "perms.h"
struct aa_msg_sec {
struct aa_label *label;
};
struct aa_ipc_sec {
struct aa_label *label;
};
static inline struct aa_ipc_sec *apparmor_ipc(const struct kern_ipc_perm *ipc)
{
return ipc->security + apparmor_blob_sizes.lbs_ipc;
}
static inline struct aa_msg_sec *apparmor_msg_msg(const struct msg_msg *msg_msg)
{
return msg_msg->security + apparmor_blob_sizes.lbs_msg_msg;
}
static inline bool is_mqueue_sb(struct super_block *sb)
{
if (!sb)
pr_warn("mqueue sb == NULL\n");
if (!sb && !sb->s_type->name)
pr_warn("mqueue sb name == NULL\n");
return sb && sb->s_type->name && strcmp(sb->s_type->name, "mqueue") == 0;
}
static inline bool is_mqueue_inode(struct inode *i)
{
struct aa_inode_sec *isec;
if (!i)
return false;
isec = apparmor_inode(i);
return isec && isec->sclass == AA_CLASS_POSIX_MQUEUE;
}
int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender,
const struct cred *target_cred, struct aa_label *target,
int sig);
#define AA_AUDIT_POSIX_MQUEUE_MASK (AA_MAY_WRITE | AA_MAY_READ | \
AA_MAY_CREATE | AA_MAY_DELETE | \
AA_MAY_OPEN | AA_MAY_SETATTR | \
AA_MAY_GETATTR)
int aa_profile_mqueue_perm(struct aa_profile *profile,
const struct path *path,
u32 request, char *buffer,
struct apparmor_audit_data *ad);
int aa_mqueue_perm(const char *op, const struct cred *subj_cred,
struct aa_label *label,
const struct path *path, u32 request);
#endif /* __AA_IPC_H */
+9
View File
@@ -204,6 +204,9 @@ void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs,
u32 mask);
void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
u32 mask);
void aa_audit_perms(struct audit_buffer *ab, struct apparmor_audit_data *ad,
const char *chrs, u32 chrsmask, const char * const *names,
u32 namesmask);
void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
u32 chrsmask, const char * const *names, u32 namesmask);
void aa_apply_modes_to_perms(struct aa_profile *profile,
@@ -216,6 +219,12 @@ void aa_profile_match_label(struct aa_profile *profile,
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny,
struct apparmor_audit_data *ad);
static inline u32 denied_perms(struct aa_perms *perms, u32 request)
{
return request & (~perms->allow | perms->deny);
}
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
u32 request, struct apparmor_audit_data *ad,
void (*cb)(struct audit_buffer *, void *));
+108
View File
@@ -9,10 +9,13 @@
*/
#include <linux/gfp.h>
#include <linux/nsproxy.h>
#include <linux/ipc_namespace.h>
#include "include/audit.h"
#include "include/capability.h"
#include "include/cred.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/ipc.h"
#include "include/sig_names.h"
@@ -115,3 +118,108 @@ int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender,
profile_signal_perm(target_cred, profile, sender,
MAY_READ, &ad));
}
static void audit_mqueue_cb(struct audit_buffer *ab, void *va)
{
struct apparmor_audit_data *ad = aad_of_va(va);
aa_audit_perms(ab, ad, NULL, 0, NULL, AA_AUDIT_POSIX_MQUEUE_MASK);
/* move class into generic audit framse work */
audit_log_format(ab, "class=\"posix_mqueue\"");
if (ad->request & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " fsuid=%u",
from_kuid(&init_user_ns, ad->subj_cred->fsuid));
audit_log_format(ab, " ouid=%u",
from_kuid(&init_user_ns, ad->mq.ouid));
}
if (ad->peer) {
audit_log_format(ab, " olabel=");
aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAGS_NONE, GFP_ATOMIC);
}
}
int aa_profile_mqueue_perm(struct aa_profile *profile, const struct path *path,
u32 request, char *buffer,
struct apparmor_audit_data *ad)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms = { };
unsigned int state;
char *name;
if (profile_unconfined(profile) ||
!RULE_MEDIATES(rules, AA_CLASS_POSIX_MQUEUE))
return 0;
ad->subj_label = &profile->label;
name = dentry_path_raw(path->dentry, buffer, aa_g_path_max);
if (IS_ERR(name))
return PTR_ERR(name);
if (path->mnt != current->nsproxy->ipc_ns->mq_mnt) {
/* TODO: disconnected path detection */
pr_warn("apparmor mqueue disconnected TODO\n");
}
ad->name = name;
state = aa_dfa_match(rules->policy->dfa,
rules->policy->start[AA_CLASS_POSIX_MQUEUE],
name);
perms = *aa_lookup_perms(rules->policy, state);
aa_apply_modes_to_perms(profile, &perms);
if (!denied_perms(&perms, request)) {
/* early bailout sufficient perms no need to do further
* checks
*/
return aa_check_perms(profile, &perms, request, ad,
audit_mqueue_cb);
}
/* continue check to see if we have label perms */
//aa_label_match(profile, peer??, state false, request, &perms);
//aa_apply_modes_to_perms(profile, &perms);
// this will just cause failure without above label check
return aa_check_perms(profile, &perms, request, ad, audit_mqueue_cb);
}
/* mqueue - no label caching test */
int aa_mqueue_perm(const char *op, const struct cred *subj_cred,
struct aa_label *label,
const struct path *path, u32 request)
{
struct aa_profile *profile;
char *buffer;
int error;
DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_POSIX_MQUEUE, op);
// do we need delegate deleted with mqueues? probably
//flags |= PATH_DELEGATE_DELETED;
/* sadly due to rcu walk hairiness, we use dentry_path_raw instead
* of just accessing the name directly, which means we need to
* do the whole buffer allocation mess
*/
buffer = aa_get_buffer(false);
if (!buffer)
return -ENOMEM;
/* audit fields that won't change during iteration */
ad.subj_cred = subj_cred;
ad.request = request;
ad.peer = NULL;
ad.mq.ouid = d_backing_inode(path->dentry) ?
d_backing_inode(path->dentry)->i_uid :
subj_cred->fsuid;
error = fn_for_each_confined(label, profile,
aa_profile_mqueue_perm(profile, path, request,
buffer, &ad));
aa_put_buffer(buffer);
return error;
}
+25 -16
View File
@@ -172,7 +172,7 @@ void aa_str_kref(struct kref *kref)
const char aa_file_perm_chrs[] = "xwracd km l ";
const char *aa_file_perm_names[] = {
const char *aa_base_perm_names[] = {
"exec",
"write",
"read",
@@ -262,6 +262,10 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
{
char str[33];
if (!chrs)
chrs = aa_file_perm_chrs;
if (!names)
names = aa_base_perm_names;
audit_log_format(ab, "\"");
if ((mask & chrsmask) && chrs) {
aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
@@ -275,6 +279,22 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
audit_log_format(ab, "\"");
}
void aa_audit_perms(struct audit_buffer *ab, struct apparmor_audit_data *ad,
const char *chrs, u32 chrsmask, const char * const *names,
u32 namesmask)
{
if (ad->request) {
audit_log_format(ab, " requested=");
aa_audit_perm_mask(ab, ad->request, chrs, chrsmask,
names, namesmask);
}
if (ad->denied) {
audit_log_format(ab, " denied=");
aa_audit_perm_mask(ab, ad->denied, chrs, chrsmask,
names, namesmask);
}
}
/**
* aa_audit_perms_cb - generic callback fn for auditing perms
* @ab: audit buffer (NOT NULL)
@@ -282,21 +302,10 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
*/
static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
struct apparmor_audit_data *ad = aad(sa);
struct apparmor_audit_data *ad = aad_of_va(va);
if (ad->request) {
audit_log_format(ab, " requested_mask=");
aa_audit_perm_mask(ab, ad->request, aa_file_perm_chrs,
PERMS_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK);
}
if (ad->denied) {
audit_log_format(ab, "denied_mask=");
aa_audit_perm_mask(ab, ad->denied, aa_file_perm_chrs,
PERMS_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK);
}
aa_audit_perms(ab, ad, aa_file_perm_chrs, PERMS_CHRS_MASK,
aa_base_perm_names, PERMS_NAMES_MASK);
audit_log_format(ab, " peer=");
aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
FLAGS_NONE, GFP_ATOMIC);
@@ -390,7 +399,7 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
void (*cb)(struct audit_buffer *, void *))
{
int type, error;
u32 denied = request & (~perms->allow | perms->deny);
u32 denied = denied_perms(perms, request);
if (likely(!denied)) {
/* mask off perms that are not being force audited */
+190 -4
View File
@@ -18,6 +18,8 @@
#include <linux/ctype.h>
#include <linux/sysctl.h>
#include <linux/audit.h>
#include <linux/nsproxy.h>
#include <linux/ipc_namespace.h>
#include <linux/user_namespace.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
@@ -33,6 +35,7 @@
#include "include/capability.h"
#include "include/cred.h"
#include "include/file.h"
#include "include/inode.h"
#include "include/ipc.h"
#include "include/net.h"
#include "include/path.h"
@@ -65,6 +68,11 @@ static LIST_HEAD(aa_global_buffers);
static DEFINE_SPINLOCK(aa_buffers_lock);
static DEFINE_PER_CPU(struct aa_local_cache, aa_local_buffers);
static bool is_mqueue_dentry(struct dentry *dentry)
{
return dentry && is_mqueue_inode(d_backing_inode(dentry));
}
/*
* LSM hook functions
*/
@@ -452,11 +460,168 @@ static int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN);
}
static int common_mqueue_path_perm(const char *op, u32 request,
const struct path *path)
{
struct aa_label *label;
int error = 0;
label = begin_current_label_crit_section();
if (!unconfined(label))
error = aa_mqueue_perm(OP_UNLINK, current_cred(), label, path,
request);
end_current_label_crit_section(label);
return error;
}
static int apparmor_inode_getattr(const struct path *path)
{
if (is_mqueue_dentry(path->dentry))
/* TODO: fn() for d_parent */
return common_mqueue_path_perm(OP_UNLINK, AA_MAY_GETATTR, path);
return common_perm_cond(OP_GETATTR, path, AA_MAY_GETATTR);
}
/* inode security operations */
/* alloced by infrastructure */
static int apparmor_inode_alloc_security(struct inode *inode)
{
struct aa_inode_sec *isec = apparmor_inode(inode);
spin_lock_init(&isec->lock);
isec->inode = inode;
isec->label = NULL;
isec->sclass = 0;
isec->initialized = false;
return 0;
}
/* freed by infrastructure */
static void apparmor_inode_free_security(struct inode *inode)
{
struct aa_inode_sec *isec = apparmor_inode(inode);
if (!isec)
return;
aa_put_label(isec->label);
}
/* this is broken, in that we must make it work for ALL xattr fs
* or it will bail early, so this does not work with LSM stacking
*/
static int apparmor_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
struct xattr *xattrs, int *xattr_count)
{
struct aa_inode_sec *isec = apparmor_inode(inode);
if (is_mqueue_inode(dir)) {
/* only initialize based on implied label atm */
isec->label = aa_get_current_label();
isec->sclass = AA_CLASS_POSIX_MQUEUE;
isec->initialized = true;
}
/* we aren't setting xattrs yet so pretend it isn't supported,
* note bug in LSM means other LSMs won't get to init inode either
*/
return -EOPNOTSUPP;
}
static int inode_init_with_dentry(struct inode *inode, struct dentry *dentry)
{
struct aa_inode_sec *isec = apparmor_inode(inode);
if (isec->initialized)
return 0;
spin_lock(&isec->lock);
/* recheck under lock */
if (isec->initialized)
goto unlock;
if (is_mqueue_sb(inode->i_sb)) {
/* only initialize based on implied label atm */
isec->label = aa_get_current_label();
isec->sclass = AA_CLASS_POSIX_MQUEUE;
isec->initialized = true;
}
unlock:
spin_unlock(&isec->lock);
return 0;
}
static void apparmor_d_instantiate(struct dentry *dentry, struct inode *inode)
{
if (inode)
inode_init_with_dentry(inode, dentry);
}
static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
umode_t mode)
{
struct aa_label *label;
int error = 0;
label = begin_current_label_crit_section();
if (!unconfined(label)) {
struct path path = {
.dentry = dentry,
.mnt = current->nsproxy->ipc_ns->mq_mnt,
};
if (is_mqueue_inode(dir))
error = aa_mqueue_perm(OP_CREATE, current_cred(),
label, &path, AA_MAY_CREATE);
}
end_current_label_crit_section(label);
return error;
}
static int common_mqueue_perm(const char *op, u32 request, struct inode *dir, struct dentry *dentry)
{
/* can't directly determine ipc ns, but know for mqueues dir is mnt_root */
bool isdir = d_inode(current->nsproxy->ipc_ns->mq_mnt->mnt_root) == dir;
struct path path = {
.dentry = dentry,
.mnt = isdir ? current->nsproxy->ipc_ns->mq_mnt : NULL,
};
if (dir != d_inode(current->nsproxy->ipc_ns->mq_mnt->mnt_root))
pr_warn("apparmor: unlink dir != mnt_root - disconnected");
return common_mqueue_path_perm(op, request, &path);
}
static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry)
{
int error = 0;
if (is_mqueue_dentry(dentry))
error = common_mqueue_perm(OP_UNLINK, AA_MAY_DELETE, dir, dentry);
return error;
}
static int apparmor_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
/* TODO: extend to support iattr as a parameter */
if (is_mqueue_dentry(dentry))
/* TODO: fn() for d_parent */
return common_mqueue_perm(OP_UNLINK, AA_MAY_SETATTR,
d_backing_inode(dentry->d_parent), dentry);
return 0;
}
static int apparmor_file_open(struct file *file)
{
struct aa_file_ctx *fctx = file_ctx(file);
@@ -489,11 +654,17 @@ static int apparmor_file_open(struct file *file)
vfsuid = i_uid_into_vfsuid(idmap, inode);
cond.uid = vfsuid_into_kuid(vfsuid);
error = aa_path_perm(OP_OPEN, file->f_cred,
label, &file->f_path, 0,
aa_map_file_to_perms(file), &cond);
if (is_mqueue_inode(file_inode(file)))
error = aa_mqueue_perm(OP_OPEN, file->f_cred,
label, &file->f_path,
aa_map_file_to_perms(file));
else
error = aa_path_perm(OP_OPEN, file->f_cred,
label, &file->f_path, 0,
aa_map_file_to_perms(file), &cond);
/* todo cache full allowed permissions set and state */
fctx->allow = aa_map_file_to_perms(file);
if (!error)
fctx->allow = aa_map_file_to_perms(file);
}
aa_put_label(label);
@@ -505,6 +676,7 @@ static int apparmor_file_alloc_security(struct file *file)
struct aa_file_ctx *ctx = file_ctx(file);
struct aa_label *label = begin_current_label_crit_section();
/* no inode available here */
spin_lock_init(&ctx->lock);
rcu_assign_pointer(ctx->label, aa_get_label(label));
end_current_label_crit_section(label);
@@ -1516,9 +1688,13 @@ static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb
struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
.lbs_cred = sizeof(struct aa_label *),
.lbs_file = sizeof(struct aa_file_ctx),
.lbs_inode = sizeof(struct aa_inode_sec),
.lbs_task = sizeof(struct aa_task_ctx),
.lbs_sock = sizeof(struct aa_sk_ctx),
.lbs_secmark = true,
.lbs_ipc = sizeof(struct aa_ipc_sec),
.lbs_msg_msg = sizeof(struct aa_msg_sec),
.lbs_superblock = sizeof(struct aa_superblock_sec),
};
static const struct lsm_id apparmor_lsmid = {
@@ -1550,6 +1726,16 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(path_truncate, apparmor_path_truncate),
LSM_HOOK_INIT(inode_getattr, apparmor_inode_getattr),
LSM_HOOK_INIT(inode_alloc_security, apparmor_inode_alloc_security),
LSM_HOOK_INIT(inode_free_security, apparmor_inode_free_security),
LSM_HOOK_INIT(inode_init_security, apparmor_inode_init_security),
LSM_HOOK_INIT(d_instantiate, apparmor_d_instantiate),
LSM_HOOK_INIT(inode_create, apparmor_inode_create),
LSM_HOOK_INIT(inode_unlink, apparmor_inode_unlink),
LSM_HOOK_INIT(inode_setattr, apparmor_inode_setattr),
LSM_HOOK_INIT(inode_getattr, apparmor_inode_getattr),
LSM_HOOK_INIT(file_open, apparmor_file_open),
LSM_HOOK_INIT(file_receive, apparmor_file_receive),
LSM_HOOK_INIT(file_permission, apparmor_file_permission),