apparmor: move aa_file_perm() to use labels
Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
290f458a4f
commit
190a95189e
@ -23,6 +23,7 @@
|
|||||||
#include "include/match.h"
|
#include "include/match.h"
|
||||||
#include "include/path.h"
|
#include "include/path.h"
|
||||||
#include "include/policy.h"
|
#include "include/policy.h"
|
||||||
|
#include "include/label.h"
|
||||||
|
|
||||||
static u32 map_mask_to_chr_mask(u32 mask)
|
static u32 map_mask_to_chr_mask(u32 mask)
|
||||||
{
|
{
|
||||||
@ -433,22 +434,55 @@ audit:
|
|||||||
/**
|
/**
|
||||||
* aa_file_perm - do permission revalidation check & audit for @file
|
* aa_file_perm - do permission revalidation check & audit for @file
|
||||||
* @op: operation being checked
|
* @op: operation being checked
|
||||||
* @profile: profile being enforced (NOT NULL)
|
* @label: label being enforced (NOT NULL)
|
||||||
* @file: file to revalidate access permissions on (NOT NULL)
|
* @file: file to revalidate access permissions on (NOT NULL)
|
||||||
* @request: requested permissions
|
* @request: requested permissions
|
||||||
*
|
*
|
||||||
* Returns: %0 if access allowed else error
|
* Returns: %0 if access allowed else error
|
||||||
*/
|
*/
|
||||||
int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
|
int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
|
||||||
u32 request)
|
u32 request)
|
||||||
{
|
{
|
||||||
struct path_cond cond = {
|
struct path_cond cond = {
|
||||||
.uid = file_inode(file)->i_uid,
|
.uid = file_inode(file)->i_uid,
|
||||||
.mode = file_inode(file)->i_mode
|
.mode = file_inode(file)->i_mode
|
||||||
};
|
};
|
||||||
|
struct aa_file_ctx *fctx;
|
||||||
|
struct aa_label *flabel;
|
||||||
|
u32 denied;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
|
AA_BUG(!label);
|
||||||
request, &cond);
|
AA_BUG(!file);
|
||||||
|
|
||||||
|
fctx = file_ctx(file);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
flabel = rcu_dereference(fctx->label);
|
||||||
|
AA_BUG(!flabel);
|
||||||
|
|
||||||
|
/* revalidate access, if task is unconfined, or the cached cred
|
||||||
|
* doesn't match or if the request is for more permissions than
|
||||||
|
* was granted.
|
||||||
|
*
|
||||||
|
* Note: the test for !unconfined(flabel) is to handle file
|
||||||
|
* delegation from unconfined tasks
|
||||||
|
*/
|
||||||
|
denied = request & ~fctx->allow;
|
||||||
|
if (unconfined(label) || unconfined(flabel) ||
|
||||||
|
(!denied && aa_label_is_subset(flabel, label)))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* TODO: label cross check */
|
||||||
|
|
||||||
|
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
|
||||||
|
error = aa_path_perm(op, labels_profile(label), &file->f_path,
|
||||||
|
PATH_DELEGATE_DELETED, request, &cond);
|
||||||
|
|
||||||
|
done:
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void revalidate_tty(struct aa_label *label)
|
static void revalidate_tty(struct aa_label *label)
|
||||||
@ -469,8 +503,7 @@ static void revalidate_tty(struct aa_label *label)
|
|||||||
struct tty_file_private, list);
|
struct tty_file_private, list);
|
||||||
file = file_priv->file;
|
file = file_priv->file;
|
||||||
|
|
||||||
if (aa_file_perm(OP_INHERIT, labels_profile(label), file,
|
if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE))
|
||||||
MAY_READ | MAY_WRITE))
|
|
||||||
drop_tty = 1;
|
drop_tty = 1;
|
||||||
}
|
}
|
||||||
spin_unlock(&tty->files_lock);
|
spin_unlock(&tty->files_lock);
|
||||||
@ -484,8 +517,7 @@ static int match_file(const void *p, struct file *file, unsigned int fd)
|
|||||||
{
|
{
|
||||||
struct aa_label *label = (struct aa_label *)p;
|
struct aa_label *label = (struct aa_label *)p;
|
||||||
|
|
||||||
if (aa_file_perm(OP_INHERIT, labels_profile(label), file,
|
if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file)))
|
||||||
aa_map_file_to_perms(file)))
|
|
||||||
return fd + 1;
|
return fd + 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
#ifndef __AA_FILE_H
|
#ifndef __AA_FILE_H
|
||||||
#define __AA_FILE_H
|
#define __AA_FILE_H
|
||||||
|
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
#include "domain.h"
|
#include "domain.h"
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
#include "perms.h"
|
#include "perms.h"
|
||||||
@ -33,13 +35,13 @@ struct path;
|
|||||||
#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
|
#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
|
||||||
|
|
||||||
/* struct aa_file_ctx - the AppArmor context the file was opened in
|
/* struct aa_file_ctx - the AppArmor context the file was opened in
|
||||||
|
* @lock: lock to update the ctx
|
||||||
|
* @label: label currently cached on the ctx
|
||||||
* @perms: the permission the file was opened with
|
* @perms: the permission the file was opened with
|
||||||
*
|
|
||||||
* The file_ctx could currently be directly stored in file->f_security
|
|
||||||
* as the profile reference is now stored in the f_cred. However the
|
|
||||||
* ctx struct will expand in the future so we keep the struct.
|
|
||||||
*/
|
*/
|
||||||
struct aa_file_ctx {
|
struct aa_file_ctx {
|
||||||
|
spinlock_t lock;
|
||||||
|
struct aa_label __rcu *label;
|
||||||
u32 allow;
|
u32 allow;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,12 +52,16 @@ struct aa_file_ctx {
|
|||||||
*
|
*
|
||||||
* Returns: file_ctx or NULL on failure
|
* Returns: file_ctx or NULL on failure
|
||||||
*/
|
*/
|
||||||
static inline struct aa_file_ctx *aa_alloc_file_ctx(gfp_t gfp)
|
static inline struct aa_file_ctx *aa_alloc_file_ctx(struct aa_label *label,
|
||||||
|
gfp_t gfp)
|
||||||
{
|
{
|
||||||
struct aa_file_ctx *ctx;
|
struct aa_file_ctx *ctx;
|
||||||
|
|
||||||
ctx = kzalloc(sizeof(struct aa_file_ctx), gfp);
|
ctx = kzalloc(sizeof(struct aa_file_ctx), gfp);
|
||||||
|
if (ctx) {
|
||||||
|
spin_lock_init(&ctx->lock);
|
||||||
|
rcu_assign_pointer(ctx->label, aa_get_label(label));
|
||||||
|
}
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +71,15 @@ static inline struct aa_file_ctx *aa_alloc_file_ctx(gfp_t gfp)
|
|||||||
*/
|
*/
|
||||||
static inline void aa_free_file_ctx(struct aa_file_ctx *ctx)
|
static inline void aa_free_file_ctx(struct aa_file_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (ctx)
|
if (ctx) {
|
||||||
|
aa_put_label(rcu_access_pointer(ctx->label));
|
||||||
kzfree(ctx);
|
kzfree(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct aa_label *aa_get_file_label(struct aa_file_ctx *ctx)
|
||||||
|
{
|
||||||
|
return aa_get_label_rcu(&ctx->label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -183,7 +196,7 @@ int aa_path_perm(const char *op, struct aa_profile *profile,
|
|||||||
int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
|
int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
|
||||||
const struct path *new_dir, struct dentry *new_dentry);
|
const struct path *new_dir, struct dentry *new_dentry);
|
||||||
|
|
||||||
int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
|
int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
|
||||||
u32 request);
|
u32 request);
|
||||||
|
|
||||||
void aa_inherit_files(const struct cred *cred, struct files_struct *files);
|
void aa_inherit_files(const struct cred *cred, struct files_struct *files);
|
||||||
|
@ -433,7 +433,7 @@ static int apparmor_file_alloc_security(struct file *file)
|
|||||||
|
|
||||||
/* freed by apparmor_file_free_security */
|
/* freed by apparmor_file_free_security */
|
||||||
struct aa_label *label = begin_current_label_crit_section();
|
struct aa_label *label = begin_current_label_crit_section();
|
||||||
file->f_security = aa_alloc_file_ctx(GFP_KERNEL);
|
file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
|
||||||
if (!file_ctx(file))
|
if (!file_ctx(file))
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
end_current_label_crit_section(label);
|
end_current_label_crit_section(label);
|
||||||
@ -448,33 +448,15 @@ static void apparmor_file_free_security(struct file *file)
|
|||||||
|
|
||||||
static int common_file_perm(const char *op, struct file *file, u32 mask)
|
static int common_file_perm(const char *op, struct file *file, u32 mask)
|
||||||
{
|
{
|
||||||
struct aa_file_ctx *fctx = file->f_security;
|
struct aa_label *label;
|
||||||
struct aa_label *label, *flabel;
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
/* don't reaudit files closed during inheritance */
|
/* don't reaudit files closed during inheritance */
|
||||||
if (file->f_path.dentry == aa_null.dentry)
|
if (file->f_path.dentry == aa_null.dentry)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
flabel = aa_cred_raw_label(file->f_cred);
|
|
||||||
AA_BUG(!flabel);
|
|
||||||
|
|
||||||
if (!file->f_path.mnt ||
|
|
||||||
!path_mediated_fs(file->f_path.dentry))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
label = __begin_current_label_crit_section();
|
label = __begin_current_label_crit_section();
|
||||||
|
error = aa_file_perm(op, label, file, mask);
|
||||||
/* revalidate access, if task is unconfined, or the cached cred
|
|
||||||
* doesn't match or if the request is for more permissions than
|
|
||||||
* was granted.
|
|
||||||
*
|
|
||||||
* Note: the test for !unconfined(fprofile) is to handle file
|
|
||||||
* delegation from unconfined tasks
|
|
||||||
*/
|
|
||||||
if (!unconfined(label) && !unconfined(flabel) &&
|
|
||||||
((flabel != label) || (mask & ~fctx->allow)))
|
|
||||||
error = aa_file_perm(op, labels_profile(label), file, mask);
|
|
||||||
__end_current_label_crit_section(label);
|
__end_current_label_crit_section(label);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user