*/
struct lsm_blob_sizes {
int lbs_cred;
+ int lbs_file;
};
/*
return aa_get_newest_label(aa_cred_raw_label(cred));
}
+static inline struct aa_file_ctx *apparmor_file(const struct file *file)
+{
+ return file->f_security;
+}
+
/**
* __aa_task_raw_label - retrieve another task's label
* @task: task to query (NOT NULL)
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)
+#define file_ctx(X) apparmor_file(X)
/* struct aa_file_ctx - the AppArmor context the file was opened in
* @lock: lock to update the ctx
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)
struct lsm_blob_sizes apparmor_blob_sizes = {
.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 = {
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;
*/
do_security_initcalls();
+ /*
+ * 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);
/*
* The second call to a module specific init function
* adds hooks to the hook lists and does any other early
#ifdef CONFIG_SECURITY_LSM_DEBUG
pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
+ pr_info("LSM: file blob size = %d\n", blob_sizes.lbs_file);
#endif
return 0;
void __init security_add_blobs(struct lsm_blob_sizes *needed)
{
lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+}
+
+/**
+ * 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.
+ */
+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;
}
/*
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;
+
+ if (!lsm_file_cache)
+ return;
+
call_void_hook(file_free_security, file);
+
+ blob = file->f_security;
+ file->f_security = NULL;
+ kmem_cache_free(lsm_file_cache, blob);
}
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return rc;
rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
- if (rc)
+ if (unlikely(rc))
security_cred_free(cred);
return rc;
}
return rc;
rc = call_int_hook(cred_prepare, 0, new, old, gfp);
- if (rc)
+ if (unlikely(rc))
security_cred_free(new);
return rc;
}
#endif
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
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 = file->f_security;
- 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;
struct file *file,
u32 av)
{
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct inode *inode = file_inode(file);
struct common_audit_data ad;
u32 sid = cred_sid(cred);
struct file *file)
{
u32 sid = task_sid(to);
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct dentry *dentry = file->f_path.dentry;
struct inode_security_struct *isec;
struct common_audit_data ad;
static int selinux_file_permission(struct file *file, int mask)
{
struct inode *inode = file_inode(file);
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct inode_security_struct *isec;
u32 sid = current_sid();
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.
u32 requested, u16 cmd)
{
struct common_audit_data ad;
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct inode *inode = file_inode(file);
struct inode_security_struct *isec;
struct lsm_ioctlop_audit ioctl;
{
struct file_security_struct *fsec;
- fsec = file->f_security;
+ fsec = selinux_file(file);
fsec->fown_sid = current_sid();
}
/* struct fown_struct is never outside the context of a struct file */
file = container_of(fown, struct file, f_owner);
- fsec = file->f_security;
+ fsec = selinux_file(file);
if (!signum)
perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
struct file_security_struct *fsec;
struct inode_security_struct *isec;
- fsec = file->f_security;
+ fsec = selinux_file(file);
isec = inode_security(file_inode(file));
/*
* Save inode label and policy sequence number
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
- fsec = file->f_security;
+ fsec = selinux_file(file);
if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
if (rc)
struct lsm_blob_sizes selinux_blob_sizes = {
.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 = {
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),
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();
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
return cred->security;
}
+static inline struct file_security_struct *selinux_file(const struct file *file)
+{
+ return file->f_security;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
return cred->security;
}
+static inline struct smack_known **smack_file(const struct file *file)
+{
+ return file->f_security;
+}
+
/*
* Is the directory transmuting?
*/
*/
static int smack_file_alloc_security(struct file *file)
{
- struct smack_known *skp = smk_of_current();
+ struct smack_known **blob = smack_file(file);
- file->f_security = skp;
+ *blob = smk_of_current();
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
*/
static void smack_file_set_fowner(struct file *file)
{
- file->f_security = smk_of_current();
+ struct smack_known **blob = smack_file(file);
+
+ *blob = smk_of_current();
}
/**
static int smack_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
+ struct smack_known **blob;
struct smack_known *skp;
struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred));
struct file *file;
file = container_of(fown, struct file, f_owner);
/* we don't log here as rc can be overriden */
- skp = file->f_security;
+ blob = smack_file(file);
+ skp = *blob;
rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
struct lsm_blob_sizes smack_blob_sizes = {
.lbs_cred = sizeof(struct task_smack),
+ .lbs_file = sizeof(struct smack_known *),
};
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),