security/talpa/Kconfig | 15 ++++ security/talpa/Makefile | 1 + security/talpa/talpa_allow_calls.h | 6 ++ security/talpa/talpa_degraded.c | 116 +++++++++++++++++++++++++++++++ security/talpa/talpa_deny_calls.h | 7 ++ security/talpa/talpa_evaluation_calls.h | 7 ++ 6 files changed, 152 insertions(+), 0 deletions(-) diff --git a/security/talpa/Kconfig b/security/talpa/Kconfig index df9e3e6..43b2351 100644 --- a/security/talpa/Kconfig +++ b/security/talpa/Kconfig @@ -107,3 +107,18 @@ config TALPA_CLIENT receive vetting requests for filesystem operations. If you are unsure how to answer this question, answer Y. + + +config TALPA_DEGRADED + bool "Degraded mode safety" + depends on TALPA_CLIENT + default y + help + Degraded mode guards against deadlock scenarios with misbehaving + userspace vetting clients. When a vetting does not complete in + a configured amount of time a timeout event is raised. After a + number of timeouts exceeds a threshold super-user will be + allowed all filesystem operations bypassing the userspace + clients. + + If you are unsure how to answer this question, answer Y. diff --git a/security/talpa/Makefile b/security/talpa/Makefile index 941a57e..43ec67b 100644 --- a/security/talpa/Makefile +++ b/security/talpa/Makefile @@ -15,3 +15,4 @@ talpa-$(CONFIG_TALPA_THREAD_EXCLUSION) += talpa_thread_exclude.o talpa-$(CONFIG_TALPA_PATH_EXCLUDE) += talpa_path_exclude.o talpa-$(CONFIG_TALPA_PATH_INCLUDE) += talpa_path_include.o talpa-$(CONFIG_TALPA_CLIENT) += talpa_client.o +talpa-$(CONFIG_TALPA_DEGRADED) += talpa_degraded.o diff --git a/security/talpa/talpa_allow_calls.h b/security/talpa/talpa_allow_calls.h index 1f4b309..18e87aa 100644 --- a/security/talpa/talpa_allow_calls.h +++ b/security/talpa/talpa_allow_calls.h @@ -1,6 +1,8 @@ #include "talpa.h" #include "talpa_cache.h" +enum talpa_action talpa_degraded_allow(struct talpa_file_vetting *tfv); + static inline void talpa_allow_calls(struct talpa_file_vetting *tfv) { enum talpa_action ret; @@ -9,4 +11,8 @@ static inline void talpa_allow_calls(struct talpa_file_vetting *tfv) ret = talpa_cache_allow(tfv); #endif /* CONFIG_TALPA_CACHE */ +#ifdef CONFIG_TALPA_DEGRADED + ret = talpa_degraded_allow(tfv); +#endif /* CONFIG_TALPA_DEGRADED */ + } diff --git a/security/talpa/talpa_degraded.c b/security/talpa/talpa_degraded.c new file mode 100644 index 0000000..648678c --- /dev/null +++ b/security/talpa/talpa_degraded.c @@ -0,0 +1,116 @@ +/* + * 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 enabled; +static unsigned long threshold = 5; +static DEFINE_SPINLOCK(lock); +static unsigned long timeouts; +static unsigned long active; + + + +enum talpa_action talpa_degraded_examine(struct talpa_file_vetting *tfv) +{ + /* Allow accesses by super-user if degraded mode is active. */ + if (enabled && active && !current->uid) + return TALPA_ALLOW; + + return TALPA_NEXT; +} + +enum talpa_action talpa_degraded_allow(struct talpa_file_vetting *tfv) +{ + /* On successfull vetting turn off the degraded mode. */ + if (tfv->authoritative) { + spin_lock(&lock); + timeouts = 0; + active = 0; + spin_unlock(&lock); + } + + return TALPA_NEXT; +} + +enum talpa_action talpa_degraded_deny(struct talpa_file_vetting *tfv) +{ + /* Count the number of vetting timeouts and turn + on degraded mode if over threshold. */ + if (tfv->code == -ETIME) { + spin_lock(&lock); + timeouts++; + if (timeouts >= threshold) + active = 1; + spin_unlock(&lock); + } + + return TALPA_NEXT; +} + +static struct talpa_configuration talpa_degraded_cfg[] = { + { + .name = "enabled", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &enabled, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, + { + .name = "threshold", + .mode = S_IRUSR|S_IWUSR|S_IRGRP, + .data = &threshold, + .get = talpa_generic_get_ulong, + .set = talpa_generic_set_ulong, + }, + { + .name = "timeouts", + .mode = S_IRUSR|S_IRGRP, + .data = &timeouts, + .get = talpa_generic_get_ulong, + }, + { + .name = "active", + .mode = S_IRUSR|S_IRGRP, + .data = &active, + .get = talpa_generic_get_ulong, + }, + { + }, +}; + +static __init int talpa_degraded_init(void) +{ + int ret; + + ret = talpa_register_configuration("degraded_mode", talpa_degraded_cfg); + if (ret) + pr_err("talpa: Failed to register degraded mode configuration options!\n"); + + return ret; +} + +__initcall(talpa_degraded_init); diff --git a/security/talpa/talpa_deny_calls.h b/security/talpa/talpa_deny_calls.h index e3b404e..e1b7f6f 100644 --- a/security/talpa/talpa_deny_calls.h +++ b/security/talpa/talpa_deny_calls.h @@ -1,6 +1,8 @@ #include "talpa.h" #include "talpa_cache.h" +enum talpa_action talpa_degraded_deny(struct talpa_file_vetting *tfv); + static inline void talpa_deny_calls(struct talpa_file_vetting *tfv) { enum talpa_action ret; @@ -8,4 +10,9 @@ static inline void talpa_deny_calls(struct talpa_file_vetting *tfv) #ifdef CONFIG_TALPA_CACHE ret = talpa_cache_deny(tfv); #endif /* CONFIG_TALPA_CACHE */ + +#ifdef CONFIG_TALPA_DEGRADED + ret = talpa_degraded_deny(tfv); +#endif /* CONFIG_TALPA_DEGRADED */ + } diff --git a/security/talpa/talpa_evaluation_calls.h b/security/talpa/talpa_evaluation_calls.h index 3cacbe2..7dcbd1a 100644 --- a/security/talpa/talpa_evaluation_calls.h +++ b/security/talpa/talpa_evaluation_calls.h @@ -8,6 +8,7 @@ enum talpa_action talpa_fs_exclude_examine(struct talpa_file_vetting *tfv); enum talpa_action talpa_path_exclude_examine(struct talpa_file_vetting *tfv); enum talpa_action talpa_path_include_examine(struct talpa_file_vetting *tfv); enum talpa_action talpa_client_examine(struct talpa_file_vetting *tfv); +enum talpa_action talpa_degraded_examine(struct talpa_file_vetting *tfv); static inline int talpa_evaluation_calls(struct talpa_file_vetting *tfv) { @@ -56,6 +57,12 @@ static inline int talpa_evaluation_calls(struct talpa_file_vetting *tfv) return ret; #endif /* CONFIG_TALPA_PATH_EXCLUDE */ +#ifdef CONFIG_TALPA_DEGRADED + ret = talpa_degraded_examine(tfv); + if (ret != TALPA_NEXT) + return ret; +#endif /* CONFIG_TALPA_DEGRADED */ + #ifdef CONFIG_TALPA_CLIENT ret = talpa_client_examine(tfv); if (ret != TALPA_NEXT)