apparmor: refactor path name lookup and permission checks around labels
Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
98c3d18232
commit
aebd873e8d
@ -152,6 +152,39 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms,
|
|||||||
return aa_audit(type, profile, &sa, file_audit_cb);
|
return aa_audit(type, profile, &sa, file_audit_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is_deleted - test if a file has been completely unlinked
|
||||||
|
* @dentry: dentry of file to test for deletion (NOT NULL)
|
||||||
|
*
|
||||||
|
* Returns: %1 if deleted else %0
|
||||||
|
*/
|
||||||
|
static inline bool is_deleted(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int path_name(const char *op, struct aa_label *label,
|
||||||
|
const struct path *path, int flags, char *buffer,
|
||||||
|
const char **name, struct path_cond *cond, u32 request)
|
||||||
|
{
|
||||||
|
struct aa_profile *profile;
|
||||||
|
const char *info = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = aa_path_name(path, flags, buffer, name, &info,
|
||||||
|
labels_profile(label)->disconnected);
|
||||||
|
if (error) {
|
||||||
|
fn_for_each_confined(label, profile,
|
||||||
|
aa_audit_file(profile, &nullperms, op, request, *name,
|
||||||
|
NULL, NULL, cond->uid, info, error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* map_old_perms - map old file perms layout to the new layout
|
* map_old_perms - map old file perms layout to the new layout
|
||||||
* @old: permission set in old mapping
|
* @old: permission set in old mapping
|
||||||
@ -249,23 +282,46 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name,
|
||||||
* is_deleted - test if a file has been completely unlinked
|
u32 request, struct path_cond *cond, int flags,
|
||||||
* @dentry: dentry of file to test for deletion (NOT NULL)
|
struct aa_perms *perms)
|
||||||
*
|
|
||||||
* Returns: %1 if deleted else %0
|
|
||||||
*/
|
|
||||||
static inline bool is_deleted(struct dentry *dentry)
|
|
||||||
{
|
{
|
||||||
if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0)
|
int e = 0;
|
||||||
return 1;
|
|
||||||
return 0;
|
if (profile_unconfined(profile))
|
||||||
|
return 0;
|
||||||
|
aa_str_perms(profile->file.dfa, profile->file.start, name, cond, perms);
|
||||||
|
if (request & ~perms->allow)
|
||||||
|
e = -EACCES;
|
||||||
|
return aa_audit_file(profile, perms, op, request, name, NULL, NULL,
|
||||||
|
cond->uid, NULL, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int profile_path_perm(const char *op, struct aa_profile *profile,
|
||||||
|
const struct path *path, char *buffer, u32 request,
|
||||||
|
struct path_cond *cond, int flags,
|
||||||
|
struct aa_perms *perms)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (profile_unconfined(profile))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error = path_name(op, &profile->label, path,
|
||||||
|
flags | profile->path_flags, buffer, &name, cond,
|
||||||
|
request);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
return __aa_path_perm(op, profile, name, request, cond, flags,
|
||||||
|
perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aa_path_perm - do permissions check & audit for @path
|
* aa_path_perm - do permissions check & audit for @path
|
||||||
* @op: operation being checked
|
* @op: operation being checked
|
||||||
* @profile: profile being enforced (NOT NULL)
|
* @label: profile being enforced (NOT NULL)
|
||||||
* @path: path to check permissions of (NOT NULL)
|
* @path: path to check permissions of (NOT NULL)
|
||||||
* @flags: any additional path flags beyond what the profile specifies
|
* @flags: any additional path flags beyond what the profile specifies
|
||||||
* @request: requested permissions
|
* @request: requested permissions
|
||||||
@ -273,36 +329,22 @@ static inline bool is_deleted(struct dentry *dentry)
|
|||||||
*
|
*
|
||||||
* Returns: %0 else error if access denied or other error
|
* Returns: %0 else error if access denied or other error
|
||||||
*/
|
*/
|
||||||
int aa_path_perm(const char *op, struct aa_profile *profile,
|
int aa_path_perm(const char *op, struct aa_label *label,
|
||||||
const struct path *path, int flags, u32 request,
|
const struct path *path, int flags, u32 request,
|
||||||
struct path_cond *cond)
|
struct path_cond *cond)
|
||||||
{
|
{
|
||||||
char *buffer = NULL;
|
|
||||||
struct aa_perms perms = {};
|
struct aa_perms perms = {};
|
||||||
const char *name, *info = NULL;
|
struct aa_profile *profile;
|
||||||
|
char *buffer = NULL;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
|
flags |= PATH_DELEGATE_DELETED | (S_ISDIR(cond->mode) ? PATH_IS_DIR :
|
||||||
|
0);
|
||||||
get_buffers(buffer);
|
get_buffers(buffer);
|
||||||
error = aa_path_name(path, flags, buffer, &name, &info,
|
error = fn_for_each_confined(label, profile,
|
||||||
profile->disconnected);
|
profile_path_perm(op, profile, path, buffer, request,
|
||||||
if (error) {
|
cond, flags, &perms));
|
||||||
if (error == -ENOENT && is_deleted(path->dentry)) {
|
|
||||||
/* Access to open files that are deleted are
|
|
||||||
* give a pass (implicit delegation)
|
|
||||||
*/
|
|
||||||
error = 0;
|
|
||||||
info = NULL;
|
|
||||||
perms.allow = request;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
|
|
||||||
&perms);
|
|
||||||
if (request & ~perms.allow)
|
|
||||||
error = -EACCES;
|
|
||||||
}
|
|
||||||
error = aa_audit_file(profile, &perms, op, request, name, NULL, NULL,
|
|
||||||
cond->uid, info, error);
|
|
||||||
put_buffers(buffer);
|
put_buffers(buffer);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -482,7 +524,7 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
|
|||||||
/* TODO: label cross check */
|
/* TODO: label cross check */
|
||||||
|
|
||||||
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
|
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
|
||||||
error = aa_path_perm(op, labels_profile(label), &file->f_path,
|
error = aa_path_perm(op, label, &file->f_path,
|
||||||
PATH_DELEGATE_DELETED, request, &cond);
|
PATH_DELEGATE_DELETED, request, &cond);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -190,7 +190,10 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
|
|||||||
const char *name, struct path_cond *cond,
|
const char *name, struct path_cond *cond,
|
||||||
struct aa_perms *perms);
|
struct aa_perms *perms);
|
||||||
|
|
||||||
int aa_path_perm(const char *op, struct aa_profile *profile,
|
int __aa_path_perm(const char *op, struct aa_profile *profile,
|
||||||
|
const char *name, u32 request, struct path_cond *cond,
|
||||||
|
int flags, struct aa_perms *perms);
|
||||||
|
int aa_path_perm(const char *op, struct aa_label *label,
|
||||||
const struct path *path, int flags, u32 request,
|
const struct path *path, int flags, u32 request,
|
||||||
struct path_cond *cond);
|
struct path_cond *cond);
|
||||||
|
|
||||||
|
@ -196,8 +196,7 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
|
|||||||
|
|
||||||
label = __begin_current_label_crit_section();
|
label = __begin_current_label_crit_section();
|
||||||
if (!unconfined(label))
|
if (!unconfined(label))
|
||||||
error = aa_path_perm(op, labels_profile(label), path, 0, mask,
|
error = aa_path_perm(op, label, path, 0, mask, cond);
|
||||||
cond);
|
|
||||||
__end_current_label_crit_section(label);
|
__end_current_label_crit_section(label);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -359,15 +358,12 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
|
|||||||
d_backing_inode(old_dentry)->i_mode
|
d_backing_inode(old_dentry)->i_mode
|
||||||
};
|
};
|
||||||
|
|
||||||
error = aa_path_perm(OP_RENAME_SRC, labels_profile(label),
|
error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0,
|
||||||
&old_path, 0,
|
|
||||||
MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
|
MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
|
||||||
AA_MAY_SETATTR | AA_MAY_DELETE,
|
AA_MAY_SETATTR | AA_MAY_DELETE,
|
||||||
&cond);
|
&cond);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = aa_path_perm(OP_RENAME_DEST,
|
error = aa_path_perm(OP_RENAME_DEST, label, &new_path,
|
||||||
labels_profile(label),
|
|
||||||
&new_path,
|
|
||||||
0, MAY_WRITE | AA_MAY_SETATTR |
|
0, MAY_WRITE | AA_MAY_SETATTR |
|
||||||
AA_MAY_CREATE, &cond);
|
AA_MAY_CREATE, &cond);
|
||||||
|
|
||||||
@ -416,8 +412,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
|
|||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct path_cond cond = { inode->i_uid, inode->i_mode };
|
struct path_cond cond = { inode->i_uid, inode->i_mode };
|
||||||
|
|
||||||
error = aa_path_perm(OP_OPEN, labels_profile(label),
|
error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
|
||||||
&file->f_path, 0,
|
|
||||||
aa_map_file_to_perms(file), &cond);
|
aa_map_file_to_perms(file), &cond);
|
||||||
/* todo cache full allowed permissions set and state */
|
/* todo cache full allowed permissions set and state */
|
||||||
fctx->allow = aa_map_file_to_perms(file);
|
fctx->allow = aa_map_file_to_perms(file);
|
||||||
|
Loading…
Reference in New Issue
Block a user