Commit f7ea6504 authored by Lukas Braun's avatar Lukas Braun Committed by Simon Ruderich
Browse files

slsm: passtfs: allow concurrent open(2)s

Also fixes race conditions with concurrent writes.
parent 51fc8293
......@@ -9,10 +9,12 @@
#include "tree.h"
DEFINE_SEMAPHORE(fs_open);
static char *rules;
static size_t rules_length;
struct passtfs_privdata {
struct mutex mutex;
char *buf;
size_t size;
unsigned dirty:1;
};
struct securityfs_files {
struct dentry *dir;
......@@ -21,87 +23,98 @@ struct securityfs_files {
static struct securityfs_files fs_files;
/**
* profiles_open - called when profiles file is opend
* checks if profiles is already open and frees eventually allocated buffer
* rules.
*
* @inode: inode of opened file
* @file: file structure of opend file
*
* Returns: 0 on success or -EBUSY if file is already open
*/
int profiles_open(struct inode *inode, struct file *file)
{
if (down_trylock(&fs_open))
return -EBUSY;
struct passtfs_privdata *pd = kzalloc(sizeof(*pd), GFP_KERNEL);
if (!pd)
return -ENOMEM;
mutex_init(&pd->mutex);
file->private_data = pd;
return 0;
}
/**
* profiles_write - called when new rules are written to the profiles files.
*
* @f: file struct (unused)
* @buf: userland buffer with new rules
* @size: length of buf
* @pos: position in file
*
* Returns: written characters or error on failure
*/
static ssize_t profiles_write(struct file *f, const char __user *buf, size_t size,
loff_t *pos)
{
char *temp;
size_t new_length;
char *buf_new;
size_t size_new;
ssize_t ret;
struct passtfs_privdata *pd = f->private_data;
if (size > (ssize_t)size)
return -EFBIG;
new_length = size + rules_length;
mutex_lock(&pd->mutex);
temp = krealloc(rules, new_length, GFP_KERNEL);
if (!temp) {
return -ENOMEM;
size_new = pd->size + size;
buf_new = krealloc(pd->buf, size_new, GFP_KERNEL);
if (!buf_new) {
ret = -ENOMEM;
goto out;
}
rules = temp;
pd->buf = buf_new;
if (copy_from_user(rules + rules_length, buf, size)) {
return -EFAULT;
if (copy_from_user(buf_new + pd->size, buf, size)) {
/* reference to realloced buffer in pd->buf is ok, as long as
* pd->size isn't updated */
ret = -EFAULT;
goto out;
}
rules_length = new_length;
pd->size = size_new;
pd->dirty = 1;
ret = (ssize_t)size;
out:
mutex_unlock(&pd->mutex);
return (ssize_t)size;
return ret;
}
/** profiles_release - called when profiles file is closed
* resets device_open flag.i and kicks off the tree build
*
* @inode:
* @file:
/** profiles_flush - called during close(2)
*
* Returns: 0 on succes or error when tree build fails
* Return value is returned by close(2)
*/
int profiles_release(struct inode *inode, struct file *file)
int profiles_flush(struct file *file, fl_owner_t id)
{
int ret;
struct passtfs_privdata *pd = file->private_data;
int ret = 0;
/* Build new tree */
ret = slsm_new_tree(rules, rules_length);
mutex_lock(&pd->mutex);
if (pd->dirty) {
ret = slsm_new_tree(pd->buf, pd->size);
pd->dirty = 0;
}
mutex_unlock(&pd->mutex);
kfree(rules);
rules = NULL;
rules_length = 0;
return ret;
}
up(&fs_open);
return ret;
/** profiles_release - called when the last reference to @file is closed
*
* Return value is ignored.
*/
int profiles_release(struct inode *inode, struct file *file)
{
struct passtfs_privdata *pd = file->private_data;
BUG_ON(!pd);
profiles_flush(file, 0);
kfree(pd->buf);
mutex_destroy(&pd->mutex);
kfree(pd);
file->private_data = NULL;
return 0;
}
static const struct file_operations fs_fops_profiles = {
.owner = THIS_MODULE,
.open = profiles_open,
.write = profiles_write,
.flush = profiles_flush,
.release = profiles_release,
};
......
Supports Markdown
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