security/talpa/Kconfig | 16 +++ security/talpa/Makefile | 1 + security/talpa/talpa_evaluation_calls.h | 8 ++ security/talpa/talpa_operation_exclude.c | 151 ++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 0 deletions(-) diff --git a/security/talpa/Kconfig b/security/talpa/Kconfig index 7910cc1..c3c8dfe 100644 --- a/security/talpa/Kconfig +++ b/security/talpa/Kconfig @@ -20,3 +20,19 @@ config TALPA_CACHE By default all block device backed filesystems are cached. If you are unsure how to answer this question, answer Y. + + +config TALPA_OPERATION_EXCLUSION + bool "Operation and type exclusions" + depends on TALPA + default y + help + It is generally not useful to intercept filesystem operations + which cannot be used as a vector for malicious entry. This + Talpa filter makes sure those operations are ignored which + provides a performance optimisation and no security risk. + + It is also sometimes useful to ignore access to some classes + of filesystem objects, like directories or sockets. + + If you are unsure how to answer this question, answer Y. diff --git a/security/talpa/Makefile b/security/talpa/Makefile index 8da21b9..4aba14f 100644 --- a/security/talpa/Makefile +++ b/security/talpa/Makefile @@ -9,3 +9,4 @@ talpa-y := talpa_interceptor.o \ talpa_configuration.o talpa-$(CONFIG_TALPA_CACHE) += talpa_cache.o +talpa-$(CONFIG_TALPA_OPERATION_EXCLUSION) += talpa_operation_exclude.o diff --git a/security/talpa/talpa_evaluation_calls.h b/security/talpa/talpa_evaluation_calls.h index 24d0955..2b635a1 100644 --- a/security/talpa/talpa_evaluation_calls.h +++ b/security/talpa/talpa_evaluation_calls.h @@ -3,6 +3,8 @@ #include "talpa.h" #include "talpa_cache.h" +enum talpa_action talpa_opexcl_examine(struct talpa_file_vetting *tfv); + static inline int talpa_evaluation_calls(struct talpa_file_vetting *tfv) { enum talpa_action ret = TALPA_NEXT; @@ -26,5 +28,11 @@ static inline int talpa_evaluation_calls(struct talpa_file_vetting *tfv) return ret; #endif /* CONFIG_TALPA_CACHE */ +#ifdef CONFIG_TALPA_OPERATION_EXCLUSION + ret = talpa_opexcl_examine(tfv); + if (ret != TALPA_NEXT) + return ret; +#endif /* CONFIG_TALPA_OPERATION_EXCLUSION */ + return ret; } diff --git a/security/talpa/talpa_operation_exclude.c b/security/talpa/talpa_operation_exclude.c new file mode 100644 index 0000000..36f96aa --- /dev/null +++ b/security/talpa/talpa_operation_exclude.c @@ -0,0 +1,151 @@ +/* + * Copyright 2008 Sophos Plc + * + * 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; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "talpa.h" + + +static unsigned long talpa_excl_enbl = 1; +static unsigned long talpa_excl_files = 1; +static unsigned long talpa_excl_dirs = 1; +static unsigned long talpa_excl_symlinks = 1; +static unsigned long talpa_excl_fifos = 1; +static unsigned long talpa_excl_sockets = 1; +static unsigned long talpa_excl_chrdevs = 1; +static unsigned long talpa_excl_blkdevs = 1; + +enum talpa_action talpa_opexcl_examine(struct talpa_file_vetting *tfv) +{ + unsigned long mode = tfv->file->f_dentry->d_inode->i_mode; + + if (!talpa_excl_enbl) + return TALPA_NEXT; + + /* don't make the common case go through 7 || */ + if (S_ISREG(mode) && !talpa_excl_files) + return TALPA_NEXT; + + if ((S_ISLNK(mode) && talpa_excl_symlinks) + || (S_ISFIFO(mode) && talpa_excl_fifos) + || (S_ISSOCK(mode) && talpa_excl_sockets) + || (S_ISBLK(mode) && talpa_excl_blkdevs) + || (S_ISCHR(mode) && talpa_excl_chrdevs) + || (S_ISDIR(mode) && talpa_excl_dirs) + || (S_ISREG(mode) && talpa_excl_files)) { + /* FIXME if we cache these results we need to invalidate the + * cache on talpa_excl_* changes.... */ + tfv->authoritative = 1; + return TALPA_ALLOW; + } + + switch (tfv->operation) { + case TALPA_OPEN: + /* Allow if file was truncated on open, is write only + or is open for exclusive creation. */ + if (tfv->flags&(O_WRONLY|O_TRUNC) || + (tfv->flags&(O_CREAT|O_EXCL)) == ((O_CREAT|O_EXCL))) + return TALPA_ALLOW; + break; + case TALPA_CLOSE: + /* Allow if we are closing a read-only file. */ + if (!(tfv->flags&(O_WRONLY|O_RDWR|O_APPEND|O_CREAT|O_TRUNC))) + return TALPA_ALLOW; + break; + } + + return TALPA_NEXT; +} + +static struct talpa_configuration talpa_opexcl_cfg[] = { + { + .name = "enabled", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_enbl, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, + { + .name = "files", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_files, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, + { + .name = "symlinks", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_symlinks, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, + { + .name = "dirs", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_dirs, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, +{ + .name = "sockets", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_sockets, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, +{ + .name = "fifos", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_fifos, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, +{ + .name = "chrdevs", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_chrdevs, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, +{ + .name = "blkdevs", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &talpa_excl_blkdevs, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, + { + }, +}; + +static __init int talpa_opexcl_init(void) +{ + int ret; + + ret = talpa_register_configuration("operation_exclusion", talpa_opexcl_cfg); + if (ret) + pr_err("talpa: Failed to register operation exclusion configuration!\n"); + + return ret; +} +__initcall(talpa_opexcl_init);