Skip to content

Commit

Permalink
LSM: Infrastructure management of the file security
Browse files Browse the repository at this point in the history
Move management of the file->f_security blob out of the
individual security modules and into the infrastructure.
The modules no longer allocate or free the data, instead
they tell the infrastructure how much space they require.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
[kees: adjusted for ordered init series]
Signed-off-by: Kees Cook <keescook@chromium.org>
  • Loading branch information
Casey Schaufler authored and Kees Cook committed Jan 8, 2019
1 parent f28952a commit 33bf60c
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 51 deletions.
1 change: 1 addition & 0 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -2032,6 +2032,7 @@ struct security_hook_list {
*/
struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
};

/*
Expand Down
5 changes: 4 additions & 1 deletion security/apparmor/include/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ struct path;
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
AA_EXEC_MMAP | AA_MAY_LINK)

#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
static inline struct aa_file_ctx *file_ctx(struct file *file)
{
return file->f_security + apparmor_blob_sizes.lbs_file;
}

/* struct aa_file_ctx - the AppArmor context the file was opened in
* @lock: lock to update the ctx
Expand Down
19 changes: 10 additions & 9 deletions security/apparmor/lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,21 +434,21 @@ static int apparmor_file_open(struct file *file)

static int apparmor_file_alloc_security(struct file *file)
{
int error = 0;

/* freed by apparmor_file_free_security */
struct aa_file_ctx *ctx = file_ctx(file);
struct aa_label *label = begin_current_label_crit_section();
file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
if (!file_ctx(file))
error = -ENOMEM;
end_current_label_crit_section(label);

return error;
spin_lock_init(&ctx->lock);
rcu_assign_pointer(ctx->label, aa_get_label(label));
end_current_label_crit_section(label);
return 0;
}

static void apparmor_file_free_security(struct file *file)
{
aa_free_file_ctx(file_ctx(file));
struct aa_file_ctx *ctx = file_ctx(file);

if (ctx)
aa_put_label(rcu_access_pointer(ctx->label));
}

static int common_file_perm(const char *op, struct file *file, u32 mask)
Expand Down Expand Up @@ -1156,6 +1156,7 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
*/
struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
.lbs_cred = sizeof(struct aa_task_ctx *),
.lbs_file = sizeof(struct aa_file_ctx),
};

static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
Expand Down
54 changes: 51 additions & 3 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

static struct kmem_cache *lsm_file_cache;

char *lsm_names;
static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;

Expand Down Expand Up @@ -158,6 +160,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
return;

lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
}

/* Prepare LSM for initialization. */
Expand Down Expand Up @@ -279,6 +282,15 @@ static void __init ordered_lsm_init(void)
prepare_lsm(*lsm);

init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
init_debug("file blob size = %d\n", blob_sizes.lbs_file);

/*
* Create any kmem_caches needed for blobs
*/
if (blob_sizes.lbs_file)
lsm_file_cache = kmem_cache_create("lsm_file_cache",
blob_sizes.lbs_file, 0,
SLAB_PANIC, NULL);

for (lsm = ordered_lsms; *lsm; lsm++)
initialize_lsm(*lsm);
Expand Down Expand Up @@ -448,6 +460,27 @@ void __init lsm_early_cred(struct cred *cred)
panic("%s: Early cred alloc failed.\n", __func__);
}

