aboutsummaryrefslogtreecommitdiff
path: root/security/trustees/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/trustees/fs.c')
-rwxr-xr-xsecurity/trustees/fs.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/security/trustees/fs.c b/security/trustees/fs.c
new file mode 100755
index 00000000000..6463c64631a
--- /dev/null
+++ b/security/trustees/fs.c
@@ -0,0 +1,273 @@
+/*
+ * Trustees ACL Project
+ *
+ * Copyright (c) 1999-2000 Vyacheslav Zavadsky
+ * Copyright (c) 2004 Andrew Ruder (aeruder@ksu.edu)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ * This code handles the virtual filesystem for trustees.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/security.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "internal.h"
+
+
+/* initialization code for the trustees filesystem */
+
+/* File operations
+ *
+ * this is all the code for handling the file operations done on the few files
+ * in the trustees filesystem
+ */
+static int trustees_open(struct inode *inode, struct file *filp);
+static ssize_t trustees_read_bogus(struct file *filp, char __user * buf,
+ size_t count, loff_t * offset);
+static ssize_t trustees_write_bogus(struct file *filp,
+ const char __user * buf, size_t count,
+ loff_t * offset);
+static ssize_t trustees_read_status(struct file *filp, char __user * buf,
+ size_t count, loff_t * offset);
+static ssize_t trustees_read_apiversion(struct file *filp, char __user * buf,
+ size_t count, loff_t * offset);
+static ssize_t trustees_write_trustees(struct file *filp,
+ const char __user * buf,
+ size_t count, loff_t * offset);
+static int trustees_open_trustees(struct inode *inode, struct file *file);
+static int trustees_release_trustees(struct inode *inode, struct file *file);
+
+/* Various structs
+ */
+
+static struct file_operations trustees_ops_apiversion = {
+ .open = trustees_open,
+ .read = trustees_read_apiversion,
+ .write = trustees_write_bogus,
+};
+
+static struct file_operations trustees_ops_status = {
+ .open = trustees_open,
+ .read = trustees_read_status,
+ .write = trustees_write_bogus
+};
+
+static struct file_operations trustees_ops_trustees = {
+ .open = trustees_open_trustees,
+ .read = trustees_read_bogus,
+ .write = trustees_write_trustees,
+ .release = trustees_release_trustees
+};
+
+static struct trustees_file_info {
+ const char *name;
+ struct file_operations *fops;
+ int mode;
+ struct dentry *dentry;
+} trustees_files[] = {
+ {.name = "device",
+ .fops = &trustees_ops_trustees,
+ .mode = S_IWUSR,
+ .dentry = 0
+ },
+ {.name = "status",
+ .fops = &trustees_ops_status,
+ .mode = S_IRUSR,
+ .dentry = 0
+ },
+ {.name = "apiversion",
+ .fops = &trustees_ops_apiversion,
+ .mode = S_IRUSR | S_IRGRP | S_IROTH,
+ .dentry = 0
+ },
+ {"", NULL, 0, 0}
+};
+
+struct trustee_command_reader {
+ struct trustee_command command;
+ unsigned curarg;
+ void *arg[TRUSTEE_MAX_ARGS];
+ size_t argsize[TRUSTEE_MAX_ARGS];
+};
+
+
+static struct dentry *toplevel = NULL;
+
+int trustees_init_fs(void)
+{
+ struct trustees_file_info *iter;
+ toplevel = securityfs_create_dir("trustees", NULL);
+ if (!toplevel) trustees_deinit_fs();
+ for (iter = trustees_files; iter->fops && toplevel; iter++) {
+ iter->dentry = securityfs_create_file(
+ iter->name, iter->mode, toplevel, NULL, iter->fops);
+ if (!iter->dentry) trustees_deinit_fs();
+ }
+ return !toplevel;
+}
+
+void trustees_deinit_fs(void)
+{
+ struct trustees_file_info *iter;
+ for (iter = trustees_files; iter->fops; iter++) {
+ securityfs_remove(iter->dentry);
+ iter->dentry = NULL;
+ }
+ securityfs_remove(toplevel);
+ toplevel = NULL;
+}
+
+/*
+ * They're opening the file...
+ */
+
+static int trustees_open(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+static int trustees_open_trustees(struct inode *inode, struct file *file)
+{
+ file->private_data = vmalloc(sizeof(struct trustee_command_reader));
+ if (!file->private_data)
+ return -ENOMEM;
+
+ memset(file->private_data, 0, sizeof(struct trustee_command_reader));
+
+ return 0;
+}
+
+static int trustees_release_trustees(struct inode *inode, struct file *file)
+{
+ vfree(file->private_data);
+ return 0;
+}
+
+/* Do a read on a bogus file. Just return nothing :) */
+static ssize_t trustees_read_bogus(struct file *filp, char __user * buf,
+ size_t count, loff_t * offset)
+{
+ return 0;
+}
+
+/* Similar way to handle writes. Just say we wrote the data and return */
+static ssize_t trustees_write_bogus(struct file *filp,
+ const char __user * buf, size_t count,
+ loff_t * offset)
+{
+ return count;
+}
+
+/* Function for handling reading of the status. */
+static ssize_t trustees_read_status(struct file *filp, char __user * buf,
+ size_t count, loff_t * offset)
+{
+ static const char msg[] = "Damnit, it works, OK?!\n";
+ unsigned long nocopy;
+
+ if (*offset >= (sizeof(msg) - 1)) {
+ return 0;
+ }
+
+ if (count > (sizeof(msg) - 1 - *offset)) {
+ count = sizeof(msg) - 1 - *offset;
+ }
+ nocopy = copy_to_user(buf, msg, count);
+ (*offset) += count;
+ (*offset) -= nocopy;
+
+ return count;
+}
+
+/* Function for handling reading of the apiversion. */
+static ssize_t trustees_read_apiversion(struct file *filp, char __user * buf,
+ size_t count, loff_t * offset)
+{
+ static const char msg[] = TRUSTEES_APIVERSION_STR "\n";
+ unsigned long nocopy;
+
+ if (*offset >= (sizeof(msg) - 1)) {
+ return 0;
+ }
+
+ if (count > (sizeof(msg) - 1 - *offset)) {
+ count = sizeof(msg) - 1 - *offset;
+ }
+ nocopy = copy_to_user(buf, msg, count);
+ (*offset) += count;
+ (*offset) -= nocopy;
+
+ return count;
+}
+
+/* Cleanup our reader (deallocate all the allocated memory) */
+static void cleanup_reader(struct trustee_command_reader *reader) {
+ int z;
+ if (!reader) {
+ TS_ERR_MSG("How does reader disappear on us?\n");
+ return;
+ }
+
+ for (z = reader->curarg - 1; z >= 0; z--) {
+ vfree(reader->arg[z]);
+ reader->argsize[z] = 0;
+ }
+ reader->command.command = 0;
+ reader->curarg = 0;
+}
+
+static ssize_t trustees_write_trustees(struct file *filp,
+ const char __user * buf,
+ size_t count, loff_t * offset)
+{
+ struct trustee_command_reader *reader = filp->private_data;
+
+ if (reader->command.command == 0) {
+ reader->curarg = 0;
+ if (count != sizeof(struct trustee_command)) {
+ return -EIO;
+ }
+ if (copy_from_user(&reader->command, buf, count)) {
+ reader->command.command = 0;
+ TS_ERR_MSG("copy_from_user failed on command\n");
+ return -EIO;
+ }
+ if (reader->command.numargs > TRUSTEE_MAX_ARGS) {
+ TS_ERR_MSG("Too many arguments specified for command %d\n",
+ reader->command.command);
+ return -EIO;
+ }
+ } else {
+ unsigned curarg = reader->curarg;
+ if (!(reader->arg[curarg] = vmalloc(count+1))) {
+ cleanup_reader(reader);
+ return -EIO;
+ }
+ reader->argsize[curarg] = count;
+ ((char *)reader->arg[curarg])[count] = '\0';
+ reader->curarg++;
+ if (copy_from_user(reader->arg[curarg], buf, count)) {
+ cleanup_reader(reader);
+ TS_ERR_MSG("copy_from_user failed on arg\n");
+ return -EIO;
+ }
+ }
+
+ if (reader->command.command && reader->curarg == reader->command.numargs) {
+ int ret = trustees_process_command(reader->command, reader->arg,
+ reader->argsize);
+ cleanup_reader(reader);
+ if (ret) return -EIO;
+ }
+
+ return count;
+}