From 791ec491c372f49cea3ea7a7143454a9023ac9d4 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Fri, 17 Feb 2017 07:57:00 -0500 Subject: prlimit,security,selinux: add a security hook for prlimit When SELinux was first added to the kernel, a process could only get and set its own resource limits via getrlimit(2) and setrlimit(2), so no MAC checks were required for those operations, and thus no security hooks were defined for them. Later, SELinux introduced a hook for setlimit(2) with a check if the hard limit was being changed in order to be able to rely on the hard limit value as a safe reset point upon context transitions. Later on, when prlimit(2) was added to the kernel with the ability to get or set resource limits (hard or soft) of another process, LSM/SELinux was not updated other than to pass the target process to the setrlimit hook. This resulted in incomplete control over both getting and setting the resource limits of another process. Add a new security_task_prlimit() hook to the check_prlimit_permission() function to provide complete mediation. The hook is only called when acting on another task, and only if the existing DAC/capability checks would allow access. Pass flags down to the hook to indicate whether the prlimit(2) call will read, write, or both read and write the resource limits of the target process. The existing security_task_setrlimit() hook is left alone; it continues to serve a purpose in supporting the ability to make decisions based on the old and/or new resource limit values when setting limits. This is consistent with the DAC/capability logic, where check_prlimit_permission() performs generic DAC/capability checks for acting on another task, while do_prlimit() performs a capability check based on a comparison of the old and new resource limits. Fix the inline documentation for the hook to match the code. Implement the new hook for SELinux. For setting resource limits, we reuse the existing setrlimit permission. Note that this does overload the setrlimit permission to mean the ability to set the resource limit (soft or hard) of another process or the ability to change one's own hard limit. For getting resource limits, a new getrlimit permission is defined. This was not originally defined since getrlimit(2) could only be used to obtain a process' own limits. Signed-off-by: Stephen Smalley Signed-off-by: James Morris --- security/security.c | 8 ++++++++ security/selinux/hooks.c | 14 ++++++++++++++ security/selinux/include/classmap.h | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) (limited to 'security') diff --git a/security/security.c b/security/security.c index d0e07f2..905dad2 100644 --- a/security/security.c +++ b/security/security.c @@ -1036,6 +1036,12 @@ int security_task_getioprio(struct task_struct *p) return call_int_hook(task_getioprio, 0, p); } +int security_task_prlimit(const struct cred *cred, const struct cred *tcred, + unsigned int flags) +{ + return call_int_hook(task_prlimit, 0, cred, tcred, flags); +} + int security_task_setrlimit(struct task_struct *p, unsigned int resource, struct rlimit *new_rlim) { @@ -1793,6 +1799,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.task_setioprio), .task_getioprio = LIST_HEAD_INIT(security_hook_heads.task_getioprio), + .task_prlimit = + LIST_HEAD_INIT(security_hook_heads.task_prlimit), .task_setrlimit = LIST_HEAD_INIT(security_hook_heads.task_setrlimit), .task_setscheduler = diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 0c2ac31..870d24e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3920,6 +3920,19 @@ static int selinux_task_getioprio(struct task_struct *p) PROCESS__GETSCHED, NULL); } +int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, + unsigned int flags) +{ + u32 av = 0; + + if (flags & LSM_PRLIMIT_WRITE) + av |= PROCESS__SETRLIMIT; + if (flags & LSM_PRLIMIT_READ) + av |= PROCESS__GETRLIMIT; + return avc_has_perm(cred_sid(cred), cred_sid(tcred), + SECCLASS_PROCESS, av, NULL); +} + static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, struct rlimit *new_rlim) { @@ -6206,6 +6219,7 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(task_setnice, selinux_task_setnice), LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio), LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio), + LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit), LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit), LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler), LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler), diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index d429c4a..1e0cc9b 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -47,7 +47,7 @@ struct security_class_mapping secclass_map[] = { "getattr", "setexec", "setfscreate", "noatsecure", "siginh", "setrlimit", "rlimitinh", "dyntransition", "setcurrent", "execmem", "execstack", "execheap", "setkeycreate", - "setsockcreate", NULL } }, + "setsockcreate", "getrlimit", NULL } }, { "system", { "ipc_info", "syslog_read", "syslog_mod", "syslog_console", "module_request", "module_load", NULL } }, -- cgit v1.1 From 84e6885e9e6a818d1ca1eabb9b720b357ab07a8b Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 28 Feb 2017 09:35:08 -0500 Subject: selinux: fix kernel BUG on prlimit(..., NULL, NULL) commit 79bcf325e6b32b3c ("prlimit,security,selinux: add a security hook for prlimit") introduced a security hook for prlimit() and implemented it for SELinux. However, if prlimit() is called with NULL arguments for both the new limit and the old limit, then the hook is called with 0 for the read/write flags, since the prlimit() will neither read nor write the process' limits. This would in turn lead to calling avc_has_perm() with 0 for the requested permissions, which triggers a BUG_ON() in avc_has_perm_noaudit() since the kernel should never be invoking avc_has_perm() with no permissions. Fix this in the SELinux hook by returning immediately if the flags are 0. Arguably prlimit64() itself ought to return immediately if both old_rlim and new_rlim are NULL since it is effectively a no-op in that case. Reported by the lkp-robot based on trinity testing. Signed-off-by: Stephen Smalley Acked-by: Paul Moore Signed-off-by: James Morris --- security/selinux/hooks.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'security') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 870d24e..3ba5ce1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3925,6 +3925,8 @@ int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, { u32 av = 0; + if (!flags) + return 0; if (flags & LSM_PRLIMIT_WRITE) av |= PROCESS__SETRLIMIT; if (flags & LSM_PRLIMIT_READ) -- cgit v1.1 From dd0859dccbe291cf8179a96390f5c0e45cb9af1d Mon Sep 17 00:00:00 2001 From: James Morris Date: Wed, 15 Feb 2017 00:17:24 +1100 Subject: security: introduce CONFIG_SECURITY_WRITABLE_HOOKS Subsequent patches will add RO hardening to LSM hooks, however, SELinux still needs to be able to perform runtime disablement after init to handle architectures where init-time disablement via boot parameters is not feasible. Introduce a new kernel configuration parameter CONFIG_SECURITY_WRITABLE_HOOKS, and a helper macro __lsm_ro_after_init, to handle this case. Signed-off-by: James Morris Acked-by: Stephen Smalley Acked-by: Casey Schaufler Acked-by: Kees Cook --- security/Kconfig | 5 +++++ security/selinux/Kconfig | 6 ++++++ 2 files changed, 11 insertions(+) (limited to 'security') diff --git a/security/Kconfig b/security/Kconfig index d900f47..3ff1bf9 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -31,6 +31,11 @@ config SECURITY If you are unsure how to answer this question, answer N. +config SECURITY_WRITABLE_HOOKS + depends on SECURITY + bool + default n + config SECURITYFS bool "Enable the securityfs filesystem" help diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index ea7e3ef..8af7a69 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -40,6 +40,7 @@ config SECURITY_SELINUX_BOOTPARAM_VALUE config SECURITY_SELINUX_DISABLE bool "NSA SELinux runtime disable" depends on SECURITY_SELINUX + select SECURITY_WRITABLE_HOOKS default n help This option enables writing to a selinuxfs node 'disable', which @@ -50,6 +51,11 @@ config SECURITY_SELINUX_DISABLE portability across platforms where boot parameters are difficult to employ. + NOTE: selecting this option will disable the '__ro_after_init' + kernel hardening feature for security hooks. Please consider + using the selinux=0 boot parameter instead of enabling this + option. + If you are unsure how to answer this question, answer N. config SECURITY_SELINUX_DEVELOP -- cgit v1.1 From ca97d939db114c8d1619e10a3b82af8615372dae Mon Sep 17 00:00:00 2001 From: James Morris Date: Wed, 15 Feb 2017 00:18:51 +1100 Subject: security: mark LSM hooks as __ro_after_init Mark all of the registration hooks as __ro_after_init (via the __lsm_ro_after_init macro). Signed-off-by: James Morris Acked-by: Stephen Smalley Acked-by: Kees Cook --- security/apparmor/lsm.c | 2 +- security/commoncap.c | 2 +- security/loadpin/loadpin.c | 2 +- security/security.c | 2 +- security/selinux/hooks.c | 2 +- security/smack/smack_lsm.c | 2 +- security/tomoyo/tomoyo.c | 2 +- security/yama/yama_lsm.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'security') diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 709eacd..e287b69 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -587,7 +587,7 @@ static int apparmor_task_setrlimit(struct task_struct *task, return error; } -static struct security_hook_list apparmor_hooks[] = { +static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), LSM_HOOK_INIT(capget, apparmor_capget), diff --git a/security/commoncap.c b/security/commoncap.c index 78b3783..7abebd7 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -1071,7 +1071,7 @@ int cap_mmap_file(struct file *file, unsigned long reqprot, #ifdef CONFIG_SECURITY -struct security_hook_list capability_hooks[] = { +struct security_hook_list capability_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(capable, cap_capable), LSM_HOOK_INIT(settime, cap_settime), LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check), diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 1d82eae..dbe6efd 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -174,7 +174,7 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) return 0; } -static struct security_hook_list loadpin_hooks[] = { +static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security), LSM_HOOK_INIT(kernel_read_file, loadpin_read_file), }; diff --git a/security/security.c b/security/security.c index 905dad2..d6d18a3 100644 --- a/security/security.c +++ b/security/security.c @@ -1628,7 +1628,7 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, } #endif /* CONFIG_AUDIT */ -struct security_hook_heads security_hook_heads = { +struct security_hook_heads security_hook_heads __lsm_ro_after_init = { .binder_set_context_mgr = LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr), .binder_transaction = diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3ba5ce1..d37a723 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6123,7 +6123,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) #endif -static struct security_hook_list selinux_hooks[] = { +static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder), diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index fc8fb31..927e60e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4633,7 +4633,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) return 0; } -static struct security_hook_list smack_hooks[] = { +static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), LSM_HOOK_INIT(syslog, smack_syslog), diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index edc52d6..b5fb930 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -496,7 +496,7 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, * tomoyo_security_ops is a "struct security_operations" which is used for * registering TOMOYO. */ -static struct security_hook_list tomoyo_hooks[] = { +static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank), LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer), diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 88271a3..8298e09 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -428,7 +428,7 @@ int yama_ptrace_traceme(struct task_struct *parent) return rc; } -static struct security_hook_list yama_hooks[] = { +static struct security_hook_list yama_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme), LSM_HOOK_INIT(task_prctl, yama_task_prctl), -- cgit v1.1 From 579fc0dc09111c1f8b94742a0ed5a0bb8fdddbb9 Mon Sep 17 00:00:00 2001 From: James Morris Date: Mon, 6 Mar 2017 11:58:08 -0500 Subject: selinux: constify nlmsg permission tables Constify nlmsg permission tables, which are initialized once and then do not change. Signed-off-by: James Morris Signed-off-by: Paul Moore --- security/selinux/nlmsgtab.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'security') diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 2ca9cde..57e2596 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -28,7 +28,7 @@ struct nlmsg_perm { u32 perm; }; -static struct nlmsg_perm nlmsg_route_perms[] = +static const struct nlmsg_perm nlmsg_route_perms[] = { { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, @@ -80,7 +80,7 @@ static struct nlmsg_perm nlmsg_route_perms[] = { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, }; -static struct nlmsg_perm nlmsg_tcpdiag_perms[] = +static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = { { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, @@ -88,7 +88,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] = { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, }; -static struct nlmsg_perm nlmsg_xfrm_perms[] = +static const struct nlmsg_perm nlmsg_xfrm_perms[] = { { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, @@ -115,7 +115,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; -static struct nlmsg_perm nlmsg_audit_perms[] = +static const struct nlmsg_perm nlmsg_audit_perms[] = { { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, @@ -136,7 +136,7 @@ static struct nlmsg_perm nlmsg_audit_perms[] = }; -static int nlmsg_perm(u16 nlmsg_type, u32 *perm, struct nlmsg_perm *tab, size_t tabsize) +static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, size_t tabsize) { int i, err = -EINVAL; -- cgit v1.1 From bad4417b692ede5cf31105b329cea1544875b526 Mon Sep 17 00:00:00 2001 From: James Morris Date: Mon, 13 Feb 2017 16:34:35 +1100 Subject: integrity: mark default IMA rules as __ro_after_init The default IMA rules are loaded during init and then do not change, so mark them as __ro_after_init. Signed-off-by: James Morris Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_policy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'security') diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index aed47b7..e8498a3 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -83,7 +83,7 @@ struct ima_rule_entry { * normal users can easily run the machine out of memory simply building * and running executables. */ -static struct ima_rule_entry dont_measure_rules[] = { +static struct ima_rule_entry dont_measure_rules[] __ro_after_init = { {.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, @@ -97,7 +97,7 @@ static struct ima_rule_entry dont_measure_rules[] = { {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC} }; -static struct ima_rule_entry original_measurement_rules[] = { +static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, @@ -108,7 +108,7 @@ static struct ima_rule_entry original_measurement_rules[] = { {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, }; -static struct ima_rule_entry default_measurement_rules[] = { +static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, @@ -122,7 +122,7 @@ static struct ima_rule_entry default_measurement_rules[] = { {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, }; -static struct ima_rule_entry default_appraise_rules[] = { +static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { {.action = DONT_APPRAISE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC}, {.action = DONT_APPRAISE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC}, -- cgit v1.1 From 1ac202e978e18f045006d75bd549612620c6ec3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Fri, 24 Feb 2017 15:05:14 +0100 Subject: ima: accept previously set IMA_NEW_FILE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modifying the attributes of a file makes ima_inode_post_setattr reset the IMA cache flags. So if the file, which has just been created, is opened a second time before the first file descriptor is closed, verification fails since the security.ima xattr has not been written yet. We therefore have to look at the IMA_NEW_FILE even if the file already existed. With this patch there should no longer be an error when cat tries to open testfile: $ rm -f testfile $ ( echo test >&3 ; touch testfile ; cat testfile ) 3>testfile A file being new is no reason to accept that it is missing a digital signature demanded by the policy. Signed-off-by: Daniel Glöckner Cc: stable@vger.kernel.org Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_appraise.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 1fd9539..5d0785c 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -207,10 +207,11 @@ int ima_appraise_measurement(enum ima_hooks func, cause = "missing-hash"; status = INTEGRITY_NOLABEL; - if (opened & FILE_CREATED) { + if (opened & FILE_CREATED) iint->flags |= IMA_NEW_FILE; + if ((iint->flags & IMA_NEW_FILE) && + !(iint->flags & IMA_DIGSIG_REQUIRED)) status = INTEGRITY_PASS; - } goto out; } -- cgit v1.1 From e2f586bd83177d22072b275edd4b8b872daba924 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 6 Mar 2017 19:46:14 +0100 Subject: selinux: check for address length in selinux_socket_bind() KMSAN (KernelMemorySanitizer, a new error detection tool) reports use of uninitialized memory in selinux_socket_bind(): ================================================================== BUG: KMSAN: use of unitialized memory inter: 0 CPU: 3 PID: 1074 Comm: packet2 Tainted: G B 4.8.0-rc6+ #1916 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 0000000000000000 ffff8800882ffb08 ffffffff825759c8 ffff8800882ffa48 ffffffff818bf551 ffffffff85bab870 0000000000000092 ffffffff85bab550 0000000000000000 0000000000000092 00000000bb0009bb 0000000000000002 Call Trace: [< inline >] __dump_stack lib/dump_stack.c:15 [] dump_stack+0x238/0x290 lib/dump_stack.c:51 [] kmsan_report+0x276/0x2e0 mm/kmsan/kmsan.c:1008 [] __msan_warning+0x5b/0xb0 mm/kmsan/kmsan_instr.c:424 [] selinux_socket_bind+0xf41/0x1080 security/selinux/hooks.c:4288 [] security_socket_bind+0x1ec/0x240 security/security.c:1240 [] SYSC_bind+0x358/0x5f0 net/socket.c:1366 [] SyS_bind+0x82/0xa0 net/socket.c:1356 [] do_syscall_64+0x58/0x70 arch/x86/entry/common.c:292 [] entry_SYSCALL64_slow_path+0x25/0x25 arch/x86/entry/entry_64.o:? chained origin: 00000000ba6009bb [] save_stack_trace+0x27/0x50 arch/x86/kernel/stacktrace.c:67 [< inline >] kmsan_save_stack_with_flags mm/kmsan/kmsan.c:322 [< inline >] kmsan_save_stack mm/kmsan/kmsan.c:337 [] kmsan_internal_chain_origin+0x118/0x1e0 mm/kmsan/kmsan.c:530 [] __msan_set_alloca_origin4+0xc3/0x130 mm/kmsan/kmsan_instr.c:380 [] SYSC_bind+0x129/0x5f0 net/socket.c:1356 [] SyS_bind+0x82/0xa0 net/socket.c:1356 [] do_syscall_64+0x58/0x70 arch/x86/entry/common.c:292 [] return_from_SYSCALL_64+0x0/0x6a arch/x86/entry/entry_64.o:? origin description: ----address@SYSC_bind (origin=00000000b8c00900) ================================================================== (the line numbers are relative to 4.8-rc6, but the bug persists upstream) , when I run the following program as root: ======================================================= #include #include #include int main(int argc, char *argv[]) { struct sockaddr addr; int size = 0; if (argc > 1) { size = atoi(argv[1]); } memset(&addr, 0, sizeof(addr)); int fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); bind(fd, &addr, size); return 0; } ======================================================= (for different values of |size| other error reports are printed). This happens because bind() unconditionally copies |size| bytes of |addr| to the kernel, leaving the rest uninitialized. Then security_socket_bind() reads the IP address bytes, including the uninitialized ones, to determine the port, or e.g. pass them further to sel_netnode_find(), which uses them to calculate a hash. Signed-off-by: Alexander Potapenko Acked-by: Eric Dumazet [PM: fixed some whitespace damage] Signed-off-by: Paul Moore --- security/selinux/hooks.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'security') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d37a723..e67a526 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4367,10 +4367,18 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in u32 sid, node_perm; if (family == PF_INET) { + if (addrlen < sizeof(struct sockaddr_in)) { + err = -EINVAL; + goto out; + } addr4 = (struct sockaddr_in *)address; snum = ntohs(addr4->sin_port); addrp = (char *)&addr4->sin_addr.s_addr; } else { + if (addrlen < SIN6_LEN_RFC2133) { + err = -EINVAL; + goto out; + } addr6 = (struct sockaddr_in6 *)address; snum = ntohs(addr6->sin6_port); addrp = (char *)&addr6->sin6_addr.s6_addr; -- cgit v1.1 From 3dd0c8d06511c7c61c62305fcf431ca28884d263 Mon Sep 17 00:00:00 2001 From: Mikhail Kurinnoi Date: Fri, 27 Jan 2017 19:23:01 +0300 Subject: ima: provide ">" and "<" operators for fowner/uid/euid rules. For now we have only "=" operator for fowner/uid/euid rules. This patch provide two more operators - ">" and "<" in order to make fowner/uid/euid rules more flexible. Examples of usage. Appraise all files owned by special and system users (SYS_UID_MAX 999): appraise fowner<1000 Don't appraise files owned by normal users (UID_MIN 1000): dont_appraise fowner>999 Appraise all files owned by users with UID 1000-1010: dont_appraise fowner>1010 appraise fowner>999 Changelog v3: - Removed code duplication in ima_parse_rule(). - Fix ima_policy_show() - (Mimi) Changelog v2: - Fixed default policy rules. Signed-off-by: Mikhail Kurinnoi Signed-off-by: Mimi Zohar security/integrity/ima/ima_policy.c | 115 +++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 28 deletions(-) --- security/integrity/ima/ima_policy.c | 115 +++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 28 deletions(-) (limited to 'security') diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index e8498a3..3ab1067 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -64,6 +64,8 @@ struct ima_rule_entry { u8 fsuuid[16]; kuid_t uid; kuid_t fowner; + bool (*uid_op)(kuid_t, kuid_t); /* Handlers for operators */ + bool (*fowner_op)(kuid_t, kuid_t); /* uid_eq(), uid_gt(), uid_lt() */ int pcr; struct { void *rule; /* LSM file metadata specific */ @@ -103,7 +105,8 @@ static struct ima_rule_entry original_measurement_rules[] __ro_after_init = { {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, - .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, + .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, + .flags = IMA_FUNC | IMA_MASK | IMA_UID}, {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, }; @@ -114,9 +117,11 @@ static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, - .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, + .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, + .flags = IMA_FUNC | IMA_INMASK | IMA_EUID}, {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, - .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, + .uid = GLOBAL_ROOT_UID, .uid_op = &uid_eq, + .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, @@ -139,10 +144,11 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, #endif #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT - {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER}, + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, + .flags = IMA_FOWNER}, #else /* force signature */ - {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, #endif }; @@ -240,19 +246,20 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, if ((rule->flags & IMA_FSUUID) && memcmp(rule->fsuuid, inode->i_sb->s_uuid, sizeof(rule->fsuuid))) return false; - if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid)) + if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid)) return false; if (rule->flags & IMA_EUID) { if (has_capability_noaudit(current, CAP_SETUID)) { - if (!uid_eq(rule->uid, cred->euid) - && !uid_eq(rule->uid, cred->suid) - && !uid_eq(rule->uid, cred->uid)) + if (!rule->uid_op(cred->euid, rule->uid) + && !rule->uid_op(cred->suid, rule->uid) + && !rule->uid_op(cred->uid, rule->uid)) return false; - } else if (!uid_eq(rule->uid, cred->euid)) + } else if (!rule->uid_op(cred->euid, rule->uid)) return false; } - if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid)) + if ((rule->flags & IMA_FOWNER) && + !rule->fowner_op(inode->i_uid, rule->fowner)) return false; for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; @@ -486,7 +493,9 @@ enum { Opt_obj_user, Opt_obj_role, Opt_obj_type, Opt_subj_user, Opt_subj_role, Opt_subj_type, Opt_func, Opt_mask, Opt_fsmagic, - Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner, + Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq, + Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, + Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, Opt_appraise_type, Opt_permit_directio, Opt_pcr }; @@ -507,9 +516,15 @@ static match_table_t policy_tokens = { {Opt_mask, "mask=%s"}, {Opt_fsmagic, "fsmagic=%s"}, {Opt_fsuuid, "fsuuid=%s"}, - {Opt_uid, "uid=%s"}, - {Opt_euid, "euid=%s"}, - {Opt_fowner, "fowner=%s"}, + {Opt_uid_eq, "uid=%s"}, + {Opt_euid_eq, "euid=%s"}, + {Opt_fowner_eq, "fowner=%s"}, + {Opt_uid_gt, "uid>%s"}, + {Opt_euid_gt, "euid>%s"}, + {Opt_fowner_gt, "fowner>%s"}, + {Opt_uid_lt, "uid<%s"}, + {Opt_euid_lt, "euid<%s"}, + {Opt_fowner_lt, "fowner<%s"}, {Opt_appraise_type, "appraise_type=%s"}, {Opt_permit_directio, "permit_directio"}, {Opt_pcr, "pcr=%s"}, @@ -541,24 +556,37 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, return result; } -static void ima_log_string(struct audit_buffer *ab, char *key, char *value) +static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value, + bool (*rule_operator)(kuid_t, kuid_t)) { - audit_log_format(ab, "%s=", key); + if (rule_operator == &uid_gt) + audit_log_format(ab, "%s>", key); + else if (rule_operator == &uid_lt) + audit_log_format(ab, "%s<", key); + else + audit_log_format(ab, "%s=", key); audit_log_untrustedstring(ab, value); audit_log_format(ab, " "); } +static void ima_log_string(struct audit_buffer *ab, char *key, char *value) +{ + ima_log_string_op(ab, key, value, NULL); +} static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) { struct audit_buffer *ab; char *from; char *p; + bool uid_token; int result = 0; ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); entry->uid = INVALID_UID; entry->fowner = INVALID_UID; + entry->uid_op = &uid_eq; + entry->fowner_op = &uid_eq; entry->action = UNKNOWN; while ((p = strsep(&rule, " \t")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -694,11 +722,21 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) if (!result) entry->flags |= IMA_FSUUID; break; - case Opt_uid: - ima_log_string(ab, "uid", args[0].from); - case Opt_euid: - if (token == Opt_euid) - ima_log_string(ab, "euid", args[0].from); + case Opt_uid_gt: + case Opt_euid_gt: + entry->uid_op = &uid_gt; + case Opt_uid_lt: + case Opt_euid_lt: + if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) + entry->uid_op = &uid_lt; + case Opt_uid_eq: + case Opt_euid_eq: + uid_token = (token == Opt_uid_eq) || + (token == Opt_uid_gt) || + (token == Opt_uid_lt); + + ima_log_string_op(ab, uid_token ? "uid" : "euid", + args[0].from, entry->uid_op); if (uid_valid(entry->uid)) { result = -EINVAL; @@ -713,12 +751,18 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) (uid_t)lnum != lnum) result = -EINVAL; else - entry->flags |= (token == Opt_uid) + entry->flags |= uid_token ? IMA_UID : IMA_EUID; } break; - case Opt_fowner: - ima_log_string(ab, "fowner", args[0].from); + case Opt_fowner_gt: + entry->fowner_op = &uid_gt; + case Opt_fowner_lt: + if (token == Opt_fowner_lt) + entry->fowner_op = &uid_lt; + case Opt_fowner_eq: + ima_log_string_op(ab, "fowner", args[0].from, + entry->fowner_op); if (uid_valid(entry->fowner)) { result = -EINVAL; @@ -1049,19 +1093,34 @@ int ima_policy_show(struct seq_file *m, void *v) if (entry->flags & IMA_UID) { snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); - seq_printf(m, pt(Opt_uid), tbuf); + if (entry->uid_op == &uid_gt) + seq_printf(m, pt(Opt_uid_gt), tbuf); + else if (entry->uid_op == &uid_lt) + seq_printf(m, pt(Opt_uid_lt), tbuf); + else + seq_printf(m, pt(Opt_uid_eq), tbuf); seq_puts(m, " "); } if (entry->flags & IMA_EUID) { snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); - seq_printf(m, pt(Opt_euid), tbuf); + if (entry->uid_op == &uid_gt) + seq_printf(m, pt(Opt_euid_gt), tbuf); + else if (entry->uid_op == &uid_lt) + seq_printf(m, pt(Opt_euid_lt), tbuf); + else + seq_printf(m, pt(Opt_euid_eq), tbuf); seq_puts(m, " "); } if (entry->flags & IMA_FOWNER) { snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); - seq_printf(m, pt(Opt_fowner), tbuf); + if (entry->fowner_op == &uid_gt) + seq_printf(m, pt(Opt_fowner_gt), tbuf); + else if (entry->fowner_op == &uid_lt) + seq_printf(m, pt(Opt_fowner_lt), tbuf); + else + seq_printf(m, pt(Opt_fowner_eq), tbuf); seq_puts(m, " "); } -- cgit v1.1 From f6076f704aa29679fdba114b0f60e71e0884840a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 10:48:28 +0100 Subject: selinux: Use kmalloc_array() in cond_init_bool_indexes() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/conditional.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 34afead..fcfab26 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -176,8 +176,9 @@ void cond_policydb_destroy(struct policydb *p) int cond_init_bool_indexes(struct policydb *p) { kfree(p->bool_val_to_struct); - p->bool_val_to_struct = - kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL); + p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim, + sizeof(*p->bool_val_to_struct), + GFP_KERNEL); if (!p->bool_val_to_struct) return -ENOMEM; return 0; -- cgit v1.1 From e34cfef901badc0e17c2b296a535e7412ef038f3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 11:00:23 +0100 Subject: selinux: Delete an unnecessary return statement in cond_compute_av() The script "checkpatch.pl" pointed information out like the following. WARNING: void function return statements are not generally useful Thus remove such a statement in the affected function. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/conditional.c | 1 - 1 file changed, 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index fcfab26..4a3bf29 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -664,5 +664,4 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, (node->key.specified & AVTAB_XPERMS)) services_compute_xperms_drivers(xperms, node); } - return; } -- cgit v1.1 From fb13a312daa11005b0230695a1d6a0b4e2b27069 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 11:22:12 +0100 Subject: selinux: Improve size determinations in four functions Replace the specification of data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/conditional.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 4a3bf29..771c96a 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -227,7 +227,7 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp) u32 len; int rc; - booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL); + booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL); if (!booldatum) return -ENOMEM; @@ -332,7 +332,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum goto err; } - list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL); + list = kzalloc(sizeof(*list), GFP_KERNEL); if (!list) { rc = -ENOMEM; goto err; @@ -421,7 +421,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) goto err; rc = -ENOMEM; - expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL); + expr = kzalloc(sizeof(*expr), GFP_KERNEL); if (!expr) goto err; @@ -472,7 +472,7 @@ int cond_read_list(struct policydb *p, void *fp) for (i = 0; i < len; i++) { rc = -ENOMEM; - node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); + node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) goto err; -- cgit v1.1 From 2f00e680fe25d8d2758879b772d54cb46a78b59d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 12:06:13 +0100 Subject: selinux: Use kmalloc_array() in hashtab_create() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/hashtab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 2cc4961..dc99fff 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -24,7 +24,7 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void * p->nel = 0; p->hash_value = hash_value; p->keycmp = keycmp; - p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL); + p->htable = kmalloc_array(size, sizeof(*p->htable), GFP_KERNEL); if (p->htable == NULL) { kfree(p); return NULL; -- cgit v1.1 From cb8d21e3640f18444c597bddaec156637eacecf8 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 12:36:59 +0100 Subject: selinux: Adjust four checks for null pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The script "checkpatch.pl" pointed information out like the following. Comparison to NULL could be written !… Thus fix affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/hashtab.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index dc99fff..3858706 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -17,7 +17,7 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void * u32 i; p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) + if (!p) return p; p->size = size; @@ -25,7 +25,7 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void * p->hash_value = hash_value; p->keycmp = keycmp; p->htable = kmalloc_array(size, sizeof(*p->htable), GFP_KERNEL); - if (p->htable == NULL) { + if (!p->htable) { kfree(p); return NULL; } @@ -58,7 +58,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum) return -EEXIST; newnode = kzalloc(sizeof(*newnode), GFP_KERNEL); - if (newnode == NULL) + if (!newnode) return -ENOMEM; newnode->key = key; newnode->datum = datum; @@ -87,7 +87,7 @@ void *hashtab_search(struct hashtab *h, const void *key) while (cur && h->keycmp(h, key, cur->key) > 0) cur = cur->next; - if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) + if (!cur || (h->keycmp(h, key, cur->key) != 0)) return NULL; return cur->datum; -- cgit v1.1 From ad10a10567e243425d7be35a3d950709371fa048 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 13:08:59 +0100 Subject: selinux: Use kcalloc() in policydb_index() Multiplications for the size determination of memory allocations indicated that array data structures should be processed. Thus use the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 9c92f29..66b9a35 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -540,23 +540,23 @@ static int policydb_index(struct policydb *p) #endif rc = -ENOMEM; - p->class_val_to_struct = - kzalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), - GFP_KERNEL); + p->class_val_to_struct = kcalloc(p->p_classes.nprim, + sizeof(*p->class_val_to_struct), + GFP_KERNEL); if (!p->class_val_to_struct) goto out; rc = -ENOMEM; - p->role_val_to_struct = - kzalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)), - GFP_KERNEL); + p->role_val_to_struct = kcalloc(p->p_roles.nprim, + sizeof(*p->role_val_to_struct), + GFP_KERNEL); if (!p->role_val_to_struct) goto out; rc = -ENOMEM; - p->user_val_to_struct = - kzalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), - GFP_KERNEL); + p->user_val_to_struct = kcalloc(p->p_users.nprim, + sizeof(*p->user_val_to_struct), + GFP_KERNEL); if (!p->user_val_to_struct) goto out; -- cgit v1.1 From b4e4686f65a3092f63ed01c887d9f56714d29f4a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 14:00:02 +0100 Subject: selinux: Delete an unnecessary return statement in policydb_destroy() The script "checkpatch.pl" pointed information out like the following. WARNING: void function return statements are not generally useful Thus remove such a statement in the affected function. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 66b9a35..bccc9ac 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -880,8 +880,6 @@ void policydb_destroy(struct policydb *p) ebitmap_destroy(&p->filename_trans_ttypes); ebitmap_destroy(&p->policycaps); ebitmap_destroy(&p->permissive_map); - - return; } /* -- cgit v1.1 From 3a0aa56518432a1a598ac3e48a93f2e99c66a393 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 16:34:25 +0100 Subject: selinux: Return directly after a failed next_entry() in genfs_read() Return directly after a call of the function "next_entry" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index bccc9ac..375e304 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -2006,7 +2006,7 @@ static int genfs_read(struct policydb *p, void *fp) rc = next_entry(buf, fp, sizeof(u32)); if (rc) - goto out; + return rc; nel = le32_to_cpu(buf[0]); for (i = 0; i < nel; i++) { -- cgit v1.1 From 315e01ada8047cba0520ecca050ad8f5237abb41 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 17:43:47 +0100 Subject: selinux: One function call less in genfs_read() after null pointer detection Call the function "kfree" at the end only after it was determined that the local variable "newgenfs" contained a non-null pointer. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 375e304..4390558 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -2098,9 +2098,10 @@ static int genfs_read(struct policydb *p, void *fp) } rc = 0; out: - if (newgenfs) + if (newgenfs) { kfree(newgenfs->fstype); - kfree(newgenfs); + kfree(newgenfs); + } ocontext_destroy(newc, OCON_FSUSE); return rc; -- cgit v1.1 From 02fcef27cc908e22ddb68d30ad1b7fd9ac3a1c24 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 19:02:42 +0100 Subject: selinux: Delete an unnecessary variable assignment in filename_trans_read() The local variable "ft" was set to a null pointer despite of an immediate reassignment. Thus remove this statement from the beginning of a loop. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 4390558..7131251 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1929,7 +1929,6 @@ static int filename_trans_read(struct policydb *p, void *fp) nel = le32_to_cpu(buf[0]); for (i = 0; i < nel; i++) { - ft = NULL; otype = NULL; name = NULL; -- cgit v1.1 From 57152a5be08e240654993984a0f6e54254882626 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 19:35:59 +0100 Subject: selinux: Return directly after a failed next_entry() in range_read() Return directly after a call of the function "next_entry" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 7131251..6c09301 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1852,7 +1852,7 @@ static int range_read(struct policydb *p, void *fp) rc = next_entry(buf, fp, sizeof(u32)); if (rc) - goto out; + return rc; nel = le32_to_cpu(buf[0]); for (i = 0; i < nel; i++) { -- cgit v1.1 From 9c312e79d6afb673114ebe7aabd5594e79827eea Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 20:40:12 +0100 Subject: selinux: Delete an unnecessary variable initialisation in range_read() The local variable "rt" will be set to an appropriate pointer a bit later. Thus omit the explicit initialisation at the beginning which became unnecessary with a previous update step. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 6c09301..a838939 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1841,7 +1841,7 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name) static int range_read(struct policydb *p, void *fp) { - struct range_trans *rt = NULL; + struct range_trans *rt; struct mls_range *r = NULL; int i, rc; __le32 buf[2]; -- cgit v1.1 From 3dfc9b02864b19f4dab376f14479ee4ad1de6c9e Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 22 Mar 2017 19:46:19 +0900 Subject: LSM: Initialize security_hook_heads upon registration. "struct security_hook_heads" is an array of "struct list_head" where elements can be initialized just before registration. There is no need to waste 350+ lines for initialization. Let's initialize "struct security_hook_heads" just before registration. Signed-off-by: Tetsuo Handa Acked-by: Kees Cook Cc: John Johansen Cc: Kees Cook Cc: Paul Moore Cc: Stephen Smalley Cc: Casey Schaufler Cc: James Morris Signed-off-by: James Morris --- security/security.c | 361 +--------------------------------------------------- 1 file changed, 7 insertions(+), 354 deletions(-) (limited to 'security') diff --git a/security/security.c b/security/security.c index d6d18a3..2f15488 100644 --- a/security/security.c +++ b/security/security.c @@ -32,6 +32,7 @@ /* Maximum number of letters for an LSM name string */ #define SECURITY_NAME_MAX 10 +struct security_hook_heads security_hook_heads __lsm_ro_after_init; char *lsm_names; /* Boot-time LSM user choice */ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = @@ -54,6 +55,12 @@ static void __init do_security_initcalls(void) */ int __init security_init(void) { + int i; + struct list_head *list = (struct list_head *) &security_hook_heads; + + for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct list_head); + i++) + INIT_LIST_HEAD(&list[i]); pr_info("Security Framework initialized\n"); /* @@ -1627,357 +1634,3 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, actx); } #endif /* CONFIG_AUDIT */ - -struct security_hook_heads security_hook_heads __lsm_ro_after_init = { - .binder_set_context_mgr = - LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr), - .binder_transaction = - LIST_HEAD_INIT(security_hook_heads.binder_transaction), - .binder_transfer_binder = - LIST_HEAD_INIT(security_hook_heads.binder_transfer_binder), - .binder_transfer_file = - LIST_HEAD_INIT(security_hook_heads.binder_transfer_file), - - .ptrace_access_check = - LIST_HEAD_INIT(security_hook_heads.ptrace_access_check), - .ptrace_traceme = - LIST_HEAD_INIT(security_hook_heads.ptrace_traceme), - .capget = LIST_HEAD_INIT(security_hook_heads.capget), - .capset = LIST_HEAD_INIT(security_hook_heads.capset), - .capable = LIST_HEAD_INIT(security_hook_heads.capable), - .quotactl = LIST_HEAD_INIT(security_hook_heads.quotactl), - .quota_on = LIST_HEAD_INIT(security_hook_heads.quota_on), - .syslog = LIST_HEAD_INIT(security_hook_heads.syslog), - .settime = LIST_HEAD_INIT(security_hook_heads.settime), - .vm_enough_memory = - LIST_HEAD_INIT(security_hook_heads.vm_enough_memory), - .bprm_set_creds = - LIST_HEAD_INIT(security_hook_heads.bprm_set_creds), - .bprm_check_security = - LIST_HEAD_INIT(security_hook_heads.bprm_check_security), - .bprm_secureexec = - LIST_HEAD_INIT(security_hook_heads.bprm_secureexec), - .bprm_committing_creds = - LIST_HEAD_INIT(security_hook_heads.bprm_committing_creds), - .bprm_committed_creds = - LIST_HEAD_INIT(security_hook_heads.bprm_committed_creds), - .sb_alloc_security = - LIST_HEAD_INIT(security_hook_heads.sb_alloc_security), - .sb_free_security = - LIST_HEAD_INIT(security_hook_heads.sb_free_security), - .sb_copy_data = LIST_HEAD_INIT(security_hook_heads.sb_copy_data), - .sb_remount = LIST_HEAD_INIT(security_hook_heads.sb_remount), - .sb_kern_mount = - LIST_HEAD_INIT(security_hook_heads.sb_kern_mount), - .sb_show_options = - LIST_HEAD_INIT(security_hook_heads.sb_show_options), - .sb_statfs = LIST_HEAD_INIT(security_hook_heads.sb_statfs), - .sb_mount = LIST_HEAD_INIT(security_hook_heads.sb_mount), - .sb_umount = LIST_HEAD_INIT(security_hook_heads.sb_umount), - .sb_pivotroot = LIST_HEAD_INIT(security_hook_heads.sb_pivotroot), - .sb_set_mnt_opts = - LIST_HEAD_INIT(security_hook_heads.sb_set_mnt_opts), - .sb_clone_mnt_opts = - LIST_HEAD_INIT(security_hook_heads.sb_clone_mnt_opts), - .sb_parse_opts_str = - LIST_HEAD_INIT(security_hook_heads.sb_parse_opts_str), - .dentry_init_security = - LIST_HEAD_INIT(security_hook_heads.dentry_init_security), - .dentry_create_files_as = - LIST_HEAD_INIT(security_hook_heads.dentry_create_files_as), -#ifdef CONFIG_SECURITY_PATH - .path_unlink = LIST_HEAD_INIT(security_hook_heads.path_unlink), - .path_mkdir = LIST_HEAD_INIT(security_hook_heads.path_mkdir), - .path_rmdir = LIST_HEAD_INIT(security_hook_heads.path_rmdir), - .path_mknod = LIST_HEAD_INIT(security_hook_heads.path_mknod), - .path_truncate = - LIST_HEAD_INIT(security_hook_heads.path_truncate), - .path_symlink = LIST_HEAD_INIT(security_hook_heads.path_symlink), - .path_link = LIST_HEAD_INIT(security_hook_heads.path_link), - .path_rename = LIST_HEAD_INIT(security_hook_heads.path_rename), - .path_chmod = LIST_HEAD_INIT(security_hook_heads.path_chmod), - .path_chown = LIST_HEAD_INIT(security_hook_heads.path_chown), - .path_chroot = LIST_HEAD_INIT(security_hook_heads.path_chroot), -#endif - .inode_alloc_security = - LIST_HEAD_INIT(security_hook_heads.inode_alloc_security), - .inode_free_security = - LIST_HEAD_INIT(security_hook_heads.inode_free_security), - .inode_init_security = - LIST_HEAD_INIT(security_hook_heads.inode_init_security), - .inode_create = LIST_HEAD_INIT(security_hook_heads.inode_create), - .inode_link = LIST_HEAD_INIT(security_hook_heads.inode_link), - .inode_unlink = LIST_HEAD_INIT(security_hook_heads.inode_unlink), - .inode_symlink = - LIST_HEAD_INIT(security_hook_heads.inode_symlink), - .inode_mkdir = LIST_HEAD_INIT(security_hook_heads.inode_mkdir), - .inode_rmdir = LIST_HEAD_INIT(security_hook_heads.inode_rmdir), - .inode_mknod = LIST_HEAD_INIT(security_hook_heads.inode_mknod), - .inode_rename = LIST_HEAD_INIT(security_hook_heads.inode_rename), - .inode_readlink = - LIST_HEAD_INIT(security_hook_heads.inode_readlink), - .inode_follow_link = - LIST_HEAD_INIT(security_hook_heads.inode_follow_link), - .inode_permission = - LIST_HEAD_INIT(security_hook_heads.inode_permission), - .inode_setattr = - LIST_HEAD_INIT(security_hook_heads.inode_setattr), - .inode_getattr = - LIST_HEAD_INIT(security_hook_heads.inode_getattr), - .inode_setxattr = - LIST_HEAD_INIT(security_hook_heads.inode_setxattr), - .inode_post_setxattr = - LIST_HEAD_INIT(security_hook_heads.inode_post_setxattr), - .inode_getxattr = - LIST_HEAD_INIT(security_hook_heads.inode_getxattr), - .inode_listxattr = - LIST_HEAD_INIT(security_hook_heads.inode_listxattr), - .inode_removexattr = - LIST_HEAD_INIT(security_hook_heads.inode_removexattr), - .inode_need_killpriv = - LIST_HEAD_INIT(security_hook_heads.inode_need_killpriv), - .inode_killpriv = - LIST_HEAD_INIT(security_hook_heads.inode_killpriv), - .inode_getsecurity = - LIST_HEAD_INIT(security_hook_heads.inode_getsecurity), - .inode_setsecurity = - LIST_HEAD_INIT(security_hook_heads.inode_setsecurity), - .inode_listsecurity = - LIST_HEAD_INIT(security_hook_heads.inode_listsecurity), - .inode_getsecid = - LIST_HEAD_INIT(security_hook_heads.inode_getsecid), - .inode_copy_up = - LIST_HEAD_INIT(security_hook_heads.inode_copy_up), - .inode_copy_up_xattr = - LIST_HEAD_INIT(security_hook_heads.inode_copy_up_xattr), - .file_permission = - LIST_HEAD_INIT(security_hook_heads.file_permission), - .file_alloc_security = - LIST_HEAD_INIT(security_hook_heads.file_alloc_security), - .file_free_security = - LIST_HEAD_INIT(security_hook_heads.file_free_security), - .file_ioctl = LIST_HEAD_INIT(security_hook_heads.file_ioctl), - .mmap_addr = LIST_HEAD_INIT(security_hook_heads.mmap_addr), - .mmap_file = LIST_HEAD_INIT(security_hook_heads.mmap_file), - .file_mprotect = - LIST_HEAD_INIT(security_hook_heads.file_mprotect), - .file_lock = LIST_HEAD_INIT(security_hook_heads.file_lock), - .file_fcntl = LIST_HEAD_INIT(security_hook_heads.file_fcntl), - .file_set_fowner = - LIST_HEAD_INIT(security_hook_heads.file_set_fowner), - .file_send_sigiotask = - LIST_HEAD_INIT(security_hook_heads.file_send_sigiotask), - .file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive), - .file_open = LIST_HEAD_INIT(security_hook_heads.file_open), - .task_create = LIST_HEAD_INIT(security_hook_heads.task_create), - .task_free = LIST_HEAD_INIT(security_hook_heads.task_free), - .cred_alloc_blank = - LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank), - .cred_free = LIST_HEAD_INIT(security_hook_heads.cred_free), - .cred_prepare = LIST_HEAD_INIT(security_hook_heads.cred_prepare), - .cred_transfer = - LIST_HEAD_INIT(security_hook_heads.cred_transfer), - .kernel_act_as = - LIST_HEAD_INIT(security_hook_heads.kernel_act_as), - .kernel_create_files_as = - LIST_HEAD_INIT(security_hook_heads.kernel_create_files_as), - .kernel_module_request = - LIST_HEAD_INIT(security_hook_heads.kernel_module_request), - .kernel_read_file = - LIST_HEAD_INIT(security_hook_heads.kernel_read_file), - .kernel_post_read_file = - LIST_HEAD_INIT(security_hook_heads.kernel_post_read_file), - .task_fix_setuid = - LIST_HEAD_INIT(security_hook_heads.task_fix_setuid), - .task_setpgid = LIST_HEAD_INIT(security_hook_heads.task_setpgid), - .task_getpgid = LIST_HEAD_INIT(security_hook_heads.task_getpgid), - .task_getsid = LIST_HEAD_INIT(security_hook_heads.task_getsid), - .task_getsecid = - LIST_HEAD_INIT(security_hook_heads.task_getsecid), - .task_setnice = LIST_HEAD_INIT(security_hook_heads.task_setnice), - .task_setioprio = - LIST_HEAD_INIT(security_hook_heads.task_setioprio), - .task_getioprio = - LIST_HEAD_INIT(security_hook_heads.task_getioprio), - .task_prlimit = - LIST_HEAD_INIT(security_hook_heads.task_prlimit), - .task_setrlimit = - LIST_HEAD_INIT(security_hook_heads.task_setrlimit), - .task_setscheduler = - LIST_HEAD_INIT(security_hook_heads.task_setscheduler), - .task_getscheduler = - LIST_HEAD_INIT(security_hook_heads.task_getscheduler), - .task_movememory = - LIST_HEAD_INIT(security_hook_heads.task_movememory), - .task_kill = LIST_HEAD_INIT(security_hook_heads.task_kill), - .task_prctl = LIST_HEAD_INIT(security_hook_heads.task_prctl), - .task_to_inode = - LIST_HEAD_INIT(security_hook_heads.task_to_inode), - .ipc_permission = - LIST_HEAD_INIT(security_hook_heads.ipc_permission), - .ipc_getsecid = LIST_HEAD_INIT(security_hook_heads.ipc_getsecid), - .msg_msg_alloc_security = - LIST_HEAD_INIT(security_hook_heads.msg_msg_alloc_security), - .msg_msg_free_security = - LIST_HEAD_INIT(security_hook_heads.msg_msg_free_security), - .msg_queue_alloc_security = - LIST_HEAD_INIT(security_hook_heads.msg_queue_alloc_security), - .msg_queue_free_security = - LIST_HEAD_INIT(security_hook_heads.msg_queue_free_security), - .msg_queue_associate = - LIST_HEAD_INIT(security_hook_heads.msg_queue_associate), - .msg_queue_msgctl = - LIST_HEAD_INIT(security_hook_heads.msg_queue_msgctl), - .msg_queue_msgsnd = - LIST_HEAD_INIT(security_hook_heads.msg_queue_msgsnd), - .msg_queue_msgrcv = - LIST_HEAD_INIT(security_hook_heads.msg_queue_msgrcv), - .shm_alloc_security = - LIST_HEAD_INIT(security_hook_heads.shm_alloc_security), - .shm_free_security = - LIST_HEAD_INIT(security_hook_heads.shm_free_security), - .shm_associate = - LIST_HEAD_INIT(security_hook_heads.shm_associate), - .shm_shmctl = LIST_HEAD_INIT(security_hook_heads.shm_shmctl), - .shm_shmat = LIST_HEAD_INIT(security_hook_heads.shm_shmat), - .sem_alloc_security = - LIST_HEAD_INIT(security_hook_heads.sem_alloc_security), - .sem_free_security = - LIST_HEAD_INIT(security_hook_heads.sem_free_security), - .sem_associate = - LIST_HEAD_INIT(security_hook_heads.sem_associate), - .sem_semctl = LIST_HEAD_INIT(security_hook_heads.sem_semctl), - .sem_semop = LIST_HEAD_INIT(security_hook_heads.sem_semop), - .netlink_send = LIST_HEAD_INIT(security_hook_heads.netlink_send), - .d_instantiate = - LIST_HEAD_INIT(security_hook_heads.d_instantiate), - .getprocattr = LIST_HEAD_INIT(security_hook_heads.getprocattr), - .setprocattr = LIST_HEAD_INIT(security_hook_heads.setprocattr), - .ismaclabel = LIST_HEAD_INIT(security_hook_heads.ismaclabel), - .secid_to_secctx = - LIST_HEAD_INIT(security_hook_heads.secid_to_secctx), - .secctx_to_secid = - LIST_HEAD_INIT(security_hook_heads.secctx_to_secid), - .release_secctx = - LIST_HEAD_INIT(security_hook_heads.release_secctx), - .inode_invalidate_secctx = - LIST_HEAD_INIT(security_hook_heads.inode_invalidate_secctx), - .inode_notifysecctx = - LIST_HEAD_INIT(security_hook_heads.inode_notifysecctx), - .inode_setsecctx = - LIST_HEAD_INIT(security_hook_heads.inode_setsecctx), - .inode_getsecctx = - LIST_HEAD_INIT(security_hook_heads.inode_getsecctx), -#ifdef CONFIG_SECURITY_NETWORK - .unix_stream_connect = - LIST_HEAD_INIT(security_hook_heads.unix_stream_connect), - .unix_may_send = - LIST_HEAD_INIT(security_hook_heads.unix_may_send), - .socket_create = - LIST_HEAD_INIT(security_hook_heads.socket_create), - .socket_post_create = - LIST_HEAD_INIT(security_hook_heads.socket_post_create), - .socket_bind = LIST_HEAD_INIT(security_hook_heads.socket_bind), - .socket_connect = - LIST_HEAD_INIT(security_hook_heads.socket_connect), - .socket_listen = - LIST_HEAD_INIT(security_hook_heads.socket_listen), - .socket_accept = - LIST_HEAD_INIT(security_hook_heads.socket_accept), - .socket_sendmsg = - LIST_HEAD_INIT(security_hook_heads.socket_sendmsg), - .socket_recvmsg = - LIST_HEAD_INIT(security_hook_heads.socket_recvmsg), - .socket_getsockname = - LIST_HEAD_INIT(security_hook_heads.socket_getsockname), - .socket_getpeername = - LIST_HEAD_INIT(security_hook_heads.socket_getpeername), - .socket_getsockopt = - LIST_HEAD_INIT(security_hook_heads.socket_getsockopt), - .socket_setsockopt = - LIST_HEAD_INIT(security_hook_heads.socket_setsockopt), - .socket_shutdown = - LIST_HEAD_INIT(security_hook_heads.socket_shutdown), - .socket_sock_rcv_skb = - LIST_HEAD_INIT(security_hook_heads.socket_sock_rcv_skb), - .socket_getpeersec_stream = - LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_stream), - .socket_getpeersec_dgram = - LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_dgram), - .sk_alloc_security = - LIST_HEAD_INIT(security_hook_heads.sk_alloc_security), - .sk_free_security = - LIST_HEAD_INIT(security_hook_heads.sk_free_security), - .sk_clone_security = - LIST_HEAD_INIT(security_hook_heads.sk_clone_security), - .sk_getsecid = LIST_HEAD_INIT(security_hook_heads.sk_getsecid), - .sock_graft = LIST_HEAD_INIT(security_hook_heads.sock_graft), - .inet_conn_request = - LIST_HEAD_INIT(security_hook_heads.inet_conn_request), - .inet_csk_clone = - LIST_HEAD_INIT(security_hook_heads.inet_csk_clone), - .inet_conn_established = - LIST_HEAD_INIT(security_hook_heads.inet_conn_established), - .secmark_relabel_packet = - LIST_HEAD_INIT(security_hook_heads.secmark_relabel_packet), - .secmark_refcount_inc = - LIST_HEAD_INIT(security_hook_heads.secmark_refcount_inc), - .secmark_refcount_dec = - LIST_HEAD_INIT(security_hook_heads.secmark_refcount_dec), - .req_classify_flow = - LIST_HEAD_INIT(security_hook_heads.req_classify_flow), - .tun_dev_alloc_security = - LIST_HEAD_INIT(security_hook_heads.tun_dev_alloc_security), - .tun_dev_free_security = - LIST_HEAD_INIT(security_hook_heads.tun_dev_free_security), - .tun_dev_create = - LIST_HEAD_INIT(security_hook_heads.tun_dev_create), - .tun_dev_attach_queue = - LIST_HEAD_INIT(security_hook_heads.tun_dev_attach_queue), - .tun_dev_attach = - LIST_HEAD_INIT(security_hook_heads.tun_dev_attach), - .tun_dev_open = LIST_HEAD_INIT(security_hook_heads.tun_dev_open), -#endif /* CONFIG_SECURITY_NETWORK */ -#ifdef CONFIG_SECURITY_NETWORK_XFRM - .xfrm_policy_alloc_security = - LIST_HEAD_INIT(security_hook_heads.xfrm_policy_alloc_security), - .xfrm_policy_clone_security = - LIST_HEAD_INIT(security_hook_heads.xfrm_policy_clone_security), - .xfrm_policy_free_security = - LIST_HEAD_INIT(security_hook_heads.xfrm_policy_free_security), - .xfrm_policy_delete_security = - LIST_HEAD_INIT(security_hook_heads.xfrm_policy_delete_security), - .xfrm_state_alloc = - LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc), - .xfrm_state_alloc_acquire = - LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc_acquire), - .xfrm_state_free_security = - LIST_HEAD_INIT(security_hook_heads.xfrm_state_free_security), - .xfrm_state_delete_security = - LIST_HEAD_INIT(security_hook_heads.xfrm_state_delete_security), - .xfrm_policy_lookup = - LIST_HEAD_INIT(security_hook_heads.xfrm_policy_lookup), - .xfrm_state_pol_flow_match = - LIST_HEAD_INIT(security_hook_heads.xfrm_state_pol_flow_match), - .xfrm_decode_session = - LIST_HEAD_INIT(security_hook_heads.xfrm_decode_session), -#endif /* CONFIG_SECURITY_NETWORK_XFRM */ -#ifdef CONFIG_KEYS - .key_alloc = LIST_HEAD_INIT(security_hook_heads.key_alloc), - .key_free = LIST_HEAD_INIT(security_hook_heads.key_free), - .key_permission = - LIST_HEAD_INIT(security_hook_heads.key_permission), - .key_getsecurity = - LIST_HEAD_INIT(security_hook_heads.key_getsecurity), -#endif /* CONFIG_KEYS */ -#ifdef CONFIG_AUDIT - .audit_rule_init = - LIST_HEAD_INIT(security_hook_heads.audit_rule_init), - .audit_rule_known = - LIST_HEAD_INIT(security_hook_heads.audit_rule_known), - .audit_rule_match = - LIST_HEAD_INIT(security_hook_heads.audit_rule_match), - .audit_rule_free = - LIST_HEAD_INIT(security_hook_heads.audit_rule_free), -#endif /* CONFIG_AUDIT */ -}; -- cgit v1.1 From e4e55b47ed9ae2c05ff062601ff6dacbe9dc4775 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 24 Mar 2017 20:46:33 +0900 Subject: LSM: Revive security_task_alloc() hook and per "struct task_struct" security blob. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We switched from "struct task_struct"->security to "struct cred"->security in Linux 2.6.29. But not all LSM modules were happy with that change. TOMOYO LSM module is an example which want to use per "struct task_struct" security blob, for TOMOYO's security context is defined based on "struct task_struct" rather than "struct cred". AppArmor LSM module is another example which want to use it, for AppArmor is currently abusing the cred a little bit to store the change_hat and setexeccon info. Although security_task_free() hook was revived in Linux 3.4 because Yama LSM module wanted to release per "struct task_struct" security blob, security_task_alloc() hook and "struct task_struct"->security field were not revived. Nowadays, we are getting proposals of lightweight LSM modules which want to use per "struct task_struct" security blob. We are already allowing multiple concurrent LSM modules (up to one fully armored module which uses "struct cred"->security field or exclusive hooks like security_xfrm_state_pol_flow_match(), plus unlimited number of lightweight modules which do not use "struct cred"->security nor exclusive hooks) as long as they are built into the kernel. But this patch does not implement variable length "struct task_struct"->security field which will become needed when multiple LSM modules want to use "struct task_struct"-> security field. Although it won't be difficult to implement variable length "struct task_struct"->security field, let's think about it after we merged this patch. Signed-off-by: Tetsuo Handa Acked-by: John Johansen Acked-by: Serge Hallyn Acked-by: Casey Schaufler Tested-by: Djalal Harouni Acked-by: José Bollo Cc: Paul Moore Cc: Stephen Smalley Cc: Eric Paris Cc: Kees Cook Cc: James Morris Cc: José Bollo Signed-off-by: James Morris --- security/security.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'security') diff --git a/security/security.c b/security/security.c index 2f15488..549bddc 100644 --- a/security/security.c +++ b/security/security.c @@ -937,6 +937,11 @@ int security_task_create(unsigned long clone_flags) return call_int_hook(task_create, 0, clone_flags); } +int security_task_alloc(struct task_struct *task, unsigned long clone_flags) +{ + return call_int_hook(task_alloc, 0, task, clone_flags); +} + void security_task_free(struct task_struct *task) { call_void_hook(task_free, task); -- cgit v1.1 From 7f6d0ad8b771a4936f448180de3bbfad92be34dc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 21:20:43 +0100 Subject: selinux: Return directly after a failed kzalloc() in cat_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index a838939..36285d1 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1637,10 +1637,9 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[3]; u32 len; - rc = -ENOMEM; catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC); if (!catdatum) - goto bad; + return -ENOMEM; rc = next_entry(buf, fp, sizeof buf); if (rc) -- cgit v1.1 From 3c354d7d7bd5e788c3d94969e4a85648d29d9d12 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 21:42:02 +0100 Subject: selinux: Return directly after a failed kzalloc() in sens_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 36285d1..aa1ce7c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1595,10 +1595,9 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[2]; u32 len; - rc = -ENOMEM; levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC); if (!levdatum) - goto bad; + return -ENOMEM; rc = next_entry(buf, fp, sizeof buf); if (rc) -- cgit v1.1 From b5921191005d050d55cf4f3b10f60110f7ed2c24 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 21:52:55 +0100 Subject: selinux: Improve another size determination in sens_read() Replace the specification of a data type by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index aa1ce7c..4759c22 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1611,7 +1611,7 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) goto bad; rc = -ENOMEM; - levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); + levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_ATOMIC); if (!levdatum->level) goto bad; -- cgit v1.1 From 4bd9f07b89f1a300f96b4863c3a8a4ec36991930 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 22:08:22 +0100 Subject: selinux: Return directly after a failed kzalloc() in user_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 4759c22..9a90953 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1544,10 +1544,9 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[3]; u32 len; - rc = -ENOMEM; usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); if (!usrdatum) - goto bad; + return -ENOMEM; if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) to_read = 3; -- cgit v1.1 From 549fe69ee5c7a7f55c34555032961a2265e6e713 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 22:15:54 +0100 Subject: selinux: Return directly after a failed kzalloc() in type_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 9a90953..fd58de5 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1469,10 +1469,9 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[4]; u32 len; - rc = -ENOMEM; typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); if (!typdatum) - goto bad; + return -ENOMEM; if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) to_read = 4; -- cgit v1.1 From ea6e2f7d12921f336def7398805ee3b1619e2f4b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 22:20:25 +0100 Subject: selinux: Return directly after a failed kzalloc() in role_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index fd58de5..30f29c6 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1412,10 +1412,9 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[3]; u32 len; - rc = -ENOMEM; role = kzalloc(sizeof(*role), GFP_KERNEL); if (!role) - goto bad; + return -ENOMEM; if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) to_read = 3; -- cgit v1.1 From df4a14dfb484f95d81126e481e66b6e22eec49e8 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 14 Jan 2017 22:30:51 +0100 Subject: selinux: Return directly after a failed kzalloc() in class_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 30f29c6..edf173e 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1318,10 +1318,9 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) u32 len, len2, ncons, nel; int i, rc; - rc = -ENOMEM; cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL); if (!cladatum) - goto bad; + return -ENOMEM; rc = next_entry(buf, fp, sizeof(u32)*6); if (rc) -- cgit v1.1 From 442ca4d656645505346017c37ac137cde680bf38 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 15 Jan 2017 11:15:19 +0100 Subject: selinux: Return directly after a failed kzalloc() in common_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index edf173e..99ee0ee 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1152,10 +1152,9 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) u32 len, nel; int i, rc; - rc = -ENOMEM; comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL); if (!comdatum) - goto bad; + return -ENOMEM; rc = next_entry(buf, fp, sizeof buf); if (rc) -- cgit v1.1 From 7befb7514e5d53026e9fe4a6548f118a65a20a4f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 15 Jan 2017 11:20:13 +0100 Subject: selinux: Return directly after a failed kzalloc() in perm_read() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 99ee0ee..5ca2d26e 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1118,10 +1118,9 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[2]; u32 len; - rc = -ENOMEM; perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL); if (!perdatum) - goto bad; + return -ENOMEM; rc = next_entry(buf, fp, sizeof buf); if (rc) -- cgit v1.1 From ebd2b47ba52760e9653456ba19032f79d734a343 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 15 Jan 2017 12:10:09 +0100 Subject: selinux: Return directly after a failed kzalloc() in roles_init() Return directly after a call of the function "kzalloc" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 5ca2d26e..658247f 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -178,10 +178,9 @@ static int roles_init(struct policydb *p) int rc; struct role_datum *role; - rc = -ENOMEM; role = kzalloc(sizeof(*role), GFP_KERNEL); if (!role) - goto out; + return -ENOMEM; rc = -EINVAL; role->value = ++p->p_roles.nprim; -- cgit v1.1 From b380f783772eeb66a0da85549a85aadbe5f8e76d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 15 Jan 2017 13:13:19 +0100 Subject: selinux: Use kmalloc_array() in sidtab_init() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/sidtab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index 5840a35..c9533b2 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -18,7 +18,7 @@ int sidtab_init(struct sidtab *s) { int i; - s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC); + s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC); if (!s->htable) return -ENOMEM; for (i = 0; i < SIDTAB_SIZE; i++) -- cgit v1.1 From 8ee4586ca5fe6c2a00f6a39f828f54c8f6cda472 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 15 Jan 2017 13:30:20 +0100 Subject: selinux: Adjust two checks for null pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The script "checkpatch.pl" pointed information out like the following. Comparison to NULL could be written !… Thus fix affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/ss/sidtab.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index c9533b2..f6915f2 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -54,7 +54,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) } newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC); - if (newnode == NULL) { + if (!newnode) { rc = -ENOMEM; goto out; } @@ -98,7 +98,7 @@ static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) if (force && cur && sid == cur->sid && cur->context.len) return &cur->context; - if (cur == NULL || sid != cur->sid || cur->context.len) { + if (!cur || sid != cur->sid || cur->context.len) { /* Remap invalid SIDs to the unlabeled SID. */ sid = SECINITSID_UNLABELED; hvalue = SIDTAB_HASH(sid); -- cgit v1.1 From 710a0647ba955abd25460c36a09d80fdbe878273 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 15 Jan 2017 14:04:53 +0100 Subject: selinuxfs: Use seq_puts() in sel_avc_stats_seq_show() A string which did not contain data format specifications should be put into a sequence. Thus use the corresponding function "seq_puts". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Paul Moore --- security/selinux/selinuxfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'security') diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index cb3fd98..ce71718 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1456,10 +1456,10 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v) { struct avc_cache_stats *st = v; - if (v == SEQ_START_TOKEN) - seq_printf(seq, "lookups hits misses allocations reclaims " - "frees\n"); - else { + if (v == SEQ_START_TOKEN) { + seq_puts(seq, + "lookups hits misses allocations reclaims frees\n"); + } else { unsigned int lookups = st->lookups; unsigned int misses = st->misses; unsigned int hits = lookups - misses; -- cgit v1.1 From 342e91578eb6909529bc7095964cd44b9c057c4e Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 16 Mar 2017 15:26:52 -0700 Subject: selinux: Remove unnecessary check of array base in selinux_set_mapping() 'perms' will never be NULL since it isn't a plain pointer but an array of u32 values. This fixes the following warning when building with clang: security/selinux/ss/services.c:158:16: error: address of array 'p_in->perms' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] while (p_in->perms && p_in->perms[k]) { Signed-off-by: Matthias Kaehlcke Signed-off-by: Paul Moore --- security/selinux/ss/services.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b4aa491..60d9b02 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -157,7 +157,7 @@ static int selinux_set_mapping(struct policydb *pol, } k = 0; - while (p_in->perms && p_in->perms[k]) { + while (p_in->perms[k]) { /* An empty permission string skips ahead */ if (!*p_in->perms[k]) { k++; -- cgit v1.1 From 8291798dcf059cdc5e55a59b2c4ad70ae14508c2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 29 Mar 2017 16:52:58 -0700 Subject: TOMOYO: Use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Acked-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/file.c | 12 ++++++------ security/tomoyo/tomoyo.c | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'security') diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 7041a58..223f21f 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -692,7 +692,7 @@ int tomoyo_path_number_perm(const u8 type, const struct path *path, { struct tomoyo_request_info r; struct tomoyo_obj_info obj = { - .path1 = *path, + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, }; int error = -ENOMEM; struct tomoyo_path_info buf; @@ -740,7 +740,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct tomoyo_path_info buf; struct tomoyo_request_info r; struct tomoyo_obj_info obj = { - .path1 = *path, + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, }; int idx; @@ -786,7 +786,7 @@ int tomoyo_path_perm(const u8 operation, const struct path *path, const char *ta { struct tomoyo_request_info r; struct tomoyo_obj_info obj = { - .path1 = *path, + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, }; int error; struct tomoyo_path_info buf; @@ -843,7 +843,7 @@ int tomoyo_mkdev_perm(const u8 operation, const struct path *path, { struct tomoyo_request_info r; struct tomoyo_obj_info obj = { - .path1 = *path, + .path1 = { .mnt = path->mnt, .dentry = path->dentry }, }; int error = -ENOMEM; struct tomoyo_path_info buf; @@ -890,8 +890,8 @@ int tomoyo_path2_perm(const u8 operation, const struct path *path1, struct tomoyo_path_info buf2; struct tomoyo_request_info r; struct tomoyo_obj_info obj = { - .path1 = *path1, - .path2 = *path2, + .path1 = { .mnt = path1->mnt, .dentry = path1->dentry }, + .path2 = { .mnt = path2->mnt, .dentry = path2->dentry } }; int idx; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index b5fb930..130b4fa 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -165,7 +165,7 @@ static int tomoyo_path_truncate(const struct path *path) */ static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); } @@ -181,7 +181,7 @@ static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, umode_t mode) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, mode & S_IALLUGO); } @@ -196,7 +196,7 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry, */ static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); } @@ -212,7 +212,7 @@ static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, const char *old_name) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); } @@ -229,7 +229,7 @@ static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry, static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, umode_t mode, unsigned int dev) { - struct path path = { parent->mnt, dentry }; + struct path path = { .mnt = parent->mnt, .dentry = dentry }; int type = TOMOYO_TYPE_CREATE; const unsigned int perm = mode & S_IALLUGO; @@ -268,8 +268,8 @@ static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry, static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) { - struct path path1 = { new_dir->mnt, old_dentry }; - struct path path2 = { new_dir->mnt, new_dentry }; + struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; + struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); } @@ -288,8 +288,8 @@ static int tomoyo_path_rename(const struct path *old_parent, const struct path *new_parent, struct dentry *new_dentry) { - struct path path1 = { old_parent->mnt, old_dentry }; - struct path path2 = { new_parent->mnt, new_dentry }; + struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; + struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); } @@ -417,7 +417,7 @@ static int tomoyo_sb_mount(const char *dev_name, const struct path *path, */ static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) { - struct path path = { mnt, mnt->mnt_root }; + struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); } -- cgit v1.1 From cae303df3f379f04ce7efadb2e30de460918b302 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 31 Mar 2017 18:21:18 +0300 Subject: selinux: Fix an uninitialized variable bug We removed this initialization as a cleanup but it is probably required. The concern is that "nel" can be zero. I'm not an expert on SELinux code but I think it looks possible to write an SELinux policy which triggers this bug. GCC doesn't catch this, but my static checker does. Fixes: 9c312e79d6af ("selinux: Delete an unnecessary variable initialisation in range_read()") Signed-off-by: Dan Carpenter Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 658247f..0080122 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1832,7 +1832,7 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name) static int range_read(struct policydb *p, void *fp) { - struct range_trans *rt; + struct range_trans *rt = NULL; struct mls_range *r = NULL; int i, rc; __le32 buf[2]; -- cgit v1.1 From fff292914d3a2f1efd05ca71c2ba72a3c663201e Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Fri, 31 Mar 2017 15:20:48 +0300 Subject: security, keys: convert key.usage from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Acked-by: David Howells Signed-off-by: James Morris --- security/keys/gc.c | 2 +- security/keys/key.c | 6 +++--- security/keys/keyring.c | 8 ++++---- security/keys/proc.c | 2 +- security/keys/request_key_auth.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'security') diff --git a/security/keys/gc.c b/security/keys/gc.c index addf060..4478925 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -220,7 +220,7 @@ continue_scanning: key = rb_entry(cursor, struct key, serial_node); cursor = rb_next(cursor); - if (atomic_read(&key->usage) == 0) + if (refcount_read(&key->usage) == 0) goto found_unreferenced_key; if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { diff --git a/security/keys/key.c b/security/keys/key.c index 346fbf2..ff92443 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -285,7 +285,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, if (!key->index_key.description) goto no_memory_3; - atomic_set(&key->usage, 1); + refcount_set(&key->usage, 1); init_rwsem(&key->sem); lockdep_set_class(&key->sem, &type->lock_class); key->index_key.type = type; @@ -621,7 +621,7 @@ void key_put(struct key *key) if (key) { key_check(key); - if (atomic_dec_and_test(&key->usage)) + if (refcount_dec_and_test(&key->usage)) schedule_work(&key_gc_work); } } @@ -656,7 +656,7 @@ not_found: found: /* pretend it doesn't exist if it is awaiting deletion */ - if (atomic_read(&key->usage) == 0) + if (refcount_read(&key->usage) == 0) goto not_found; /* this races with key_put(), but that doesn't matter since key_put() diff --git a/security/keys/keyring.c b/security/keys/keyring.c index c91e4e0..3d95f7d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -1033,7 +1033,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) /* we've got a match but we might end up racing with * key_cleanup() if the keyring is currently 'dead' * (ie. it has a zero usage count) */ - if (!atomic_inc_not_zero(&keyring->usage)) + if (!refcount_inc_not_zero(&keyring->usage)) continue; keyring->last_used_at = current_kernel_time().tv_sec; goto out; @@ -1250,14 +1250,14 @@ int key_link(struct key *keyring, struct key *key) struct assoc_array_edit *edit; int ret; - kenter("{%d,%d}", keyring->serial, atomic_read(&keyring->usage)); + kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage)); key_check(keyring); key_check(key); ret = __key_link_begin(keyring, &key->index_key, &edit); if (ret == 0) { - kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage)); + kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage)); ret = __key_link_check_restriction(keyring, key); if (ret == 0) ret = __key_link_check_live_key(keyring, key); @@ -1266,7 +1266,7 @@ int key_link(struct key *keyring, struct key *key) __key_link_end(keyring, &key->index_key, edit); } - kleave(" = %d {%d,%d}", ret, keyring->serial, atomic_read(&keyring->usage)); + kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage)); return ret; } EXPORT_SYMBOL(key_link); diff --git a/security/keys/proc.c b/security/keys/proc.c index b9f531c..69199f1 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -252,7 +252,7 @@ static int proc_keys_show(struct seq_file *m, void *v) showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), showflag(key, 'N', KEY_FLAG_NEGATIVE), showflag(key, 'i', KEY_FLAG_INVALIDATED), - atomic_read(&key->usage), + refcount_read(&key->usage), xbuf, key->perm, from_kuid_munged(seq_user_ns(m), key->uid), diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 6bbe2f5..0f06215 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -213,7 +213,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, if (ret < 0) goto error_inst; - kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); + kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage)); return authkey; auth_key_revoked: -- cgit v1.1 From ddb99e118e37f324a4be65a411bb60ae62795cf9 Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Fri, 31 Mar 2017 15:20:49 +0300 Subject: security, keys: convert key_user.usage from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Acked-by: David Howells Signed-off-by: James Morris --- security/keys/internal.h | 3 ++- security/keys/key.c | 6 +++--- security/keys/proc.c | 2 +- security/keys/process_keys.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'security') diff --git a/security/keys/internal.h b/security/keys/internal.h index a2f4c0a..6bee06a 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -17,6 +17,7 @@ #include #include #include +#include struct iovec; @@ -53,7 +54,7 @@ struct key_user { struct rb_node node; struct mutex cons_lock; /* construction initiation lock */ spinlock_t lock; - atomic_t usage; /* for accessing qnkeys & qnbytes */ + refcount_t usage; /* for accessing qnkeys & qnbytes */ atomic_t nkeys; /* number of keys */ atomic_t nikeys; /* number of instantiated keys */ kuid_t uid; diff --git a/security/keys/key.c b/security/keys/key.c index ff92443..b4958b3 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -93,7 +93,7 @@ try_again: /* if we get here, then the user record still hadn't appeared on the * second pass - so we use the candidate record */ - atomic_set(&candidate->usage, 1); + refcount_set(&candidate->usage, 1); atomic_set(&candidate->nkeys, 0); atomic_set(&candidate->nikeys, 0); candidate->uid = uid; @@ -110,7 +110,7 @@ try_again: /* okay - we found a user record for this UID */ found: - atomic_inc(&user->usage); + refcount_inc(&user->usage); spin_unlock(&key_user_lock); kfree(candidate); out: @@ -122,7 +122,7 @@ out: */ void key_user_put(struct key_user *user) { - if (atomic_dec_and_lock(&user->usage, &key_user_lock)) { + if (refcount_dec_and_lock(&user->usage, &key_user_lock)) { rb_erase(&user->node, &key_user_tree); spin_unlock(&key_user_lock); diff --git a/security/keys/proc.c b/security/keys/proc.c index 69199f1..bf08d02 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -340,7 +340,7 @@ static int proc_key_users_show(struct seq_file *m, void *v) seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", from_kuid_munged(seq_user_ns(m), user->uid), - atomic_read(&user->usage), + refcount_read(&user->usage), atomic_read(&user->nkeys), atomic_read(&user->nikeys), user->qnkeys, diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index b6fdd22..44451af 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -30,7 +30,7 @@ static DEFINE_MUTEX(key_user_keyring_mutex); /* The root user's tracking struct */ struct key_user root_key_user = { - .usage = ATOMIC_INIT(3), + .usage = REFCOUNT_INIT(3), .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), .nkeys = ATOMIC_INIT(2), -- cgit v1.1 From 469ff8f7d46d75b36de68a0411a2ce80109ad00b Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Mon, 25 Apr 2016 11:30:39 -0700 Subject: KEYS: Use a typedef for restrict_link function pointers This pointer type needs to be returned from a lookup function, and without a typedef the syntax gets cumbersome. Signed-off-by: Mat Martineau --- security/keys/key.c | 8 ++------ security/keys/keyring.c | 4 +--- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'security') diff --git a/security/keys/key.c b/security/keys/key.c index b4958b3..08dfa13 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -225,9 +225,7 @@ serial_exists: struct key *key_alloc(struct key_type *type, const char *desc, kuid_t uid, kgid_t gid, const struct cred *cred, key_perm_t perm, unsigned long flags, - int (*restrict_link)(struct key *, - const struct key_type *, - const union key_payload *)) + key_restrict_link_func_t restrict_link) { struct key_user *user = NULL; struct key *key; @@ -806,9 +804,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, struct key *keyring, *key = NULL; key_ref_t key_ref; int ret; - int (*restrict_link)(struct key *, - const struct key_type *, - const union key_payload *) = NULL; + key_restrict_link_func_t restrict_link = NULL; /* look up the key type to see if it's one of the registered kernel * types */ diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 3d95f7d..1b29ac7 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -492,9 +492,7 @@ static long keyring_read(const struct key *keyring, struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, const struct cred *cred, key_perm_t perm, unsigned long flags, - int (*restrict_link)(struct key *, - const struct key_type *, - const union key_payload *), + key_restrict_link_func_t restrict_link, struct key *dest) { struct key *keyring; -- cgit v1.1 From aaf66c883813f0078e3dafe7d20d1461321ac14f Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Tue, 30 Aug 2016 11:33:13 -0700 Subject: KEYS: Split role of the keyring pointer for keyring restrict functions The first argument to the restrict_link_func_t functions was a keyring pointer. These functions are called by the key subsystem with this argument set to the destination keyring, but restrict_link_by_signature expects a pointer to the relevant trusted keyring. Restrict functions may need something other than a single struct key pointer to allow or reject key linkage, so the data used to make that decision (such as the trust keyring) is moved to a new, fourth argument. The first argument is now always the destination keyring. Signed-off-by: Mat Martineau --- security/keys/key.c | 5 +++-- security/keys/keyring.c | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'security') diff --git a/security/keys/key.c b/security/keys/key.c index 08dfa13..27fc1bb 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -499,7 +499,7 @@ int key_instantiate_and_link(struct key *key, if (keyring) { if (keyring->restrict_link) { ret = keyring->restrict_link(keyring, key->type, - &prep.payload); + &prep.payload, NULL); if (ret < 0) goto error; } @@ -851,7 +851,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, index_key.desc_len = strlen(index_key.description); if (restrict_link) { - ret = restrict_link(keyring, index_key.type, &prep.payload); + ret = restrict_link(keyring, index_key.type, &prep.payload, + NULL); if (ret < 0) { key_ref = ERR_PTR(ret); goto error_free_prep; diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 1b29ac7..2ccc66e 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -517,6 +517,7 @@ EXPORT_SYMBOL(keyring_alloc); * @keyring: The keyring being added to. * @type: The type of key being added. * @payload: The payload of the key intended to be added. + * @data: Additional data for evaluating restriction. * * Reject the addition of any links to a keyring. It can be overridden by * passing KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when @@ -527,7 +528,8 @@ EXPORT_SYMBOL(keyring_alloc); */ int restrict_link_reject(struct key *keyring, const struct key_type *type, - const union key_payload *payload) + const union key_payload *payload, + struct key *restriction_key) { return -EPERM; } @@ -1220,7 +1222,7 @@ static int __key_link_check_restriction(struct key *keyring, struct key *key) { if (!keyring->restrict_link) return 0; - return keyring->restrict_link(keyring, key->type, &key->payload); + return keyring->restrict_link(keyring, key->type, &key->payload, NULL); } /** -- cgit v1.1 From 2b6aa412ff23a02ac777ad307249c60a839cfd25 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 31 Aug 2016 16:05:43 -0700 Subject: KEYS: Use structure to capture key restriction function and data Replace struct key's restrict_link function pointer with a pointer to the new struct key_restriction. The structure contains pointers to the restriction function as well as relevant data for evaluating the restriction. The garbage collector checks restrict_link->keytype when key types are unregistered. Restrictions involving a removed key type are converted to use restrict_link_reject so that restrictions cannot be removed by unregistering key types. Signed-off-by: Mat Martineau --- security/integrity/digsig.c | 9 +++++- security/integrity/ima/ima_mok.c | 11 ++++++- security/keys/gc.c | 11 +++++++ security/keys/internal.h | 2 ++ security/keys/key.c | 23 ++++++++------ security/keys/keyring.c | 68 +++++++++++++++++++++++++++++++++++++--- 6 files changed, 108 insertions(+), 16 deletions(-) (limited to 'security') diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 106e855..06554c4 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -81,18 +81,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, int __init integrity_init_keyring(const unsigned int id) { const struct cred *cred = current_cred(); + struct key_restriction *restriction; int err = 0; if (!init_keyring) return 0; + restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL); + if (!restriction) + return -ENOMEM; + + restriction->check = restrict_link_to_ima; + keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), KGIDT_INIT(0), cred, ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE | KEY_USR_SEARCH), KEY_ALLOC_NOT_IN_QUOTA, - restrict_link_to_ima, NULL); + restriction, NULL); if (IS_ERR(keyring[id])) { err = PTR_ERR(keyring[id]); pr_info("Can't allocate %s keyring (%d)\n", diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c index 74a27995..073ddc9 100644 --- a/security/integrity/ima/ima_mok.c +++ b/security/integrity/ima/ima_mok.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -27,15 +28,23 @@ struct key *ima_blacklist_keyring; */ __init int ima_mok_init(void) { + struct key_restriction *restriction; + pr_notice("Allocating IMA blacklist keyring.\n"); + restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL); + if (!restriction) + panic("Can't allocate IMA blacklist restriction."); + + restriction->check = restrict_link_by_builtin_trusted; + ima_blacklist_keyring = keyring_alloc(".ima_blacklist", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE | KEY_USR_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, - restrict_link_by_builtin_trusted, NULL); + restriction, NULL); if (IS_ERR(ima_blacklist_keyring)) panic("Can't allocate IMA blacklist keyring."); diff --git a/security/keys/gc.c b/security/keys/gc.c index 4478925..15b9ddf 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -229,6 +229,9 @@ continue_scanning: set_bit(KEY_FLAG_DEAD, &key->flags); key->perm = 0; goto skip_dead_key; + } else if (key->type == &key_type_keyring && + key->restrict_link) { + goto found_restricted_keyring; } } @@ -334,6 +337,14 @@ found_unreferenced_key: gc_state |= KEY_GC_REAP_AGAIN; goto maybe_resched; + /* We found a restricted keyring and need to update the restriction if + * it is associated with the dead key type. + */ +found_restricted_keyring: + spin_unlock(&key_serial_lock); + keyring_restriction_gc(key, key_gc_dead_keytype); + goto maybe_resched; + /* We found a keyring and we need to check the payload for links to * dead or expired keys. We don't flag another reap immediately as we * have to wait for the old payload to be destroyed by RCU before we diff --git a/security/keys/internal.h b/security/keys/internal.h index 6bee06a..24762ae 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -168,6 +168,8 @@ extern void key_change_session_keyring(struct callback_head *twork); extern struct work_struct key_gc_work; extern unsigned key_gc_delay; extern void keyring_gc(struct key *keyring, time_t limit); +extern void keyring_restriction_gc(struct key *keyring, + struct key_type *dead_type); extern void key_schedule_gc(time_t gc_at); extern void key_schedule_gc_links(void); extern void key_gc_keytype(struct key_type *ktype); diff --git a/security/keys/key.c b/security/keys/key.c index 27fc1bb..2ea5967 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -201,12 +201,15 @@ serial_exists: * @cred: The credentials specifying UID namespace. * @perm: The permissions mask of the new key. * @flags: Flags specifying quota properties. - * @restrict_link: Optional link restriction method for new keyrings. + * @restrict_link: Optional link restriction for new keyrings. * * Allocate a key of the specified type with the attributes given. The key is * returned in an uninstantiated state and the caller needs to instantiate the * key before returning. * + * The restrict_link structure (if not NULL) will be freed when the + * keyring is destroyed, so it must be dynamically allocated. + * * The user's key count quota is updated to reflect the creation of the key and * the user's key data quota has the default for the key type reserved. The * instantiation function should amend this as necessary. If insufficient @@ -225,7 +228,7 @@ serial_exists: struct key *key_alloc(struct key_type *type, const char *desc, kuid_t uid, kgid_t gid, const struct cred *cred, key_perm_t perm, unsigned long flags, - key_restrict_link_func_t restrict_link) + struct key_restriction *restrict_link) { struct key_user *user = NULL; struct key *key; @@ -497,9 +500,11 @@ int key_instantiate_and_link(struct key *key, } if (keyring) { - if (keyring->restrict_link) { - ret = keyring->restrict_link(keyring, key->type, - &prep.payload, NULL); + if (keyring->restrict_link && keyring->restrict_link->check) { + struct key_restriction *keyres = keyring->restrict_link; + + ret = keyres->check(keyring, key->type, &prep.payload, + keyres->key); if (ret < 0) goto error; } @@ -804,7 +809,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, struct key *keyring, *key = NULL; key_ref_t key_ref; int ret; - key_restrict_link_func_t restrict_link = NULL; + struct key_restriction *restrict_link = NULL; /* look up the key type to see if it's one of the registered kernel * types */ @@ -850,9 +855,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, } index_key.desc_len = strlen(index_key.description); - if (restrict_link) { - ret = restrict_link(keyring, index_key.type, &prep.payload, - NULL); + if (restrict_link && restrict_link->check) { + ret = restrict_link->check(keyring, index_key.type, + &prep.payload, restrict_link->key); if (ret < 0) { key_ref = ERR_PTR(ret); goto error_free_prep; diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 2ccc66e..838334f 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -394,6 +394,13 @@ static void keyring_destroy(struct key *keyring) write_unlock(&keyring_name_lock); } + if (keyring->restrict_link) { + struct key_restriction *keyres = keyring->restrict_link; + + key_put(keyres->key); + kfree(keyres); + } + assoc_array_destroy(&keyring->keys, &keyring_assoc_array_ops); } @@ -492,7 +499,7 @@ static long keyring_read(const struct key *keyring, struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, const struct cred *cred, key_perm_t perm, unsigned long flags, - key_restrict_link_func_t restrict_link, + struct key_restriction *restrict_link, struct key *dest) { struct key *keyring; @@ -523,8 +530,8 @@ EXPORT_SYMBOL(keyring_alloc); * passing KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when * adding a key to a keyring. * - * This is meant to be passed as the restrict_link parameter to - * keyring_alloc(). + * This is meant to be stored in a key_restriction structure which is passed + * in the restrict_link parameter to keyring_alloc(). */ int restrict_link_reject(struct key *keyring, const struct key_type *type, @@ -1220,9 +1227,10 @@ void __key_link_end(struct key *keyring, */ static int __key_link_check_restriction(struct key *keyring, struct key *key) { - if (!keyring->restrict_link) + if (!keyring->restrict_link || !keyring->restrict_link->check) return 0; - return keyring->restrict_link(keyring, key->type, &key->payload, NULL); + return keyring->restrict_link->check(keyring, key->type, &key->payload, + keyring->restrict_link->key); } /** @@ -1426,3 +1434,53 @@ do_gc: up_write(&keyring->sem); kleave(" [gc]"); } + +/* + * Garbage collect restriction pointers from a keyring. + * + * Keyring restrictions are associated with a key type, and must be cleaned + * up if the key type is unregistered. The restriction is altered to always + * reject additional keys so a keyring cannot be opened up by unregistering + * a key type. + * + * Not called with any keyring locks held. The keyring's key struct will not + * be deallocated under us as only our caller may deallocate it. + * + * The caller is required to hold key_types_sem and dead_type->sem. This is + * fulfilled by key_gc_keytype() holding the locks on behalf of + * key_garbage_collector(), which it invokes on a workqueue. + */ +void keyring_restriction_gc(struct key *keyring, struct key_type *dead_type) +{ + struct key_restriction *keyres; + + kenter("%x{%s}", keyring->serial, keyring->description ?: ""); + + /* + * keyring->restrict_link is only assigned at key allocation time + * or with the key type locked, so the only values that could be + * concurrently assigned to keyring->restrict_link are for key + * types other than dead_type. Given this, it's ok to check + * the key type before acquiring keyring->sem. + */ + if (!dead_type || !keyring->restrict_link || + keyring->restrict_link->keytype != dead_type) { + kleave(" [no restriction gc]"); + return; + } + + /* Lock the keyring to ensure that a link is not in progress */ + down_write(&keyring->sem); + + keyres = keyring->restrict_link; + + keyres->check = restrict_link_reject; + + key_put(keyres->key); + keyres->key = NULL; + keyres->keytype = NULL; + + up_write(&keyring->sem); + + kleave(" [restriction gc]"); +} -- cgit v1.1 From 4a420896f12d2d043602f134ae18ad6be5b9d9dd Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Tue, 4 Oct 2016 16:27:32 -0700 Subject: KEYS: Consistent ordering for __key_link_begin and restrict check The keyring restrict callback was sometimes called before __key_link_begin and sometimes after, which meant that the keyring semaphores were not always held during the restrict callback. If the semaphores are consistently acquired before checking link restrictions, keyring contents cannot be changed after the restrict check is complete but before the evaluated key is linked to the keyring. Signed-off-by: Mat Martineau --- security/keys/key.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'security') diff --git a/security/keys/key.c b/security/keys/key.c index 2ea5967..455c04d 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -500,21 +500,23 @@ int key_instantiate_and_link(struct key *key, } if (keyring) { + ret = __key_link_begin(keyring, &key->index_key, &edit); + if (ret < 0) + goto error; + if (keyring->restrict_link && keyring->restrict_link->check) { struct key_restriction *keyres = keyring->restrict_link; ret = keyres->check(keyring, key->type, &prep.payload, keyres->key); if (ret < 0) - goto error; + goto error_link_end; } - ret = __key_link_begin(keyring, &key->index_key, &edit); - if (ret < 0) - goto error; } ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); +error_link_end: if (keyring) __key_link_end(keyring, &key->index_key, edit); @@ -855,21 +857,21 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, } index_key.desc_len = strlen(index_key.description); + ret = __key_link_begin(keyring, &index_key, &edit); + if (ret < 0) { + key_ref = ERR_PTR(ret); + goto error_free_prep; + } + if (restrict_link && restrict_link->check) { ret = restrict_link->check(keyring, index_key.type, &prep.payload, restrict_link->key); if (ret < 0) { key_ref = ERR_PTR(ret); - goto error_free_prep; + goto error_link_end; } } - ret = __key_link_begin(keyring, &index_key, &edit); - if (ret < 0) { - key_ref = ERR_PTR(ret); - goto error_free_prep; - } - /* if we're going to allocate a new key, we're going to have * to modify the keyring */ ret = key_permission(keyring_ref, KEY_NEED_WRITE); -- cgit v1.1 From 6563c91fd645556c7801748f15bc727c77fcd311 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 1 Mar 2017 16:44:09 -0800 Subject: KEYS: Add KEYCTL_RESTRICT_KEYRING Keyrings recently gained restrict_link capabilities that allow individual keys to be validated prior to linking. This functionality was only available using internal kernel APIs. With the KEYCTL_RESTRICT_KEYRING command existing keyrings can be configured to check the content of keys before they are linked, and then allow or disallow linkage of that key to the keyring. To restrict a keyring, call: keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring, const char *type, const char *restriction) where 'type' is the name of a registered key type and 'restriction' is a string describing how key linkage is to be restricted. The restriction option syntax is specific to each key type. Signed-off-by: Mat Martineau --- security/keys/compat.c | 4 ++ security/keys/internal.h | 3 ++ security/keys/keyctl.c | 58 ++++++++++++++++++++++++++ security/keys/keyring.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+) (limited to 'security') diff --git a/security/keys/compat.c b/security/keys/compat.c index 36c80bf..bb98f2b 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -136,6 +136,10 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3), arg4, compat_ptr(arg5)); + case KEYCTL_RESTRICT_KEYRING: + return keyctl_restrict_keyring(arg2, compat_ptr(arg3), + compat_ptr(arg4)); + default: return -EOPNOTSUPP; } diff --git a/security/keys/internal.h b/security/keys/internal.h index 24762ae..6ce0163 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -252,6 +252,9 @@ struct iov_iter; extern long keyctl_instantiate_key_common(key_serial_t, struct iov_iter *, key_serial_t); +extern long keyctl_restrict_keyring(key_serial_t id, + const char __user *_type, + const char __user *_restriction); #ifdef CONFIG_PERSISTENT_KEYRINGS extern long keyctl_get_persistent(uid_t, key_serial_t); extern unsigned persistent_keyring_expiry; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 52c3453..6ee2826 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1583,6 +1583,59 @@ error_keyring: } /* + * Apply a restriction to a given keyring. + * + * The caller must have Setattr permission to change keyring restrictions. + * + * The requested type name may be a NULL pointer to reject all attempts + * to link to the keyring. If _type is non-NULL, _restriction can be + * NULL or a pointer to a string describing the restriction. If _type is + * NULL, _restriction must also be NULL. + * + * Returns 0 if successful. + */ +long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, + const char __user *_restriction) +{ + key_ref_t key_ref; + bool link_reject = !_type; + char type[32]; + char *restriction = NULL; + long ret; + + key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); + if (IS_ERR(key_ref)) + return PTR_ERR(key_ref); + + if (_type) { + ret = key_get_type_from_user(type, _type, sizeof(type)); + if (ret < 0) + goto error; + } + + if (_restriction) { + if (!_type) { + ret = -EINVAL; + goto error; + } + + restriction = strndup_user(_restriction, PAGE_SIZE); + if (IS_ERR(restriction)) { + ret = PTR_ERR(restriction); + goto error; + } + } + + ret = keyring_restrict(key_ref, link_reject ? NULL : type, restriction); + kfree(restriction); + +error: + key_ref_put(key_ref); + + return ret; +} + +/* * The key control system call */ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, @@ -1693,6 +1746,11 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, (char __user *) arg3, (size_t) arg4, (void __user *) arg5); + case KEYCTL_RESTRICT_KEYRING: + return keyctl_restrict_keyring((key_serial_t) arg2, + (const char __user *) arg3, + (const char __user *) arg4); + default: return -EOPNOTSUPP; } diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 838334f..4d1678e4 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -947,6 +947,111 @@ key_ref_t keyring_search(key_ref_t keyring, } EXPORT_SYMBOL(keyring_search); +static struct key_restriction *keyring_restriction_alloc( + key_restrict_link_func_t check) +{ + struct key_restriction *keyres = + kzalloc(sizeof(struct key_restriction), GFP_KERNEL); + + if (!keyres) + return ERR_PTR(-ENOMEM); + + keyres->check = check; + + return keyres; +} + +/* + * Semaphore to serialise restriction setup to prevent reference count + * cycles through restriction key pointers. + */ +static DECLARE_RWSEM(keyring_serialise_restrict_sem); + +/* + * Check for restriction cycles that would prevent keyring garbage collection. + * keyring_serialise_restrict_sem must be held. + */ +static bool keyring_detect_restriction_cycle(const struct key *dest_keyring, + struct key_restriction *keyres) +{ + while (keyres && keyres->key && + keyres->key->type == &key_type_keyring) { + if (keyres->key == dest_keyring) + return true; + + keyres = keyres->key->restrict_link; + } + + return false; +} + +/** + * keyring_restrict - Look up and apply a restriction to a keyring + * + * @keyring: The keyring to be restricted + * @restriction: The restriction options to apply to the keyring + */ +int keyring_restrict(key_ref_t keyring_ref, const char *type, + const char *restriction) +{ + struct key *keyring; + struct key_type *restrict_type = NULL; + struct key_restriction *restrict_link; + int ret = 0; + + keyring = key_ref_to_ptr(keyring_ref); + key_check(keyring); + + if (keyring->type != &key_type_keyring) + return -ENOTDIR; + + if (!type) { + restrict_link = keyring_restriction_alloc(restrict_link_reject); + } else { + restrict_type = key_type_lookup(type); + + if (IS_ERR(restrict_type)) + return PTR_ERR(restrict_type); + + if (!restrict_type->lookup_restriction) { + ret = -ENOENT; + goto error; + } + + restrict_link = restrict_type->lookup_restriction(restriction); + } + + if (IS_ERR(restrict_link)) { + ret = PTR_ERR(restrict_link); + goto error; + } + + down_write(&keyring->sem); + down_write(&keyring_serialise_restrict_sem); + + if (keyring->restrict_link) + ret = -EEXIST; + else if (keyring_detect_restriction_cycle(keyring, restrict_link)) + ret = -EDEADLK; + else + keyring->restrict_link = restrict_link; + + up_write(&keyring_serialise_restrict_sem); + up_write(&keyring->sem); + + if (ret < 0) { + key_put(restrict_link->key); + kfree(restrict_link); + } + +error: + if (restrict_type) + key_type_put(restrict_type); + + return ret; +} +EXPORT_SYMBOL(keyring_restrict); + /* * Search the given keyring for a key that might be updated. * -- cgit v1.1 From f1c316a3ab9d24df6022682422fe897492f2c0c8 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 19 Aug 2016 20:39:09 +0200 Subject: KEYS: add SP800-56A KDF support for DH SP800-56A defines the use of DH with key derivation function based on a counter. The input to the KDF is defined as (DH shared secret || other information). The value for the "other information" is to be provided by the caller. The KDF is implemented using the hash support from the kernel crypto API. The implementation uses the symmetric hash support as the input to the hash operation is usually very small. The caller is allowed to specify the hash name that he wants to use to derive the key material allowing the use of all supported hashes provided with the kernel crypto API. As the KDF implements the proper truncation of the DH shared secret to the requested size, this patch fills the caller buffer up to its size. The patch is tested with a new test added to the keyutils user space code which uses a CAVS test vector testing the compliance with SP800-56A. Signed-off-by: Stephan Mueller Signed-off-by: David Howells --- security/keys/Kconfig | 1 + security/keys/Makefile | 3 +- security/keys/compat.c | 5 +- security/keys/compat_dh.c | 38 ++++++++ security/keys/dh.c | 220 +++++++++++++++++++++++++++++++++++++++++++--- security/keys/internal.h | 24 ++++- security/keys/keyctl.c | 2 +- 7 files changed, 275 insertions(+), 18 deletions(-) create mode 100644 security/keys/compat_dh.c (limited to 'security') diff --git a/security/keys/Kconfig b/security/keys/Kconfig index d942c7c..4ac1b83 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -90,6 +90,7 @@ config KEY_DH_OPERATIONS bool "Diffie-Hellman operations on retained keys" depends on KEYS select MPILIB + select CRYPTO_HASH help This option provides support for calculating Diffie-Hellman public keys and shared secrets using values stored as keys diff --git a/security/keys/Makefile b/security/keys/Makefile index 1fd4a16..57dff0c 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile @@ -15,7 +15,8 @@ obj-y := \ request_key.o \ request_key_auth.o \ user_defined.o -obj-$(CONFIG_KEYS_COMPAT) += compat.o +compat-obj-$(CONFIG_KEY_DH_OPERATIONS) += compat_dh.o +obj-$(CONFIG_KEYS_COMPAT) += compat.o $(compat-obj-y) obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSCTL) += sysctl.o obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o diff --git a/security/keys/compat.c b/security/keys/compat.c index bb98f2b..e87c89c 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -133,8 +133,9 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, return keyctl_get_persistent(arg2, arg3); case KEYCTL_DH_COMPUTE: - return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3), - arg4, compat_ptr(arg5)); + return compat_keyctl_dh_compute(compat_ptr(arg2), + compat_ptr(arg3), + arg4, compat_ptr(arg5)); case KEYCTL_RESTRICT_KEYRING: return keyctl_restrict_keyring(arg2, compat_ptr(arg3), diff --git a/security/keys/compat_dh.c b/security/keys/compat_dh.c new file mode 100644 index 0000000..a6a659b --- /dev/null +++ b/security/keys/compat_dh.c @@ -0,0 +1,38 @@ +/* 32-bit compatibility syscall for 64-bit systems for DH operations + * + * Copyright (C) 2016 Stephan Mueller + * + * 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 of the License, or (at your option) any later version. + */ + +#include + +#include "internal.h" + +/* + * Perform the DH computation or DH based key derivation. + * + * If successful, 0 will be returned. + */ +long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params, + char __user *buffer, size_t buflen, + struct compat_keyctl_kdf_params __user *kdf) +{ + struct keyctl_kdf_params kdfcopy; + struct compat_keyctl_kdf_params compat_kdfcopy; + + if (!kdf) + return __keyctl_dh_compute(params, buffer, buflen, NULL); + + if (copy_from_user(&compat_kdfcopy, kdf, sizeof(compat_kdfcopy)) != 0) + return -EFAULT; + + kdfcopy.hashname = compat_ptr(compat_kdfcopy.hashname); + kdfcopy.otherinfo = compat_ptr(compat_kdfcopy.otherinfo); + kdfcopy.otherinfolen = compat_kdfcopy.otherinfolen; + + return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy); +} diff --git a/security/keys/dh.c b/security/keys/dh.c index 893af4c..e603bd9 100644 --- a/security/keys/dh.c +++ b/security/keys/dh.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include "internal.h" @@ -77,9 +79,146 @@ error: return ret; } -long keyctl_dh_compute(struct keyctl_dh_params __user *params, - char __user *buffer, size_t buflen, - void __user *reserved) +struct kdf_sdesc { + struct shash_desc shash; + char ctx[]; +}; + +static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname) +{ + struct crypto_shash *tfm; + struct kdf_sdesc *sdesc; + int size; + + /* allocate synchronous hash */ + tfm = crypto_alloc_shash(hashname, 0, 0); + if (IS_ERR(tfm)) { + pr_info("could not allocate digest TFM handle %s\n", hashname); + return PTR_ERR(tfm); + } + + size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm); + sdesc = kmalloc(size, GFP_KERNEL); + if (!sdesc) + return -ENOMEM; + sdesc->shash.tfm = tfm; + sdesc->shash.flags = 0x0; + + *sdesc_ret = sdesc; + + return 0; +} + +static void kdf_dealloc(struct kdf_sdesc *sdesc) +{ + if (!sdesc) + return; + + if (sdesc->shash.tfm) + crypto_free_shash(sdesc->shash.tfm); + + kzfree(sdesc); +} + +/* convert 32 bit integer into its string representation */ +static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf) +{ + __be32 *a = (__be32 *)buf; + + *a = cpu_to_be32(val); +} + +/* + * Implementation of the KDF in counter mode according to SP800-108 section 5.1 + * as well as SP800-56A section 5.8.1 (Single-step KDF). + * + * SP800-56A: + * The src pointer is defined as Z || other info where Z is the shared secret + * from DH and other info is an arbitrary string (see SP800-56A section + * 5.8.1.2). + */ +static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, + u8 *dst, unsigned int dlen) +{ + struct shash_desc *desc = &sdesc->shash; + unsigned int h = crypto_shash_digestsize(desc->tfm); + int err = 0; + u8 *dst_orig = dst; + u32 i = 1; + u8 iteration[sizeof(u32)]; + + while (dlen) { + err = crypto_shash_init(desc); + if (err) + goto err; + + crypto_kw_cpu_to_be32(i, iteration); + err = crypto_shash_update(desc, iteration, sizeof(u32)); + if (err) + goto err; + + if (src && slen) { + err = crypto_shash_update(desc, src, slen); + if (err) + goto err; + } + + if (dlen < h) { + u8 tmpbuffer[h]; + + err = crypto_shash_final(desc, tmpbuffer); + if (err) + goto err; + memcpy(dst, tmpbuffer, dlen); + memzero_explicit(tmpbuffer, h); + return 0; + } else { + err = crypto_shash_final(desc, dst); + if (err) + goto err; + + dlen -= h; + dst += h; + i++; + } + } + + return 0; + +err: + memzero_explicit(dst_orig, dlen); + return err; +} + +static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, + char __user *buffer, size_t buflen, + uint8_t *kbuf, size_t kbuflen) +{ + uint8_t *outbuf = NULL; + int ret; + + outbuf = kmalloc(buflen, GFP_KERNEL); + if (!outbuf) { + ret = -ENOMEM; + goto err; + } + + ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen); + if (ret) + goto err; + + ret = buflen; + if (copy_to_user(buffer, outbuf, buflen) != 0) + ret = -EFAULT; + +err: + kzfree(outbuf); + return ret; +} + +long __keyctl_dh_compute(struct keyctl_dh_params __user *params, + char __user *buffer, size_t buflen, + struct keyctl_kdf_params *kdfcopy) { long ret; MPI base, private, prime, result; @@ -88,6 +227,7 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, uint8_t *kbuf; ssize_t keylen; size_t resultlen; + struct kdf_sdesc *sdesc = NULL; if (!params || (!buffer && buflen)) { ret = -EINVAL; @@ -98,12 +238,34 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, goto out; } - if (reserved) { - ret = -EINVAL; - goto out; + if (kdfcopy) { + char *hashname; + + if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN || + kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) { + ret = -EMSGSIZE; + goto out; + } + + /* get KDF name string */ + hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME); + if (IS_ERR(hashname)) { + ret = PTR_ERR(hashname); + goto out; + } + + /* allocate KDF from the kernel crypto API */ + ret = kdf_alloc(&sdesc, hashname); + kfree(hashname); + if (ret) + goto out; } - keylen = mpi_from_key(pcopy.prime, buflen, &prime); + /* + * If the caller requests postprocessing with a KDF, allow an + * arbitrary output buffer size since the KDF ensures proper truncation. + */ + keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime); if (keylen < 0 || !prime) { /* buflen == 0 may be used to query the required buffer size, * which is the prime key length. @@ -133,12 +295,25 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, goto error3; } - kbuf = kmalloc(resultlen, GFP_KERNEL); + /* allocate space for DH shared secret and SP800-56A otherinfo */ + kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen, + GFP_KERNEL); if (!kbuf) { ret = -ENOMEM; goto error4; } + /* + * Concatenate SP800-56A otherinfo past DH shared secret -- the + * input to the KDF is (DH shared secret || otherinfo) + */ + if (kdfcopy && kdfcopy->otherinfo && + copy_from_user(kbuf + resultlen, kdfcopy->otherinfo, + kdfcopy->otherinfolen) != 0) { + ret = -EFAULT; + goto error5; + } + ret = do_dh(result, base, private, prime); if (ret) goto error5; @@ -147,12 +322,17 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params, if (ret != 0) goto error5; - ret = nbytes; - if (copy_to_user(buffer, kbuf, nbytes) != 0) - ret = -EFAULT; + if (kdfcopy) { + ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, kbuf, + resultlen + kdfcopy->otherinfolen); + } else { + ret = nbytes; + if (copy_to_user(buffer, kbuf, nbytes) != 0) + ret = -EFAULT; + } error5: - kfree(kbuf); + kzfree(kbuf); error4: mpi_free(result); error3: @@ -162,5 +342,21 @@ error2: error1: mpi_free(prime); out: + kdf_dealloc(sdesc); return ret; } + +long keyctl_dh_compute(struct keyctl_dh_params __user *params, + char __user *buffer, size_t buflen, + struct keyctl_kdf_params __user *kdf) +{ + struct keyctl_kdf_params kdfcopy; + + if (!kdf) + return __keyctl_dh_compute(params, buffer, buflen, NULL); + + if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0) + return -EFAULT; + + return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy); +} diff --git a/security/keys/internal.h b/security/keys/internal.h index 6ce0163..c0f8682 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -18,6 +18,7 @@ #include #include #include +#include struct iovec; @@ -267,15 +268,34 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring) #ifdef CONFIG_KEY_DH_OPERATIONS extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *, - size_t, void __user *); + size_t, struct keyctl_kdf_params __user *); +extern long __keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *, + size_t, struct keyctl_kdf_params *); +#ifdef CONFIG_KEYS_COMPAT +extern long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params, + char __user *buffer, size_t buflen, + struct compat_keyctl_kdf_params __user *kdf); +#endif +#define KEYCTL_KDF_MAX_OUTPUT_LEN 1024 /* max length of KDF output */ +#define KEYCTL_KDF_MAX_OI_LEN 64 /* max length of otherinfo */ #else static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params, char __user *buffer, size_t buflen, - void __user *reserved) + struct keyctl_kdf_params __user *kdf) +{ + return -EOPNOTSUPP; +} + +#ifdef CONFIG_KEYS_COMPAT +static inline long compat_keyctl_dh_compute( + struct keyctl_dh_params __user *params, + char __user *buffer, size_t buflen, + struct keyctl_kdf_params __user *kdf) { return -EOPNOTSUPP; } #endif +#endif /* * Debugging key validation diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 6ee2826..10fcea1 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1744,7 +1744,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, case KEYCTL_DH_COMPUTE: return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2, (char __user *) arg3, (size_t) arg4, - (void __user *) arg5); + (struct keyctl_kdf_params __user *) arg5); case KEYCTL_RESTRICT_KEYRING: return keyctl_restrict_keyring((key_serial_t) arg2, -- cgit v1.1 From c3c8dc9f13e2e13013822ee54a529a6fe284f1e1 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 24 Mar 2017 20:42:05 +0900 Subject: smack: fix double free in smack_parse_opts_str() smack_parse_opts_str() calls kfree(opts->mnt_opts) when kcalloc() for opts->mnt_opts_flags failed. But it should not have called it because security_free_mnt_opts() will call kfree(opts->mnt_opts). Signed-off-by: Tetsuo Handa Signed-off-by: Casey Schaufler fixes: 3bf2789cad9e6573 ("smack: allow mount opts setting over filesystems with binary mount data") Cc: Vivek Trivedi Cc: Amit Sahrawat Cc: Casey Schaufler --- security/smack/smack_lsm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'security') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 927e60e..658f5d8 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -695,10 +695,8 @@ static int smack_parse_opts_str(char *options, opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int), GFP_KERNEL); - if (!opts->mnt_opts_flags) { - kfree(opts->mnt_opts); + if (!opts->mnt_opts_flags) goto out_err; - } if (fsdefault) { opts->mnt_opts[num_mnt_opts] = fsdefault; -- cgit v1.1 From af96f0d6394a0af59c4dd71d6bcd3b1ddfba5196 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 14 Nov 2016 20:12:56 +0900 Subject: Smack: Use GFP_KERNEL for smk_netlbl_mls(). Since all callers of smk_netlbl_mls() are GFP_KERNEL context (smk_set_cipso() calls memdup_user_nul(), init_smk_fs() calls __kernfs_new_node(), smk_import_entry() calls kzalloc(GFP_KERNEL)), it is safe to use GFP_KERNEL from netlbl_catmap_setbit(). Signed-off-by: Tetsuo Handa Signed-off-by: Casey Schaufler --- security/smack/smack_access.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 356e376..a4b2e6b 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -504,7 +504,7 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, if ((m & *cp) == 0) continue; rc = netlbl_catmap_setbit(&sap->attr.mls.cat, - cat, GFP_ATOMIC); + cat, GFP_KERNEL); if (rc < 0) { netlbl_catmap_free(sap->attr.mls.cat); return rc; -- cgit v1.1 From b9c42ac76ea13ab6d07681ff3079b3a242333764 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 6 Apr 2017 06:55:19 -0700 Subject: apparmor: fix boolreturn.cocci warnings security/apparmor/lib.c:132:9-10: WARNING: return of 0/1 in function 'aa_policy_init' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: scripts/coccinelle/misc/boolreturn.cocci Signed-off-by: Fengguang Wu Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 66475bd..32cafc1 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -180,13 +180,13 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix, } else policy->hname = kstrdup(name, gfp); if (!policy->hname) - return 0; + return false; /* base.name is a substring of fqname */ policy->name = basename(policy->hname); INIT_LIST_HEAD(&policy->list); INIT_LIST_HEAD(&policy->profiles); - return 1; + return true; } /** -- cgit v1.1 From eea7a05f1937b585cf53c6d53a4dd88fcb398eb8 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 6 Apr 2017 06:55:20 -0700 Subject: security/apparmor/lsm.c: set debug messages Add the _APPARMOR substring to reference the intended Kconfig option. Signed-off-by: Valentin Rothberg Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index e287b69..4aa9447 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -681,7 +681,7 @@ module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); #endif /* Debug mode */ -bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_DEBUG_MESSAGES); +bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES); module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); /* Audit mode */ -- cgit v1.1 From 9814448da7a84dd50b69e4ada2d7d1c042493daf Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Thu, 6 Apr 2017 06:55:21 -0700 Subject: apparmor: use SHASH_DESC_ON_STACK When building the kernel with clang, the compiler fails to build security/apparmor/crypto.c with the following error: security/apparmor/crypto.c:36:8: error: fields must have a constant size: 'variable length array in structure' extension will never be supported char ctx[crypto_shash_descsize(apparmor_tfm)]; ^ Since commit a0a77af14117 ("crypto: LLVMLinux: Add macro to remove use of VLAIS in crypto code"), include/crypto/hash.h defines SHASH_DESC_ON_STACK to work around this issue. Use it in aa_calc_hash() and aa_calc_profile_hash(). Signed-off-by: Nicolas Iooss Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/crypto.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'security') diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c index de8dc78..136f2a0 100644 --- a/security/apparmor/crypto.c +++ b/security/apparmor/crypto.c @@ -31,10 +31,7 @@ unsigned int aa_hash_size(void) char *aa_calc_hash(void *data, size_t len) { - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(apparmor_tfm)]; - } desc; + SHASH_DESC_ON_STACK(desc, apparmor_tfm); char *hash = NULL; int error = -ENOMEM; @@ -45,16 +42,16 @@ char *aa_calc_hash(void *data, size_t len) if (!hash) goto fail; - desc.shash.tfm = apparmor_tfm; - desc.shash.flags = 0; + desc->tfm = apparmor_tfm; + desc->flags = 0; - error = crypto_shash_init(&desc.shash); + error = crypto_shash_init(desc); if (error) goto fail; - error = crypto_shash_update(&desc.shash, (u8 *) data, len); + error = crypto_shash_update(desc, (u8 *) data, len); if (error) goto fail; - error = crypto_shash_final(&desc.shash, hash); + error = crypto_shash_final(desc, hash); if (error) goto fail; @@ -69,10 +66,7 @@ fail: int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, size_t len) { - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(apparmor_tfm)]; - } desc; + SHASH_DESC_ON_STACK(desc, apparmor_tfm); int error = -ENOMEM; __le32 le32_version = cpu_to_le32(version); @@ -86,19 +80,19 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, if (!profile->hash) goto fail; - desc.shash.tfm = apparmor_tfm; - desc.shash.flags = 0; + desc->tfm = apparmor_tfm; + desc->flags = 0; - error = crypto_shash_init(&desc.shash); + error = crypto_shash_init(desc); if (error) goto fail; - error = crypto_shash_update(&desc.shash, (u8 *) &le32_version, 4); + error = crypto_shash_update(desc, (u8 *) &le32_version, 4); if (error) goto fail; - error = crypto_shash_update(&desc.shash, (u8 *) start, len); + error = crypto_shash_update(desc, (u8 *) start, len); if (error) goto fail; - error = crypto_shash_final(&desc.shash, profile->hash); + error = crypto_shash_final(desc, profile->hash); if (error) goto fail; -- cgit v1.1 From b9b144bcafbdd53f68e227968009327b76db08a4 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 6 Apr 2017 06:55:22 -0700 Subject: apparmor: fix invalid reference to index variable of iterator line 836 Once the loop on lines 836-853 is complete and exits normally, ent is a pointer to the dummy list head value. The derefernces accessible from eg the goto fail on line 860 or the various goto fail_lock's afterwards thus seem incorrect. Reported-by: Julia Lawall Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/policy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index def1fbd..cf9d670 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -876,9 +876,11 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, if (ns_name) { ns = aa_prepare_ns(view, ns_name); if (IS_ERR(ns)) { + op = OP_PROF_LOAD; info = "failed to prepare namespace"; error = PTR_ERR(ns); ns = NULL; + ent = NULL; goto fail; } } else @@ -1013,7 +1015,7 @@ fail_lock: /* audit cause of failure */ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; fail: - audit_policy(profile, op, ns_name, ent->new->base.hname, + audit_policy(profile, op, ns_name, ent ? ent->new->base.hname : NULL, info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; @@ -1023,7 +1025,7 @@ fail: /* skip entry that caused failure */ continue; } - op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; + op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL; audit_policy(profile, op, ns_name, tmp->new->base.hname, info, error); } -- cgit v1.1 From 545de8fe0f1b3b97d6a29a78ccdc3403a8296710 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 6 Apr 2017 06:55:23 -0700 Subject: apparmor: fix parameters so that the permission test is bypassed at boot Boot parameters are written before apparmor is ready to answer whether the user is policy_view_capable(). Setting the parameters at boot results in an oops and failure to boot. Setting the parameters at boot is obviously allowed so skip the permission check when apparmor is not initialized. While we are at it move the more complicated check to last. Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/include/lib.h | 2 +- security/apparmor/lsm.c | 47 +++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 26 deletions(-) (limited to 'security') diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 65ff492..0291ff3 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -57,7 +57,7 @@ pr_err_ratelimited("AppArmor: " fmt, ##args) /* Flag indicating whether initialization completed */ -extern int apparmor_initialized __initdata; +extern int apparmor_initialized; /* fn's in lib */ char *aa_split_fqname(char *args, char **ns_name); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 4aa9447..35444c8 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -39,7 +39,7 @@ #include "include/procattr.h" /* Flag indicating whether initialization completed */ -int apparmor_initialized __initdata; +int apparmor_initialized; DEFINE_PER_CPU(struct aa_buffers, aa_buffers); @@ -738,78 +738,77 @@ __setup("apparmor=", apparmor_enabled_setup); /* set global flag turning off the ability to load policy */ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable(NULL)) + if (!apparmor_enabled) + return -EINVAL; + if (apparmor_initialized && !policy_admin_capable(NULL)) return -EPERM; return param_set_bool(val, kp); } static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable(NULL)) - return -EPERM; if (!apparmor_enabled) return -EINVAL; + if (apparmor_initialized && !policy_view_capable(NULL)) + return -EPERM; return param_get_bool(buffer, kp); } static int param_set_aabool(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable(NULL)) - return -EPERM; if (!apparmor_enabled) return -EINVAL; + if (apparmor_initialized && !policy_admin_capable(NULL)) + return -EPERM; return param_set_bool(val, kp); } static int param_get_aabool(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable(NULL)) - return -EPERM; if (!apparmor_enabled) return -EINVAL; + if (apparmor_initialized && !policy_view_capable(NULL)) + return -EPERM; return param_get_bool(buffer, kp); } static int param_set_aauint(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable(NULL)) - return -EPERM; if (!apparmor_enabled) return -EINVAL; + if (apparmor_initialized && !policy_admin_capable(NULL)) + return -EPERM; return param_set_uint(val, kp); } static int param_get_aauint(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable(NULL)) - return -EPERM; if (!apparmor_enabled) return -EINVAL; + if (apparmor_initialized && !policy_view_capable(NULL)) + return -EPERM; return param_get_uint(buffer, kp); } static int param_get_audit(char *buffer, struct kernel_param *kp) { - if (!policy_view_capable(NULL)) - return -EPERM; - if (!apparmor_enabled) return -EINVAL; - + if (apparmor_initialized && !policy_view_capable(NULL)) + return -EPERM; return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); } static int param_set_audit(const char *val, struct kernel_param *kp) { int i; - if (!policy_admin_capable(NULL)) - return -EPERM; if (!apparmor_enabled) return -EINVAL; - if (!val) return -EINVAL; + if (apparmor_initialized && !policy_admin_capable(NULL)) + return -EPERM; for (i = 0; i < AUDIT_MAX_INDEX; i++) { if (strcmp(val, audit_mode_names[i]) == 0) { @@ -823,11 +822,10 @@ static int param_set_audit(const char *val, struct kernel_param *kp) static int param_get_mode(char *buffer, struct kernel_param *kp) { - if (!policy_view_capable(NULL)) - return -EPERM; - if (!apparmor_enabled) return -EINVAL; + if (apparmor_initialized && !policy_view_capable(NULL)) + return -EPERM; return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); } @@ -835,14 +833,13 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) static int param_set_mode(const char *val, struct kernel_param *kp) { int i; - if (!policy_admin_capable(NULL)) - return -EPERM; if (!apparmor_enabled) return -EINVAL; - if (!val) return -EINVAL; + if (apparmor_initialized && !policy_admin_capable(NULL)) + return -EPERM; for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) { if (strcmp(val, aa_profile_mode_names[i]) == 0) { -- cgit v1.1 From 622f6e3265707ebf02ba776ac6e68003bcc31213 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 6 Apr 2017 06:55:24 -0700 Subject: apparmor: Make path_max parameter readonly The path_max parameter determines the max size of buffers allocated but it should not be setable at run time. If can be used to cause an oops root@ubuntu:~# echo 16777216 > /sys/module/apparmor/parameters/path_max root@ubuntu:~# cat /sys/module/apparmor/parameters/path_max Killed [ 122.141911] BUG: unable to handle kernel paging request at ffff880080945fff [ 122.143497] IP: [] d_absolute_path+0x44/0xa0 [ 122.144742] PGD 220c067 PUD 0 [ 122.145453] Oops: 0002 [#1] SMP [ 122.146204] Modules linked in: vmw_vsock_vmci_transport vsock ppdev vmw_balloon snd_ens1371 btusb snd_ac97_codec gameport snd_rawmidi btrtl snd_seq_device ac97_bus btbcm btintel snd_pcm input_leds bluetooth snd_timer snd joydev soundcore serio_raw coretemp shpchp nfit parport_pc i2c_piix4 8250_fintek vmw_vmci parport mac_hid ib_iser rdma_cm iw_cm ib_cm ib_sa ib_mad ib_core ib_addr iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 btrfs raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid crct10dif_pclmul crc32_pclmul ghash_clmulni_intel aesni_intel aes_x86_64 lrw gf128mul glue_helper ablk_helper cryptd vmwgfx psmouse mptspi ttm mptscsih drm_kms_helper mptbase syscopyarea scsi_transport_spi sysfillrect [ 122.163365] ahci sysimgblt e1000 fb_sys_fops libahci drm pata_acpi fjes [ 122.164747] CPU: 3 PID: 1501 Comm: bash Not tainted 4.4.0-59-generic #80-Ubuntu [ 122.166250] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015 [ 122.168611] task: ffff88003496aa00 ti: ffff880076474000 task.ti: ffff880076474000 [ 122.170018] RIP: 0010:[] [] d_absolute_path+0x44/0xa0 [ 122.171525] RSP: 0018:ffff880076477b90 EFLAGS: 00010206 [ 122.172462] RAX: ffff880080945fff RBX: 0000000000000000 RCX: 0000000001000000 [ 122.173709] RDX: 0000000000ffffff RSI: ffff880080946000 RDI: ffff8800348a1010 [ 122.174978] RBP: ffff880076477bb8 R08: ffff880076477c80 R09: 0000000000000000 [ 122.176227] R10: 00007ffffffff000 R11: ffff88007f946000 R12: ffff88007f946000 [ 122.177496] R13: ffff880076477c80 R14: ffff8800348a1010 R15: ffff8800348a2400 [ 122.178745] FS: 00007fd459eb4700(0000) GS:ffff88007b6c0000(0000) knlGS:0000000000000000 [ 122.180176] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 122.181186] CR2: ffff880080945fff CR3: 0000000073422000 CR4: 00000000001406e0 [ 122.182469] Stack: [ 122.182843] 00ffffff00000001 ffff880080946000 0000000000000000 0000000000000000 [ 122.184409] 00000000570f789c ffff880076477c30 ffffffff81385671 ffff88007a2e7a58 [ 122.185810] 0000000000000000 ffff880076477c88 01000000008a1000 0000000000000000 [ 122.187231] Call Trace: [ 122.187680] [] aa_path_name+0x81/0x370 [ 122.188637] [] profile_transition+0xbd/0xb80 [ 122.190181] [] ? zone_statistics+0x7c/0xa0 [ 122.191674] [] apparmor_bprm_set_creds+0x9b0/0xac0 [ 122.193288] [] ? ext4_xattr_get+0x81/0x220 [ 122.194793] [] ? ext4_xattr_security_get+0x1c/0x30 [ 122.196392] [] ? get_vfs_caps_from_disk+0x69/0x110 [ 122.198004] [] ? mnt_may_suid+0x3f/0x50 [ 122.199737] [] ? cap_bprm_set_creds+0xa3/0x600 [ 122.201377] [] security_bprm_set_creds+0x33/0x50 [ 122.203024] [] prepare_binprm+0x85/0x190 [ 122.204515] [] do_execveat_common.isra.33+0x485/0x710 [ 122.206200] [] SyS_execve+0x3a/0x50 [ 122.207615] [] stub_execve+0x5/0x5 [ 122.208978] [] ? entry_SYSCALL_64_fastpath+0x16/0x71 [ 122.210615] Code: f8 31 c0 48 63 c2 83 ea 01 48 c7 45 e8 00 00 00 00 48 01 c6 85 d2 48 c7 45 f0 00 00 00 00 48 89 75 e0 89 55 dc 78 0c 48 8d 46 ff 46 ff 00 48 89 45 e0 48 8d 55 e0 48 8d 4d dc 48 8d 75 e8 e8 [ 122.217320] RIP [] d_absolute_path+0x44/0xa0 [ 122.218860] RSP [ 122.219919] CR2: ffff880080945fff [ 122.220936] ---[ end trace 506cdbd85eb6c55e ]--- Reported-by: Tetsuo Handa Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 35444c8..8f3c0f7 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -710,7 +710,7 @@ module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR); /* Maximum pathname length before accesses will start getting rejected */ unsigned int aa_g_path_max = 2 * PATH_MAX; -module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR); +module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); /* Determines how paranoid loading of policy is and how much verification * on the loaded policy is done. -- cgit v1.1 From 4cd4ca7cc848bedc70b5d0acac9d1ae33d73513a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Tue, 11 Apr 2017 13:07:07 +0200 Subject: keys: select CONFIG_CRYPTO when selecting DH / KDF Select CONFIG_CRYPTO in addition to CONFIG_HASH to ensure that also CONFIG_HASH2 is selected. Both are needed for the shash cipher support required for the KDF operation. Signed-off-by: Stephan Mueller Signed-off-by: David Howells --- security/keys/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'security') diff --git a/security/keys/Kconfig b/security/keys/Kconfig index 4ac1b83..6fd95f7 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -90,6 +90,7 @@ config KEY_DH_OPERATIONS bool "Diffie-Hellman operations on retained keys" depends on KEYS select MPILIB + select CRYPTO select CRYPTO_HASH help This option provides support for calculating Diffie-Hellman -- cgit v1.1