--- security/Makefile | 2 security/foobar/Makefile | 1 security/foobar/foobar.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) --- a/security/Makefile +++ b/security/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_SECURITY) += security.o d obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o + +subdir-$(CONFIG_SECURITY) += foobar --- /dev/null +++ b/security/foobar/Makefile @@ -0,0 +1 @@ +obj-m += foobar.o --- /dev/null +++ b/security/foobar/foobar.c @@ -0,0 +1,257 @@ +#include +#include +#include + +#define log_path(dentry, mnt, fmt...) \ + __log_path(__FUNCTION__, dentry, mnt, NULL, ##fmt) + +#define log_path_inode(inode, fmt...) \ + __log_path(__FUNCTION__, NULL, NULL, inode, ##fmt) + +static int show_traversals; +module_param(show_traversals, bool, 0644); + +static void __log_path(const char *op, struct dentry *dentry, + struct vfsmount *mnt, struct inode *inode, + char *fmt, ...) +{ + va_list ap; + char *page = NULL, *name = ""; + + page = (char *)__get_free_page(GFP_KERNEL); + if (!page) + name = ""; + else if (mnt) { + name = d_path(dentry, mnt, page + 1, PAGE_SIZE - 2); + if (IS_ERR(name)) { + snprintf(page, PAGE_SIZE, "<%ld>", PTR_ERR(name)); + name = page; + } else { + page[PAGE_SIZE - 2] = '"'; + page[PAGE_SIZE - 1] = '\0'; + *--name = '"'; + } + } else if (dentry) { + snprintf(page, PAGE_SIZE, "<%s>", dentry->d_name.name); + name = page; + } else if (inode) { + snprintf(page, PAGE_SIZE, "<%s:%ld>", + inode->i_sb->s_type->name, + inode->i_ino); + name = page; + } + + if (fmt) { + char *buffer = (char *)__get_free_page(GFP_KERNEL); + + if (buffer) { + int n; + + n = snprintf(buffer, PAGE_SIZE, KERN_INFO "%s(%s, ", + op, name); + va_start(ap, fmt); + n += vsnprintf(buffer + n, PAGE_SIZE - n, fmt, ap); + va_end(ap); + snprintf(buffer + n, PAGE_SIZE - n, ")\n"); + printk("%s", buffer); + + free_page((unsigned long)buffer); + } else + printk("%s: Out of memory\n", __FUNCTION__); + } else + printk(KERN_INFO "%s(%s)\n", op, name); + + free_page((unsigned long)page); +} + +static int foobar_inode_mkdir(struct inode *inode, struct dentry *dentry, + struct vfsmount *mnt, int mask) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_rmdir(struct inode *inode, struct dentry *dentry, + struct vfsmount *mnt) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_create(struct inode *inode, struct dentry *dentry, + struct vfsmount *mnt, int mask) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_link(struct dentry *old_dentry, + struct vfsmount *old_mnt, + struct inode *inode, + struct dentry *new_dentry, + struct vfsmount *new_mnt) +{ + log_path(old_dentry, old_mnt, ""); + log_path(new_dentry, new_mnt, ""); + + return 0; +} + +static int foobar_inode_unlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_mknod(struct inode *inode, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_rename(struct inode *old_inode, + struct dentry *old_dentry, + struct vfsmount *old_mnt, + struct inode *new_inode, + struct dentry *new_dentry, + struct vfsmount *new_mnt) +{ + log_path(old_dentry, old_mnt, ""); + log_path(new_dentry, new_mnt, ""); + + return 0; +} + +static int foobar_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *iattr) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + char *name, void *value, size_t size, + int flags, struct file *file) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_getxattr(struct dentry *dentry, + struct vfsmount *mnt, char *name, struct file *file) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_listxattr(struct dentry *dentry, + struct vfsmount *mnt, struct file *file) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_removexattr(struct dentry *dentry, + struct vfsmount *mnt, char *name, struct file *file) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_symlink(struct inode *dir, + struct dentry *dentry, struct vfsmount *mnt, + const char *old_name) +{ + log_path(dentry, mnt, NULL); + + return 0; +} + +static int foobar_inode_permission(struct inode *inode, int mask, + struct nameidata *nd) +{ + if (nd && (nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE)) && + !show_traversals) + return 0; + + if (nd) { + char *parent = "", *sep="", *cont = ""; + + if (nd->flags & LOOKUP_PARENT) + parent = "LOOKUP_PARENT"; + if (nd->flags & LOOKUP_CONTINUE) + cont = "LOOKUP_CONTINUE"; + if ((nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE)) == + (LOOKUP_PARENT | LOOKUP_CONTINUE)) + sep = ", "; + else if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))) + sep = "0"; + + log_path(nd->dentry, nd->mnt, "%c%c%c%c, %s%s%s", + mask & MAY_READ ? 'r' : '-', + mask & MAY_WRITE ? 'w' : '-', + mask & MAY_EXEC ? 'x' : '-', + mask & MAY_APPEND ? 'a' : '-', + parent, sep, cont); + } else { + log_path_inode(inode, "%c%c%c%c, 0", + mask & MAY_READ ? 'r' : '-', + mask & MAY_WRITE ? 'w' : '-', + mask & MAY_EXEC ? 'x' : '-', + mask & MAY_APPEND ? 'a' : '-'); + } + + return 0; +} + +struct security_operations foobar_ops = { + .inode_create = foobar_inode_create, + .inode_link = foobar_inode_link, + .inode_unlink = foobar_inode_unlink, + .inode_mkdir = foobar_inode_mkdir, + .inode_rmdir = foobar_inode_rmdir, + .inode_mknod = foobar_inode_mknod, + .inode_rename = foobar_inode_rename, + .inode_setattr = foobar_inode_setattr, + .inode_setxattr = foobar_inode_setxattr, + .inode_getxattr = foobar_inode_getxattr, + .inode_listxattr = foobar_inode_listxattr, + .inode_removexattr = foobar_inode_removexattr, + .inode_symlink = foobar_inode_symlink, + .inode_permission = foobar_inode_permission, +}; + +static int __init foobar_init(void) +{ + int error; + + error = register_security(&foobar_ops); + if (error) + printk(KERN_ERR "Unable to load foobar lsm\n"); + + return error; +} + +static void __exit foobar_exit(void) +{ + if (unregister_security(&foobar_ops)) + printk(KERN_ERR "Unable to properly unregister foobar lsm\n"); +} + +module_init(foobar_init); +module_exit(foobar_exit); + +MODULE_DESCRIPTION("lsm module logging to syslog"); +MODULE_LICENSE("GPL");