mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-10 13:28:57 -04:00
apparmor: refactory mount to use check_perms
Move the mount permissions check to use the common backend aa_check_perms() to check permissions. This will make it so caching, audit, complain, logic can be handled consistently in a single place. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
@@ -140,6 +140,17 @@ static void audit_pre(struct audit_buffer *ab, void *va)
|
||||
}
|
||||
}
|
||||
|
||||
int aa_select_audit_type(u32 denied, const struct aa_perms *perms)
|
||||
{
|
||||
if (likely(!denied))
|
||||
return AUDIT_APPARMOR_AUDIT;
|
||||
else if (denied & perms->kill)
|
||||
return AUDIT_APPARMOR_KILL;
|
||||
else if (denied == (denied & perms->complain))
|
||||
return AUDIT_APPARMOR_ALLOWED;
|
||||
return AUDIT_APPARMOR_DENIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_audit_msg - Log a message to the audit subsystem
|
||||
* @type: audit type for the message
|
||||
@@ -153,6 +164,28 @@ void aa_audit_msg(int type, struct apparmor_audit_data *ad,
|
||||
common_lsm_audit(&ad->common, audit_pre, cb);
|
||||
}
|
||||
|
||||
int aa_audit_perm_error(struct aa_label *label, u32 request, int error,
|
||||
struct apparmor_audit_data *ad,
|
||||
void (*cb)(struct audit_buffer *, void *))
|
||||
{
|
||||
int type = aa_select_audit_type(request, &nullperms);
|
||||
|
||||
if (ad) {
|
||||
struct aa_profile *profile;
|
||||
struct label_it i;
|
||||
|
||||
ad->request = request;
|
||||
ad->denied = request;
|
||||
ad->error = error;
|
||||
label_for_each_confined(i, label, profile) {
|
||||
ad->subj_label = &profile->label;
|
||||
aa_audit_msg(type, ad, cb);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_audit - Log a profile based audit event to the audit subsystem
|
||||
* @type: audit type for the message
|
||||
|
||||
@@ -184,6 +184,8 @@ struct apparmor_audit_data {
|
||||
.common.apparmor_audit_data = &NAME, \
|
||||
};
|
||||
|
||||
int aa_select_audit_type(u32 denied, const struct aa_perms *perms);
|
||||
|
||||
void aa_audit_msg(int type, struct apparmor_audit_data *ad,
|
||||
void (*cb) (struct audit_buffer *, void *));
|
||||
int aa_audit(int type, struct aa_profile *profile,
|
||||
@@ -197,6 +199,9 @@ int aa_audit(int type, struct aa_profile *profile,
|
||||
(AD)->error; \
|
||||
})
|
||||
|
||||
int aa_audit_perm_error(struct aa_label *label, u32 request, int error,
|
||||
struct apparmor_audit_data *ad,
|
||||
void (*cb)(struct audit_buffer *, void *));
|
||||
|
||||
static inline int complain_error(int error)
|
||||
{
|
||||
|
||||
@@ -425,7 +425,7 @@ 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 *))
|
||||
{
|
||||
int type, error;
|
||||
int error;
|
||||
u32 denied = request & (~perms->allow | perms->deny);
|
||||
|
||||
if (likely(!denied)) {
|
||||
@@ -434,18 +434,10 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
|
||||
if (!request || !ad)
|
||||
return 0;
|
||||
|
||||
type = AUDIT_APPARMOR_AUDIT;
|
||||
error = 0;
|
||||
} else {
|
||||
error = -EACCES;
|
||||
|
||||
if (denied & perms->kill)
|
||||
type = AUDIT_APPARMOR_KILL;
|
||||
else if (denied == (denied & perms->complain))
|
||||
type = AUDIT_APPARMOR_ALLOWED;
|
||||
else
|
||||
type = AUDIT_APPARMOR_DENIED;
|
||||
|
||||
if (denied == (denied & perms->hide))
|
||||
error = -ENOENT;
|
||||
|
||||
@@ -454,6 +446,8 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
|
||||
return error;
|
||||
}
|
||||
|
||||
int type = aa_select_audit_type(denied, perms);
|
||||
|
||||
if (ad) {
|
||||
ad->subj_label = &profile->label;
|
||||
ad->request = request;
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
#include "include/policy.h"
|
||||
|
||||
|
||||
#define DEFINE_AUDIT_MOUNT(NAME, OP, CRED) \
|
||||
DEFINE_AUDIT_DATA(NAME, LSM_AUDIT_DATA_NONE, AA_CLASS_MOUNT, OP);\
|
||||
NAME.subj_cred = (CRED)
|
||||
|
||||
static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
|
||||
{
|
||||
if (flags & MS_RDONLY)
|
||||
@@ -113,78 +117,6 @@ static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_mount - handle the auditing of mount operations
|
||||
* @subj_cred: cred of the subject
|
||||
* @profile: the profile being enforced (NOT NULL)
|
||||
* @op: operation being mediated (NOT NULL)
|
||||
* @name: name of object being mediated (MAYBE NULL)
|
||||
* @src_name: src_name of object being mediated (MAYBE_NULL)
|
||||
* @type: type of filesystem (MAYBE_NULL)
|
||||
* @trans: name of trans (MAYBE NULL)
|
||||
* @flags: filesystem independent mount flags
|
||||
* @data: filesystem mount flags
|
||||
* @request: permissions requested
|
||||
* @perms: the permissions computed for the request (NOT NULL)
|
||||
* @info: extra information message (MAYBE NULL)
|
||||
* @error: 0 if operation allowed else failure error code
|
||||
*
|
||||
* Returns: %0 or error on failure
|
||||
*/
|
||||
static int audit_mount(const struct cred *subj_cred,
|
||||
struct aa_profile *profile, const char *op,
|
||||
const char *name, const char *src_name,
|
||||
const char *type, const char *trans,
|
||||
unsigned long flags, const void *data, u32 request,
|
||||
const struct aa_perms *perms, const char *info,
|
||||
int error)
|
||||
{
|
||||
int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_MOUNT, op);
|
||||
|
||||
if (likely(!error)) {
|
||||
u32 mask = perms->audit;
|
||||
|
||||
if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
|
||||
mask = 0xffff;
|
||||
|
||||
/* mask off perms that are not being force audited */
|
||||
request &= mask;
|
||||
|
||||
if (likely(!request))
|
||||
return 0;
|
||||
audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
} else {
|
||||
/* only report permissions that were denied */
|
||||
request = request & ~perms->allow;
|
||||
|
||||
if (request & perms->kill)
|
||||
audit_type = AUDIT_APPARMOR_KILL;
|
||||
|
||||
/* quiet known rejects, assumes quiet and kill do not overlap */
|
||||
if ((request & perms->quiet) &&
|
||||
AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
request &= ~perms->quiet;
|
||||
|
||||
if (!request)
|
||||
return error;
|
||||
}
|
||||
|
||||
ad.subj_cred = subj_cred;
|
||||
ad.name = name;
|
||||
ad.mnt.src_name = src_name;
|
||||
ad.mnt.type = type;
|
||||
ad.mnt.trans = trans;
|
||||
ad.mnt.flags = flags;
|
||||
if (data && (perms->audit & AA_AUDIT_DATA))
|
||||
ad.mnt.data = data;
|
||||
ad.info = info;
|
||||
ad.error = error;
|
||||
|
||||
return aa_audit(audit_type, profile, &ad, audit_cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* match_mnt_flags - Do an ordered match on mount flags
|
||||
* @dfa: dfa to match against
|
||||
@@ -290,7 +222,6 @@ static int path_flags(struct aa_profile *profile, const struct path *path)
|
||||
|
||||
/**
|
||||
* match_mnt_path_str - handle path matching for mount
|
||||
* @subj_cred: cred of confined subject
|
||||
* @profile: the confining profile
|
||||
* @mntpath: for the mntpnt (NOT NULL)
|
||||
* @buffer: buffer to be used to lookup mntpath
|
||||
@@ -300,18 +231,19 @@ static int path_flags(struct aa_profile *profile, const struct path *path)
|
||||
* @data: fs mount data (MAYBE NULL)
|
||||
* @binary: whether @data is binary
|
||||
* @devinfo: error str if (IS_ERR(@devname))
|
||||
* @ad: apparmor audit data structure
|
||||
*
|
||||
* Returns: 0 on success else error
|
||||
*/
|
||||
static int match_mnt_path_str(const struct cred *subj_cred,
|
||||
struct aa_profile *profile,
|
||||
static int match_mnt_path_str(struct aa_profile *profile,
|
||||
const struct path *mntpath, char *buffer,
|
||||
const char *devname, const char *type,
|
||||
unsigned long flags, void *data, bool binary,
|
||||
const char *devinfo)
|
||||
const char *devinfo,
|
||||
struct apparmor_audit_data *ad)
|
||||
{
|
||||
struct aa_perms perms = { };
|
||||
const char *mntpnt = NULL, *info = NULL;
|
||||
const char *mntpnt = NULL;
|
||||
struct aa_ruleset *rules = profile->label.rules[0];
|
||||
int pos, error;
|
||||
|
||||
@@ -322,36 +254,37 @@ static int match_mnt_path_str(const struct cred *subj_cred,
|
||||
if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT))
|
||||
return 0;
|
||||
|
||||
ad->mnt.type = type;
|
||||
|
||||
error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer,
|
||||
&mntpnt, &info, profile->disconnected);
|
||||
&mntpnt, &ad->info, profile->disconnected);
|
||||
if (error)
|
||||
goto audit;
|
||||
return aa_audit_perm_error(&profile->label, AA_MAY_MOUNT,
|
||||
error, ad, audit_cb);
|
||||
ad->name = mntpnt;
|
||||
|
||||
if (IS_ERR(devname)) {
|
||||
error = PTR_ERR(devname);
|
||||
devname = NULL;
|
||||
info = devinfo;
|
||||
goto audit;
|
||||
ad->info = devinfo;
|
||||
return aa_audit_perm_error(&profile->label, AA_MAY_MOUNT,
|
||||
error, ad, audit_cb);
|
||||
}
|
||||
ad->mnt.src_name = devname;
|
||||
|
||||
error = -EACCES;
|
||||
pos = do_match_mnt(rules->policy,
|
||||
rules->policy->start[AA_CLASS_MOUNT],
|
||||
mntpnt, devname, type, flags, data, binary, &perms);
|
||||
if (pos) {
|
||||
info = mnt_info_table[pos];
|
||||
goto audit;
|
||||
}
|
||||
error = 0;
|
||||
if (pos)
|
||||
ad->info = mnt_info_table[pos];
|
||||
|
||||
audit:
|
||||
return audit_mount(subj_cred, profile, OP_MOUNT, mntpnt, devname,
|
||||
type, NULL, flags, !binary ? data : NULL,
|
||||
AA_MAY_MOUNT, &perms, info, error);
|
||||
aa_apply_modes_to_perms(profile, &perms);
|
||||
if (data && !binary && (perms.audit & AA_AUDIT_DATA))
|
||||
ad->mnt.data = data;
|
||||
return aa_check_perms(profile, &perms, AA_MAY_MOUNT, ad, audit_cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* match_mnt - handle path matching for mount
|
||||
* @subj_cred: cred of the subject
|
||||
* @profile: the confining profile
|
||||
* @path: for the mntpnt (NOT NULL)
|
||||
* @buffer: buffer to be used to lookup mntpath
|
||||
@@ -361,14 +294,14 @@ static int match_mnt_path_str(const struct cred *subj_cred,
|
||||
* @flags: mount flags to match
|
||||
* @data: fs mount data (MAYBE NULL)
|
||||
* @binary: whether @data is binary
|
||||
* @ad: apparmor audit data structure
|
||||
*
|
||||
* Returns: 0 on success else error
|
||||
*/
|
||||
static int match_mnt(const struct cred *subj_cred,
|
||||
struct aa_profile *profile, const struct path *path,
|
||||
static int match_mnt(struct aa_profile *profile, const struct path *path,
|
||||
char *buffer, const struct path *devpath, char *devbuffer,
|
||||
const char *type, unsigned long flags, void *data,
|
||||
bool binary)
|
||||
bool binary, struct apparmor_audit_data *ad)
|
||||
{
|
||||
const char *devname = NULL, *info = NULL;
|
||||
struct aa_ruleset *rules = profile->label.rules[0];
|
||||
@@ -388,8 +321,8 @@ static int match_mnt(const struct cred *subj_cred,
|
||||
devname = ERR_PTR(error);
|
||||
}
|
||||
|
||||
return match_mnt_path_str(subj_cred, profile, path, buffer, devname,
|
||||
type, flags, data, binary, info);
|
||||
return match_mnt_path_str(profile, path, buffer, devname,
|
||||
type, flags, data, binary, info, ad);
|
||||
}
|
||||
|
||||
int aa_remount(const struct cred *subj_cred,
|
||||
@@ -400,6 +333,8 @@ int aa_remount(const struct cred *subj_cred,
|
||||
char *buffer = NULL;
|
||||
bool binary;
|
||||
int error;
|
||||
DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred);
|
||||
ad.mnt.flags = flags;
|
||||
|
||||
AA_BUG(!label);
|
||||
AA_BUG(!path);
|
||||
@@ -410,9 +345,8 @@ int aa_remount(const struct cred *subj_cred,
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
error = fn_for_each_confined(label, profile,
|
||||
match_mnt(subj_cred, profile, path, buffer, NULL,
|
||||
NULL, NULL,
|
||||
flags, data, binary));
|
||||
match_mnt(profile, path, buffer, NULL, NULL, NULL,
|
||||
flags, data, binary, &ad));
|
||||
aa_put_buffer(buffer);
|
||||
|
||||
return error;
|
||||
@@ -426,6 +360,7 @@ int aa_bind_mount(const struct cred *subj_cred,
|
||||
char *buffer = NULL, *old_buffer = NULL;
|
||||
struct path old_path;
|
||||
int error;
|
||||
DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred);
|
||||
|
||||
AA_BUG(!label);
|
||||
AA_BUG(!path);
|
||||
@@ -434,10 +369,12 @@ int aa_bind_mount(const struct cred *subj_cred,
|
||||
return -EINVAL;
|
||||
|
||||
flags &= MS_REC | MS_BIND;
|
||||
ad.mnt.flags = flags;
|
||||
|
||||
error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
|
||||
if (error)
|
||||
return error;
|
||||
return aa_audit_perm_error(label, AA_MAY_MOUNT, error, &ad,
|
||||
audit_cb);
|
||||
|
||||
buffer = aa_get_buffer(false);
|
||||
old_buffer = aa_get_buffer(false);
|
||||
@@ -446,8 +383,8 @@ int aa_bind_mount(const struct cred *subj_cred,
|
||||
goto out;
|
||||
|
||||
error = fn_for_each_confined(label, profile,
|
||||
match_mnt(subj_cred, profile, path, buffer, &old_path,
|
||||
old_buffer, NULL, flags, NULL, false));
|
||||
match_mnt(profile, path, buffer, &old_path,
|
||||
old_buffer, NULL, flags, NULL, false, &ad));
|
||||
out:
|
||||
aa_put_buffer(buffer);
|
||||
aa_put_buffer(old_buffer);
|
||||
@@ -463,6 +400,7 @@ int aa_mount_change_type(const struct cred *subj_cred,
|
||||
struct aa_profile *profile;
|
||||
char *buffer = NULL;
|
||||
int error;
|
||||
DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred);
|
||||
|
||||
AA_BUG(!label);
|
||||
AA_BUG(!path);
|
||||
@@ -470,14 +408,14 @@ int aa_mount_change_type(const struct cred *subj_cred,
|
||||
/* These are the flags allowed by do_change_type() */
|
||||
flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
|
||||
MS_UNBINDABLE);
|
||||
ad.mnt.flags = flags;
|
||||
|
||||
buffer = aa_get_buffer(false);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
error = fn_for_each_confined(label, profile,
|
||||
match_mnt(subj_cred, profile, path, buffer, NULL,
|
||||
NULL, NULL,
|
||||
flags, NULL, false));
|
||||
match_mnt(profile, path, buffer, NULL, NULL, NULL,
|
||||
flags, NULL, false, &ad));
|
||||
aa_put_buffer(buffer);
|
||||
|
||||
return error;
|
||||
@@ -490,6 +428,8 @@ int aa_move_mount(const struct cred *subj_cred,
|
||||
struct aa_profile *profile;
|
||||
char *to_buffer = NULL, *from_buffer = NULL;
|
||||
int error;
|
||||
DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred);
|
||||
ad.mnt.flags = MS_MOVE;
|
||||
|
||||
AA_BUG(!label);
|
||||
AA_BUG(!from_path);
|
||||
@@ -505,9 +445,9 @@ int aa_move_mount(const struct cred *subj_cred,
|
||||
/* moving a mount detached from the namespace */
|
||||
from_path = NULL;
|
||||
error = fn_for_each_confined(label, profile,
|
||||
match_mnt(subj_cred, profile, to_path, to_buffer,
|
||||
from_path, from_buffer,
|
||||
NULL, MS_MOVE, NULL, false));
|
||||
match_mnt(profile, to_path, to_buffer, from_path,
|
||||
from_buffer, NULL, MS_MOVE, NULL, false,
|
||||
&ad));
|
||||
out:
|
||||
aa_put_buffer(to_buffer);
|
||||
aa_put_buffer(from_buffer);
|
||||
@@ -543,6 +483,8 @@ int aa_new_mount(const struct cred *subj_cred, struct aa_label *label,
|
||||
int error;
|
||||
int requires_dev = 0;
|
||||
struct path tmp_path, *dev_path = NULL;
|
||||
DEFINE_AUDIT_MOUNT(ad, OP_MOUNT, subj_cred);
|
||||
ad.mnt.flags = flags;
|
||||
|
||||
AA_BUG(!label);
|
||||
AA_BUG(!path);
|
||||
@@ -580,14 +522,14 @@ int aa_new_mount(const struct cred *subj_cred, struct aa_label *label,
|
||||
goto out;
|
||||
}
|
||||
error = fn_for_each_confined(label, profile,
|
||||
match_mnt(subj_cred, profile, path, buffer,
|
||||
dev_path, dev_buffer,
|
||||
type, flags, data, binary));
|
||||
match_mnt(profile, path, buffer, dev_path,
|
||||
dev_buffer, type, flags, data,
|
||||
binary, &ad));
|
||||
} else {
|
||||
error = fn_for_each_confined(label, profile,
|
||||
match_mnt_path_str(subj_cred, profile, path,
|
||||
buffer, dev_name,
|
||||
type, flags, data, binary, NULL));
|
||||
match_mnt_path_str(profile, path, buffer,
|
||||
dev_name, type, flags, data,
|
||||
binary, NULL, &ad));
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -599,13 +541,12 @@ int aa_new_mount(const struct cred *subj_cred, struct aa_label *label,
|
||||
return error;
|
||||
}
|
||||
|
||||
static int profile_umount(const struct cred *subj_cred,
|
||||
struct aa_profile *profile, const struct path *path,
|
||||
char *buffer)
|
||||
static int profile_umount(struct aa_profile *profile, const struct path *path,
|
||||
char *buffer, struct apparmor_audit_data *ad)
|
||||
{
|
||||
struct aa_ruleset *rules = profile->label.rules[0];
|
||||
struct aa_perms perms = { };
|
||||
const char *name = NULL, *info = NULL;
|
||||
const char *name = NULL;
|
||||
aa_state_t state;
|
||||
int error;
|
||||
|
||||
@@ -615,22 +556,23 @@ static int profile_umount(const struct cred *subj_cred,
|
||||
if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT))
|
||||
return 0;
|
||||
|
||||
/* TODO: lift path_name, need to separate profile path_flags from
|
||||
* the lookup
|
||||
*/
|
||||
error = aa_path_name(path, path_flags(profile, path), buffer, &name,
|
||||
&info, profile->disconnected);
|
||||
&ad->info, profile->disconnected);
|
||||
if (error)
|
||||
goto audit;
|
||||
return aa_audit_perm_error(&profile->label, AA_MAY_UMOUNT,
|
||||
error, ad, audit_cb);
|
||||
|
||||
ad->name = name;
|
||||
state = aa_dfa_match(rules->policy->dfa,
|
||||
rules->policy->start[AA_CLASS_MOUNT],
|
||||
name);
|
||||
perms = *aa_lookup_perms(rules->policy, state);
|
||||
if (AA_MAY_UMOUNT & ~perms.allow)
|
||||
error = -EACCES;
|
||||
|
||||
audit:
|
||||
return audit_mount(subj_cred, profile, OP_UMOUNT, name, NULL, NULL,
|
||||
NULL, 0, NULL,
|
||||
AA_MAY_UMOUNT, &perms, info, error);
|
||||
aa_apply_modes_to_perms(profile, &perms);
|
||||
return aa_check_perms(profile, &perms, AA_MAY_UMOUNT, ad, audit_cb);
|
||||
}
|
||||
|
||||
int aa_umount(const struct cred *subj_cred, struct aa_label *label,
|
||||
@@ -640,6 +582,7 @@ int aa_umount(const struct cred *subj_cred, struct aa_label *label,
|
||||
char *buffer = NULL;
|
||||
int error;
|
||||
struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
|
||||
DEFINE_AUDIT_MOUNT(ad, OP_UMOUNT, subj_cred);
|
||||
|
||||
AA_BUG(!label);
|
||||
AA_BUG(!mnt);
|
||||
@@ -649,7 +592,7 @@ int aa_umount(const struct cred *subj_cred, struct aa_label *label,
|
||||
return -ENOMEM;
|
||||
|
||||
error = fn_for_each_confined(label, profile,
|
||||
profile_umount(subj_cred, profile, &path, buffer));
|
||||
profile_umount(profile, &path, buffer, &ad));
|
||||
aa_put_buffer(buffer);
|
||||
|
||||
return error;
|
||||
@@ -659,16 +602,15 @@ int aa_umount(const struct cred *subj_cred, struct aa_label *label,
|
||||
*
|
||||
* Returns: label for transition or ERR_PTR. Does not return NULL
|
||||
*/
|
||||
static struct aa_label *build_pivotroot(const struct cred *subj_cred,
|
||||
struct aa_profile *profile,
|
||||
static struct aa_label *build_pivotroot(struct aa_profile *profile,
|
||||
const struct path *new_path,
|
||||
char *new_buffer,
|
||||
const struct path *old_path,
|
||||
char *old_buffer)
|
||||
char *old_buffer,
|
||||
struct apparmor_audit_data *ad)
|
||||
{
|
||||
struct aa_ruleset *rules = profile->label.rules[0];
|
||||
const char *old_name, *new_name = NULL, *info = NULL;
|
||||
const char *trans_name = NULL;
|
||||
const char *old_name, *new_name = NULL;
|
||||
struct aa_perms perms = { };
|
||||
aa_state_t state;
|
||||
int error;
|
||||
@@ -682,36 +624,40 @@ static struct aa_label *build_pivotroot(const struct cred *subj_cred,
|
||||
return aa_get_newest_label(&profile->label);
|
||||
|
||||
error = aa_path_name(old_path, path_flags(profile, old_path),
|
||||
old_buffer, &old_name, &info,
|
||||
old_buffer, &old_name, &ad->info,
|
||||
profile->disconnected);
|
||||
if (error)
|
||||
goto audit;
|
||||
goto err;
|
||||
ad->mnt.src_name = old_name;
|
||||
error = aa_path_name(new_path, path_flags(profile, new_path),
|
||||
new_buffer, &new_name, &info,
|
||||
new_buffer, &new_name, &ad->info,
|
||||
profile->disconnected);
|
||||
if (error)
|
||||
goto audit;
|
||||
goto err;
|
||||
ad->name = new_name;
|
||||
|
||||
error = -EACCES;
|
||||
state = aa_dfa_match(rules->policy->dfa,
|
||||
rules->policy->start[AA_CLASS_MOUNT],
|
||||
new_name);
|
||||
state = aa_dfa_null_transition(rules->policy->dfa, state);
|
||||
state = aa_dfa_match(rules->policy->dfa, state, old_name);
|
||||
perms = *aa_lookup_perms(rules->policy, state);
|
||||
/* todo: allow pivotroot to specify a transition other than profile */
|
||||
ad->mnt.trans = profile->label.hname;
|
||||
|
||||
if (AA_MAY_PIVOTROOT & perms.allow)
|
||||
error = 0;
|
||||
aa_apply_modes_to_perms(profile, &perms);
|
||||
error = aa_check_perms(profile, &perms, AA_MAY_PIVOTROOT, ad, audit_cb);
|
||||
|
||||
audit:
|
||||
error = audit_mount(subj_cred, profile, OP_PIVOTROOT, new_name,
|
||||
old_name,
|
||||
NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT,
|
||||
&perms, info, error);
|
||||
out:
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
return aa_get_newest_label(&profile->label);
|
||||
|
||||
err:
|
||||
error = aa_audit_perm_error(&profile->label, AA_MAY_PIVOTROOT, error,
|
||||
ad, audit_cb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label,
|
||||
@@ -720,8 +666,9 @@ int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label,
|
||||
{
|
||||
struct aa_profile *profile;
|
||||
struct aa_label *target = NULL;
|
||||
char *old_buffer = NULL, *new_buffer = NULL, *info = NULL;
|
||||
char *old_buffer = NULL, *new_buffer = NULL;
|
||||
int error;
|
||||
DEFINE_AUDIT_MOUNT(ad, OP_PIVOTROOT, subj_cred);
|
||||
|
||||
AA_BUG(!label);
|
||||
AA_BUG(!old_path);
|
||||
@@ -733,9 +680,8 @@ int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label,
|
||||
if (!old_buffer || !new_buffer)
|
||||
goto out;
|
||||
target = fn_label_build(label, profile, GFP_KERNEL,
|
||||
build_pivotroot(subj_cred, profile, new_path,
|
||||
new_buffer,
|
||||
old_path, old_buffer));
|
||||
build_pivotroot(profile, new_path, new_buffer,
|
||||
old_path, old_buffer, &ad));
|
||||
AA_BUG(!target);
|
||||
if (!IS_ERR(target)) {
|
||||
error = aa_replace_current_label(target);
|
||||
@@ -743,7 +689,7 @@ int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label,
|
||||
goto fail;
|
||||
aa_put_label(target);
|
||||
} else
|
||||
/* already audited error */
|
||||
/* already audited error in build_pivotroot */
|
||||
error = PTR_ERR(target);
|
||||
out:
|
||||
aa_put_buffer(old_buffer);
|
||||
@@ -752,14 +698,12 @@ int aa_pivotroot(const struct cred *subj_cred, struct aa_label *label,
|
||||
return error;
|
||||
|
||||
fail:
|
||||
/* TODO: add back in auditing of new_name and old_name */
|
||||
error = fn_for_each(label, profile,
|
||||
audit_mount(subj_cred, profile, OP_PIVOTROOT,
|
||||
NULL /*new_name */,
|
||||
NULL /* old_name */,
|
||||
NULL, NULL,
|
||||
0, target->hname, AA_MAY_PIVOTROOT, &nullperms, info,
|
||||
error));
|
||||
/* TODO: add back in auditing of new_name and old_name,
|
||||
* needs lifting of name lookup out of profile cb
|
||||
*/
|
||||
ad.mnt.trans = target->hname;
|
||||
error = aa_audit_perm_error(label, AA_MAY_PIVOTROOT, error, &ad,
|
||||
audit_cb);
|
||||
aa_put_label(target);
|
||||
goto out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user