/**
* lsm_file_alloc - allocate a composite file blob
* @file: the file that needs a blob
*
* Allocate the file blob for all the modules
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
static int lsm_file_alloc(struct file *file)
{
if (!lsm_file_cache) {
file->f_security = NULL;
return 0;
}

file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
if (file->f_security == NULL)
return -ENOMEM;
return 0;
}

/*
* Hook list operation macros.
*
Expand Down Expand Up @@ -1144,12 +1177,27 @@ int security_file_permission(struct file *file, int mask)

int security_file_alloc(struct file *file)
{
return call_int_hook(file_alloc_security, 0, file);
int rc = lsm_file_alloc(file);

if (rc)
return rc;
rc = call_int_hook(file_alloc_security, 0, file);
if (unlikely(rc))
security_file_free(file);
return rc;
}

void security_file_free(struct file *file)
{
void *blob;

call_void_hook(file_free_security, file);

blob = file->f_security;
if (blob) {
file->f_security = NULL;
kmem_cache_free(lsm_file_cache, blob);
}
}

int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Expand Down Expand Up @@ -1267,7 +1315,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
return rc;

rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
if (rc)
if (unlikely(rc))
security_cred_free(cred);
return rc;
}
Expand All @@ -1288,7 +1336,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
return rc;

rc = call_int_hook(cred_prepare, 0, new, old, gfp);
if (rc)
if (unlikely(rc))
security_cred_free(new);
return rc;
}
Expand Down
25 changes: 2 additions & 23 deletions security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ static int __init checkreqprot_setup(char *str)
__setup("checkreqprot=", checkreqprot_setup);

static struct kmem_cache *sel_inode_cache;
static struct kmem_cache *file_security_cache;

/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
Expand Down Expand Up @@ -378,27 +377,15 @@ static void inode_free_security(struct inode *inode)

static int file_alloc_security(struct file *file)
{
struct file_security_struct *fsec;
struct file_security_struct *fsec = selinux_file(file);
u32 sid = current_sid();

fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
if (!fsec)
return -ENOMEM;

fsec->sid = sid;
fsec->fown_sid = sid;
file->f_security = fsec;

return 0;
}

static void file_free_security(struct file *file)
{
struct file_security_struct *fsec = selinux_file(file);
file->f_security = NULL;
kmem_cache_free(file_security_cache, fsec);
}

static int superblock_alloc_security(struct super_block *sb)
{
struct superblock_security_struct *sbsec;
Expand Down Expand Up @@ -3345,11 +3332,6 @@ static int selinux_file_alloc_security(struct file *file)
return file_alloc_security(file);
}

static void selinux_file_free_security(struct file *file)
{
file_free_security(file);
}

/*
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
Expand Down Expand Up @@ -6646,6 +6628,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)

struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
.lbs_cred = sizeof(struct task_security_struct),
.lbs_file = sizeof(struct file_security_struct),
};

static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
Expand Down Expand Up @@ -6717,7 +6700,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {

LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
Expand Down Expand Up @@ -6902,9 +6884,6 @@ static __init int selinux_init(void)
sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct),
0, SLAB_PANIC, NULL);
file_security_cache = kmem_cache_create("selinux_file_security",
sizeof(struct file_security_struct),
0, SLAB_PANIC, NULL);
avc_init();

avtab_cache_init();
Expand Down
2 changes: 1 addition & 1 deletion security/selinux/include/objsec.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred)

static inline struct file_security_struct *selinux_file(const struct file *file)
{
return file->f_security;
return file->f_security + selinux_blob_sizes.lbs_file;
}

#endif /* _SELINUX_OBJSEC_H_ */
3 changes: 2 additions & 1 deletion security/smack/smack.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ static inline struct task_smack *smack_cred(const struct cred *cred)

static inline struct smack_known **smack_file(const struct file *file)
{
return (struct smack_known **)&file->f_security;
return (struct smack_known **)(file->f_security +
smack_blob_sizes.lbs_file);
}

/*
Expand Down
14 changes: 1 addition & 13 deletions security/smack/smack_lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1495,18 +1495,6 @@ static int smack_file_alloc_security(struct file *file)
return 0;
}

/**
* smack_file_free_security - clear a file security blob
* @file: the object
*
* The security blob for a file is a pointer to the master
* label list, so no memory is freed.
*/
static void smack_file_free_security(struct file *file)
{
file->f_security = NULL;
}

/**
* smack_file_ioctl - Smack check on ioctls
* @file: the object
Expand Down Expand Up @@ -4559,6 +4547,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,

struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
.lbs_cred = sizeof(struct task_smack),
.lbs_file = sizeof(struct smack_known *),
};

static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
Expand Down Expand Up @@ -4595,7 +4584,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),

LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
LSM_HOOK_INIT(file_free_security, smack_file_free_security),
LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
LSM_HOOK_INIT(file_lock, smack_file_lock),
LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),
Expand Down

0 comments on commit 33bf60c

Please sign in to comment.