Commit aebd873e authored by John Johansen's avatar John Johansen

apparmor: refactor path name lookup and permission checks around labels

Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent 98c3d182
...@@ -152,6 +152,39 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment