diff --git a/0001-AltHa-LSM-module.patch b/0001-AltHa-LSM-module.patch new file mode 100644 index 0000000..024ad6b --- /dev/null +++ b/0001-AltHa-LSM-module.patch @@ -0,0 +1,431 @@ +From f690c6792f5ca5737627ebf800086d7408f17456 Mon Sep 17 00:00:00 2001 +From: Kernel Bot +Date: Wed, 21 Aug 2019 16:11:26 +0300 +Subject: [PATCH 1/2] AltHa LSM module + + * ignore SUID on binaries (with exceptions possible); + * prevent running selected script interprers in interactive move; + * disable open file unlinking in selected dirs; + +Changelog: + * ported to 5.2 as ordered LSM + * introduced OLock + * no more WxorX + * error handling, path_puts and locking added + * lists handling rewritten + * indentation fixed + +Rediffed for vanilla kernel 5.4.25 +Signed-off-by: Mikhail Novosyolov +--- + security/Kconfig | 3 +- + security/Makefile | 2 + + security/altha/Kconfig | 11 ++ + security/altha/Makefile | 3 + + security/altha/altha_lsm.c | 325 +++++++++++++++++++++++++++++++++++++ + 5 files changed, 343 insertions(+), 1 deletion(-) + create mode 100644 security/altha/Kconfig + create mode 100644 security/altha/Makefile + create mode 100644 security/altha/altha_lsm.c + +diff --git a/security/Kconfig b/security/Kconfig +index 2a1a2d396228..d21a120b66d4 100644 +--- a/security/Kconfig ++++ b/security/Kconfig +@@ -238,6 +238,7 @@ source "security/loadpin/Kconfig" + source "security/yama/Kconfig" + source "security/safesetid/Kconfig" + source "security/lockdown/Kconfig" ++source "security/altha/Kconfig" + + source "security/integrity/Kconfig" + +@@ -281,7 +282,7 @@ config LSM + default "lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR + default "lockdown,yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO + default "lockdown,yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC +- default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" ++ default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,altha" + help + A comma-separated list of LSMs, in initialization order. + Any LSMs left off this list will be ignored. This can be +diff --git a/security/Makefile b/security/Makefile +index be1dd9d2cb2f..7c9628c2017e 100644 +--- a/security/Makefile ++++ b/security/Makefile +@@ -12,6 +12,7 @@ subdir-$(CONFIG_SECURITY_YAMA) += yama + subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin + subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid + subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown ++subdir-$(CONFIG_SECURITY_ALTHA) += altha + + # always enable default capabilities + obj-y += commoncap.o +@@ -29,6 +30,7 @@ obj-$(CONFIG_SECURITY_YAMA) += yama/ + obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ + obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ + obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/ ++obj-$(CONFIG_SECURITY_ALTHA) += altha/ + obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o + + # Object integrity file lists +diff --git a/security/altha/Kconfig b/security/altha/Kconfig +new file mode 100644 +index 000000000000..4bafdef4e58e +--- /dev/null ++++ b/security/altha/Kconfig +@@ -0,0 +1,11 @@ ++config SECURITY_ALTHA ++ bool "AltHa security module" ++ depends on SECURITY ++ default n ++ help ++ Some hardening options: ++ * ignore SUID on binaries (with exceptions possible); ++ * prevent running selected script interprers in interactive move; ++ * WxorX for filesystems (with exceptions possible); ++ ++ If you are unsure how to answer this question, answer N. +diff --git a/security/altha/Makefile b/security/altha/Makefile +new file mode 100644 +index 000000000000..56735b157567 +--- /dev/null ++++ b/security/altha/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_SECURITY_ALTHA) := altha.o ++ ++altha-y := altha_lsm.o +diff --git a/security/altha/altha_lsm.c b/security/altha/altha_lsm.c +new file mode 100644 +index 000000000000..7d1cc8f8a1a7 +--- /dev/null ++++ b/security/altha/altha_lsm.c +@@ -0,0 +1,325 @@ ++/* ++ * AltHa Linux Security Module ++ * ++ * Author: Anton Boyarshinov ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2, as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ALTHA_PARAMS_SIZE 4096 ++char proc_nosuid_exceptions[ALTHA_PARAMS_SIZE]; ++char proc_interpreters[ALTHA_PARAMS_SIZE]; ++char proc_olock_dirs[ALTHA_PARAMS_SIZE]; ++ ++/* Boot time disable flag */ ++static bool altha_enabled = 0; ++ ++/* sysctl flags */ ++static int nosuid_enabled; ++static int rstrscript_enabled; ++static int olock_enabled; ++ ++/* Boot parameter handing */ ++module_param_named(enabled, altha_enabled, bool, S_IRUGO); ++ ++static int __init altha_enabled_setup(char *str) ++{ ++ unsigned long enabled; ++ int error = kstrtoul(str, 0, &enabled); ++ if (!error) ++ altha_enabled = enabled ? 1 : 0; ++ return 1; ++} ++ ++__setup("altha=", altha_enabled_setup); ++ ++struct altha_list_struct { ++ struct path path; ++ struct list_head list; ++}; ++ ++/* Lists handling */ ++DECLARE_RWSEM(nosuid_exceptions_sem); ++DECLARE_RWSEM(interpreters_sem); ++DECLARE_RWSEM(olock_dirs_sem); ++LIST_HEAD(nosuid_exceptions_list); ++LIST_HEAD(interpreters_list); ++LIST_HEAD(olock_dirs_list); ++ ++static int altha_list_handler(struct ctl_table *table, int write, ++ void __user * buffer, size_t * lenp, ++ loff_t * ppos) ++{ ++ struct altha_list_struct *item, *tmp; ++ struct list_head *list_struct; ++ char *p, *fluid; ++ char *copy_buffer; ++ struct rw_semaphore *sem = table->extra2; ++ unsigned long error = proc_dostring(table, write, buffer, lenp, ppos); ++ down_write(sem); ++ if (error) ++ goto out; ++ ++ if (write && !error) { ++ copy_buffer = kmalloc(ALTHA_PARAMS_SIZE, GFP_KERNEL); ++ if (!copy_buffer) { ++ pr_err ++ ("AltHa: can't get memory for copy_buffer processing sysctl\n"); ++ error = -1; ++ goto out; ++ } ++ ++ list_struct = (struct list_head *)(table->extra1); ++ /*empty list and that fill with new info */ ++ list_for_each_entry_safe(item, tmp, list_struct, list) { ++ list_del(&item->list); ++ path_put(&item->path); ++ kfree(item); ++ } ++ ++ strlcpy(copy_buffer, table->data, ALTHA_PARAMS_SIZE); ++ ++ /* buffer can have a garbage after \n */ ++ p = strchrnul(copy_buffer, '\n'); ++ *p = 0; ++ ++ /* for strsep usage */ ++ fluid = copy_buffer; ++ ++ while ((p = strsep(&fluid, ":\n")) != NULL) { ++ if (strlen(p)) { ++ item = kmalloc(sizeof(*item), GFP_KERNEL); ++ if (!item) { ++ pr_err ++ ("AltHa: can't get memory processing sysctl\n"); ++ kfree(copy_buffer); ++ error = -1; ++ goto out; ++ } ++ if (kern_path(p, LOOKUP_FOLLOW, &item->path)) { ++ pr_info ++ ("AltHa: error lookup '%s'\n", p); ++ kfree(item); ++ } else { ++ list_add_tail(&item->list, list_struct); ++ } ++ } ++ } ++ kfree(copy_buffer); ++ } ++out: ++ up_write(sem); ++ return error; ++} ++ ++struct ctl_path nosuid_sysctl_path[] = { ++ {.procname = "kernel",}, ++ {.procname = "altha",}, ++ {.procname = "nosuid",}, ++ {} ++}; ++ ++static struct ctl_table nosuid_sysctl_table[] = { ++ { ++ .procname = "enabled", ++ .data = &nosuid_enabled, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec_minmax, ++ }, ++ { ++ .procname = "exceptions", ++ .data = proc_nosuid_exceptions, ++ .maxlen = ALTHA_PARAMS_SIZE, ++ .mode = 0644, ++ .proc_handler = altha_list_handler, ++ .extra1 = &nosuid_exceptions_list, ++ .extra2 = &nosuid_exceptions_sem, ++ }, ++ {} ++}; ++ ++struct ctl_path rstrscript_sysctl_path[] = { ++ {.procname = "kernel",}, ++ {.procname = "altha",}, ++ {.procname = "rstrscript",}, ++ {} ++}; ++ ++static struct ctl_table rstrscript_sysctl_table[] = { ++ { ++ .procname = "enabled", ++ .data = &rstrscript_enabled, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec_minmax, ++ }, ++ { ++ .procname = "interpreters", ++ .data = proc_interpreters, ++ .maxlen = ALTHA_PARAMS_SIZE, ++ .mode = 0644, ++ .proc_handler = altha_list_handler, ++ .extra1 = &interpreters_list, ++ .extra2 = &interpreters_sem, ++ }, ++ {} ++}; ++ ++struct ctl_path olock_sysctl_path[] = { ++ {.procname = "kernel",}, ++ {.procname = "altha",}, ++ {.procname = "olock",}, ++ {} ++}; ++ ++static struct ctl_table olock_sysctl_table[] = { ++ { ++ .procname = "enabled", ++ .data = &olock_enabled, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec_minmax, ++ }, ++ { ++ .procname = "dirs", ++ .data = proc_olock_dirs, ++ .maxlen = ALTHA_PARAMS_SIZE, ++ .mode = 0644, ++ .proc_handler = altha_list_handler, ++ .extra1 = &olock_dirs_list, ++ .extra2 = &olock_dirs_sem, ++ }, ++ {} ++}; ++ ++struct altha_readdir_callback { ++ struct dir_context ctx; ++ u64 inode; ++ int found; ++}; ++ ++ ++int is_olock_dir(struct inode *inode) ++{ ++ struct altha_list_struct *node; ++ down_read(&olock_dirs_sem); ++ list_for_each_entry(node, &olock_dirs_list, list) { ++ struct inode *exc_inode = node->path.dentry->d_inode; ++ if (exc_inode == inode) { ++ up_read(&olock_dirs_sem); ++ return 1; ++ } ++ } ++ up_read(&olock_dirs_sem); ++ return 0; ++} ++ ++/* Hooks */ ++static int altha_bprm_set_creds(struct linux_binprm *bprm) ++{ ++ struct altha_list_struct *node; ++ /* when it's not a shebang issued script interpreter */ ++ if (rstrscript_enabled && !bprm->called_set_creds) { ++ down_read(&interpreters_sem); ++ list_for_each_entry(node, &interpreters_list, list) { ++ if (path_equal(&bprm->file->f_path, &node->path)) { ++ uid_t cur_uid = from_kuid(bprm->cred->user_ns, ++ bprm->cred->uid); ++ pr_notice_ratelimited ++ ("AltHa/RestrScript: %s is blocked to run directly by %d\n", ++ bprm->filename, cur_uid); ++ up_read(&interpreters_sem); ++ return -EPERM; ++ } ++ } ++ up_read(&interpreters_sem); ++ } ++ if (unlikely(nosuid_enabled && ++ !uid_eq(bprm->cred->uid, bprm->cred->euid))) { ++ uid_t cur_uid = from_kuid(bprm->cred->user_ns, bprm->cred->uid); ++ down_read(&nosuid_exceptions_sem); ++ list_for_each_entry(node, &nosuid_exceptions_list, list) { ++ if (path_equal(&bprm->file->f_path, &node->path)) { ++ pr_notice_ratelimited ++ ("AltHa/NoSUID: %s permitted to setuid from %d\n", ++ bprm->filename, cur_uid); ++ up_read(&nosuid_exceptions_sem); ++ return 0; ++ } ++ } ++ up_read(&nosuid_exceptions_sem); ++ pr_notice_ratelimited ++ ("AltHa/NoSUID: %s prevented to setuid from %d\n", ++ bprm->filename, cur_uid); ++ bprm->cred->euid = bprm->cred->uid; ++ } ++ return 0; ++} ++ ++/* For OLock */ ++static int altha_inode_unlink(struct inode *inode, struct dentry *dentry) ++{ ++ if (olock_enabled && (atomic_read(&dentry->d_inode->i_writecount) ++#ifdef CONFIG_IMA ++ || atomic_read(&dentry->d_inode->i_readcount) ++#endif ++ )) { ++ if (is_olock_dir(inode)) ++ return -EPERM; ++ } ++ return 0; ++} ++ ++/* Initialization */ ++ ++static struct security_hook_list altha_hooks[] = { ++ LSM_HOOK_INIT(bprm_set_creds, altha_bprm_set_creds), ++ LSM_HOOK_INIT(inode_unlink, altha_inode_unlink), ++}; ++ ++static int __init altha_init(void) ++{ ++ if (altha_enabled) { ++ pr_info("AltHa enabled.\n"); ++ security_add_hooks(altha_hooks, ARRAY_SIZE(altha_hooks),"altha"); ++ ++ if (!register_sysctl_paths ++ (nosuid_sysctl_path, nosuid_sysctl_table)) ++ panic("AltHa: NoSUID sysctl registration failed.\n"); ++ ++ if (!register_sysctl_paths ++ (rstrscript_sysctl_path, rstrscript_sysctl_table)) ++ panic ++ ("AltHa: RestrScript sysctl registration failed.\n"); ++ ++ if (!register_sysctl_paths ++ (olock_sysctl_path, olock_sysctl_table)) ++ panic("AltHa: OLock sysctl registration failed.\n"); ++ } else ++ pr_info("AltHa disabled.\n"); ++ return 0; ++} ++ ++DEFINE_LSM(altha) = { ++ .name = "altha", ++ .init = altha_init, ++}; ++ +-- +2.20.1 + diff --git a/0002-Documentation-for-AltHa-LSM.patch b/0002-Documentation-for-AltHa-LSM.patch new file mode 100644 index 0000000..44cc39e --- /dev/null +++ b/0002-Documentation-for-AltHa-LSM.patch @@ -0,0 +1,72 @@ +From b7faaef27bb8ede32f5cf2958fa6d84976806f14 Mon Sep 17 00:00:00 2001 +From: "Anton V. Boyarshinov" +Date: Thu, 17 May 2018 08:30:25 +0000 +Subject: [PATCH 2/2] Documentation for AltHa LSM + +--- + Documentation/admin-guide/LSM/AltHa.rst | 43 +++++++++++++++++++++++++ + Documentation/admin-guide/LSM/index.rst | 1 + + 2 files changed, 44 insertions(+) + create mode 100644 Documentation/admin-guide/LSM/AltHa.rst + +diff --git a/Documentation/admin-guide/LSM/AltHa.rst b/Documentation/admin-guide/LSM/AltHa.rst +new file mode 100644 +index 000000000000..0b2ad0c8dd17 +--- /dev/null ++++ b/Documentation/admin-guide/LSM/AltHa.rst +@@ -0,0 +1,43 @@ ++==== ++AltHa ++==== ++ ++AltHa is a Linux Security Module currently has three userspace hardening options: ++ * ignore SUID on binaries (with exceptions possible); ++ * prevent running selected script interprers in interactive move; ++ * disable open file unlinking in selected dirs. ++ ++ ++It is selectable at build-time with ``CONFIG_SECURITY_ALTHA``, and should be ++enabled in runtime by command line option ``altha=1`` and configuded ++through sysctls in ``/proc/sys/kernel/altha``. ++ ++NoSUID ++============ ++Modern Linux systems can be used with minimal (or even zero at least for OWL and ALT) usage of SUID programms, but in many cases in full-featured desktop or server systems there ara plenty of them: uncounted and sometimes unnessesary. Privileged programms are always a attack surface, but mounting filesystems with ``nosuid`` flag doesn't provide enouth granularity in SUID binaries manageent. This LSM module provides a single control point for all SUID binaries. When this submodule is enabled, SUID bits on all binaries except explicitally listed are system-wide ignored. ++ ++Sysctl parameters and defaults: ++ ++* ``kernel.altha.nosuid.enabled = 0``, set to 1 to enable ++* ``kernel.altha.nosuid.exceptions =``, colon-separated list of enabled SUID binaries, for example: ``/bin/su:/usr/libexec/hasher-priv/hasher-priv`` ++ ++RestrScript ++============ ++There is a one way to hardening: prevent users from executing ther own arbitrary code. Thraditionally it can be done setting on user-writable filesystems ``noexec`` flag. But modern script languages such as Python also can be used to write exploits or even load arbitary machine code via ``dlopen`` and users can start scripts from ``noexec`` filesystem starting interpreter directly. ++Restrscript LSM submodule provides a way to restrict some programms to be executed directly, but allows to execute them as shebang handler. ++ ++Sysctl parameters and defaults: ++ ++* ``kernel.altha.rstrscript.enabled = 0``, set to 1 to enable ++* ``kernel.altha.rstrscript.interpreters =``, colon-separated list of restricted interpreters for example: ``/usr/bin/python:/usr/bin/python3:/usr/bin/perl:/usr/bin/tclsh``. Simlinks are suporrted in both ways: you can set symlink to interpreter as exception and interpreter and all symlinks on it will be restricted. ++ ++Note: in this configuration all scripts starting with ``#!/usr/bin/env python`` will be blocked. ++ ++OLock ++============ ++Unlink disabling for open files needed for Russian sertification, but this is a nasty feature leading to DOS. ++ ++Sysctl parameters and defaults: ++ ++* ``kernel.altha.olock.enabled = 0``, set to 1 to enable ++* ``kernel.altha.olock.dirs =``, colon-separated list of dirs, for example: ``/var/lib/something:/tmp/something``. +diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst +index a6ba95fbaa9f..20b57e7adadd 100644 +--- a/Documentation/admin-guide/LSM/index.rst ++++ b/Documentation/admin-guide/LSM/index.rst +@@ -47,3 +47,4 @@ subdirectories. + tomoyo + Yama + SafeSetID ++ AltHa +-- +2.20.1 + diff --git a/kernel-i586.config b/kernel-i586.config index 8ee056d..4d0c4a4 100644 --- a/kernel-i586.config +++ b/kernel-i586.config @@ -3719,7 +3719,7 @@ CONFIG_LPC_SCH=m CONFIG_LRU_CACHE=m CONFIG_LSI_ET1011C_PHY=m CONFIG_LSM_MMAP_MIN_ADDR=65536 -CONFIG_LSM="yama,loadpin,integrity,selinux,apparmor" +CONFIG_LSM="yama,loadpin,integrity,selinux,apparmor,altha" CONFIG_LTC1660=m CONFIG_LTC2471=m CONFIG_LTC2485=m diff --git a/kernel-x86_64.config b/kernel-x86_64.config index e16af3f..f9dfc0b 100644 --- a/kernel-x86_64.config +++ b/kernel-x86_64.config @@ -3764,7 +3764,7 @@ CONFIG_LPC_SCH=m CONFIG_LRU_CACHE=m CONFIG_LSI_ET1011C_PHY=m CONFIG_LSM_MMAP_MIN_ADDR=65536 -CONFIG_LSM="yama,loadpin,integrity,selinux,apparmor" +CONFIG_LSM="yama,loadpin,integrity,selinux,apparmor,altha" CONFIG_LTC1660=m CONFIG_LTC2471=m CONFIG_LTC2485=m diff --git a/kernel.spec b/kernel.spec index aa662c2..6c4bbe3 100644 --- a/kernel.spec +++ b/kernel.spec @@ -11,7 +11,7 @@ %define sublevel 25 # Release number. Increase this before a rebuild. -%define rpmrel 6 +%define rpmrel 7 %define fullrpmrel %{rpmrel} %define rpmtag %{disttag} @@ -209,9 +209,16 @@ Patch102: audit-make-it-less-verbose.patch # AUFS from http://aufs.sourceforge.net/ Patch109: fs-aufs.patch +# AltHa LSM Module +# https://www.altlinux.org/AltHa +# http://git.altlinux.org/gears/k/kernel-image-un-def.git +# TODO: known problem: https://bugzilla.altlinux.org/show_bug.cgi?id=38225 +Patch201: 0001-AltHa-LSM-module.patch +Patch202: 0002-Documentation-for-AltHa-LSM.patch + # Other patches -Patch110: objtool-sync-check.sh-set-the-exit-code-explicitly.patch -Patch200: WIP-Sign-modules-with-GOST-by-LibreSSL.patch +Patch301: objtool-sync-check.sh-set-the-exit-code-explicitly.patch +Patch302: WIP-Sign-modules-with-GOST-by-LibreSSL.patch # Disable AutoReq AutoReq: 0 @@ -876,6 +883,11 @@ sed -i '/CONFIG_CRYPTO_STREEBOG/d' .config echo 'CONFIG_CRYPTO_STREEBOG=y' >> %{build_dir}/.config.append sed -i '/CONFIG_CRYPTO_ECRDSA/d' .config echo 'CONFIG_CRYPTO_ECRDSA=y' >> %{build_dir}/.config.append + +sed -i '/CONFIG_LSM/d' .config +echo 'CONFIG_LSM="yama,loadpin,integrity,selinux,apparmor,altha"' >> %{build_dir}/.config.append +sed -i '/CONFIG_SECURITY_ALTHA/d' .config +echo 'CONFIG_SECURITY_ALTHA=y' >> %{build_dir}/.config.append %endif cat %{build_dir}/.config.append >> .config