From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefan Berger Subject: [RFC PATCH v3 1/3] ima: extend clone() with IMA namespace support Date: Tue, 27 Mar 2018 09:57:16 -0400 Message-ID: <1522159038-14175-2-git-send-email-stefanb@linux.vnet.ibm.com> References: <1522159038-14175-1-git-send-email-stefanb@linux.vnet.ibm.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1522159038-14175-1-git-send-email-stefanb-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org Errors-To: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org To: linux-integrity-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Cc: mkayaalp-4hyTIkVWTs8LubxHQvXPfYdd74u8MsAO@public.gmane.org, Mehmet Kayaalp , sunyuqiong1988-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org, containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, david.safford-JJi787mZWgc@public.gmane.org, James.Bottomley-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org, linux-security-module-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org, Yuqiong Sun , zohar-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org List-Id: containers.vger.kernel.org From: Yuqiong Sun Add new CONFIG_IMA_NS config option. Let clone() create a new IMA namespace upon CLONE_NEWUSER flag. Attach the ima_ns data structure to user_namespace. ima_ns is allocated and freed upon IMA namespace creation and exit, which is tied to USER namespace creation and exit. Currently, the ima_ns contains no useful IMA data but only a dummy interface. This patch creates the framework for namespacing the different aspects of IMA (eg. IMA-audit, IMA-measurement, IMA-appraisal). Changelog: v3: * Use CLONE_NEWUSER instead of CLONE_NEWNW flag v2: * Moved ima_init_ns and related functions into own file that is always compiled; init_ima_ns will always be there * Fixed putting of imans->parent * Move IMA namespace creation from nsproxy into mount namespace code; get rid of procfs operations for IMA namespace v1: * Use CLONE_NEWNS instead of a new CLONE_NEWIMA flag * Use existing ima.h headers * Move the ima_namespace.c to security/integrity/ima/ima_ns.c * Fix typo INFO->INO * Each namespace free's itself, removed recursively free'ing until init_ima_ns from free_ima_ns() Signed-off-by: Yuqiong Sun Signed-off-by: Mehmet Kayaalp Signed-off-by: Stefan Berger --- include/linux/ima.h | 64 ++++++++++++++++++++++++ include/linux/user_namespace.h | 4 ++ init/Kconfig | 8 +++ kernel/user.c | 7 +++ kernel/user_namespace.c | 18 +++++++ security/integrity/ima/Makefile | 3 +- security/integrity/ima/ima.h | 4 ++ security/integrity/ima/ima_init.c | 4 ++ security/integrity/ima/ima_init_ima_ns.c | 37 ++++++++++++++ security/integrity/ima/ima_ns.c | 86 ++++++++++++++++++++++++++++++++ 10 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 security/integrity/ima/ima_init_ima_ns.c create mode 100644 security/integrity/ima/ima_ns.c diff --git a/include/linux/ima.h b/include/linux/ima.h index 0e4647e0eb60..8bca67df0ad3 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -12,6 +12,7 @@ #include #include +#include struct linux_binprm; #ifdef CONFIG_IMA @@ -105,4 +106,67 @@ static inline int ima_inode_removexattr(struct dentry *dentry, return 0; } #endif /* CONFIG_IMA_APPRAISE */ + +struct ima_namespace { + struct kref kref; + struct ima_namespace *parent; +}; + +extern struct ima_namespace init_ima_ns; + +void imans_install(struct ns_common *new); + +static inline struct ima_namespace *to_ima_ns(struct ns_common *ns) +{ + return container_of(ns, struct user_namespace, ns)->ima_ns; +} + +#ifdef CONFIG_IMA_NS + +void free_ima_ns(struct kref *kref); + +static inline struct ima_namespace *get_ima_ns(struct ima_namespace *ns) +{ + BUG_ON(!ns); + if (ns) + kref_get(&ns->kref); + return ns; +} + +static inline void put_ima_ns(struct ima_namespace *ns) +{ + BUG_ON(!ns); + if (ns) + kref_put(&ns->kref, free_ima_ns); +} + +struct ima_namespace *copy_ima(struct ima_namespace *old_ns); + +static inline struct ima_namespace *get_current_ns(void) +{ + return current_user_ns()->ima_ns; +} + +#else + +static inline struct ima_namespace *get_ima_ns(struct ima_namespace *ns) +{ + return ns; +} + +static inline void put_ima_ns(struct ima_namespace *ns) +{ + return; +} + +static inline struct ima_namespace *copy_ima(struct ima_namespace *old_ns) +{ + return old_ns; +} + +static inline struct ima_namespace *get_current_ns(void) +{ + return NULL; +} +#endif /* CONFIG_IMA_NS */ #endif /* _LINUX_IMA_H */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index d6b74b91096b..8884b22d991c 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -36,6 +36,7 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */ #define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED struct ucounts; +struct ima_namespace; enum ucount_type { UCOUNT_USER_NAMESPACES, @@ -76,6 +77,9 @@ struct user_namespace { #endif struct ucounts *ucounts; int ucount_max[UCOUNT_COUNTS]; +#ifdef CONFIG_IMA + struct ima_namespace *ima_ns; +#endif } __randomize_layout; struct ucounts { diff --git a/init/Kconfig b/init/Kconfig index a9a2e2c86671..a1ad5384e081 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -931,6 +931,14 @@ config NET_NS help Allow user space to create what appear to be multiple instances of the network stack. +config IMA_NS + bool "IMA namespace" + depends on IMA + default y + help + Allow the creation of IMA namespaces for each mount namespace. + Namespaced IMA data enables having IMA features work separately + for each mount namespace. endif # NAMESPACES diff --git a/kernel/user.c b/kernel/user.c index 9a20acce460d..31c946f3adce 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -19,6 +19,10 @@ #include #include +#ifdef CONFIG_IMA +extern struct ima_namespace init_ima_ns; +#endif + /* * userns count is 1 for root user, 1 for init_uts_ns, * and 1 for... ? @@ -66,6 +70,9 @@ struct user_namespace init_user_ns = { .persistent_keyring_register_sem = __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), #endif +#ifdef CONFIG_IMA + .ima_ns = &init_ima_ns, +#endif }; EXPORT_SYMBOL_GPL(init_user_ns); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 246d4d4ce5c7..7d6e7d6e6a34 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -25,6 +25,7 @@ #include #include #include +#include static struct kmem_cache *user_ns_cachep __read_mostly; static DEFINE_MUTEX(userns_state_mutex); @@ -140,8 +141,20 @@ int create_user_ns(struct cred *new) if (!setup_userns_sysctls(ns)) goto fail_keyring; +#if CONFIG_IMA + ns->ima_ns = copy_ima(parent_ns->ima_ns); + if (IS_ERR(ns->ima_ns)) { + ret = PTR_ERR(ns->ima_ns); + goto fail_userns_sysctls; + } +#endif + set_cred_user_ns(new, ns); return 0; +#if CONFIG_IMA +fail_userns_sysctls: + retire_userns_sysctls(ns); +#endif fail_keyring: #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); @@ -195,6 +208,9 @@ static void free_user_ns(struct work_struct *work) kfree(ns->projid_map.forward); kfree(ns->projid_map.reverse); } +#ifdef CONFIG_IMA + put_ima_ns(ns->ima_ns); +#endif retire_userns_sysctls(ns); #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); @@ -1285,6 +1301,8 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns) put_user_ns(cred->user_ns); set_cred_user_ns(cred, get_user_ns(user_ns)); + imans_install(ns); + return commit_creds(cred); } diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index d921dc4f9eb0..cc60f726e651 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -7,7 +7,8 @@ obj-$(CONFIG_IMA) += ima.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ - ima_policy.o ima_template.o ima_template_lib.o + ima_policy.o ima_template.o ima_template_lib.o ima_init_ima_ns.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o +ima-$(CONFIG_IMA_NS) += ima_ns.o ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index d52b487ad259..e98c11c7cf75 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -291,6 +291,10 @@ static inline int ima_read_xattr(struct dentry *dentry, #endif /* CONFIG_IMA_APPRAISE */ +int ima_ns_init(void); +struct ima_namespace; +int ima_init_namespace(struct ima_namespace *ns); + /* LSM based policy rules require audit */ #ifdef CONFIG_IMA_LSM_RULES diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 2967d497a665..7f884a71fa1c 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -137,5 +137,9 @@ int __init ima_init(void) ima_init_policy(); + rc = ima_ns_init(); + if (rc != 0) + return rc; + return ima_fs_init(); } diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c new file mode 100644 index 000000000000..52cb94b1d392 --- /dev/null +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + * + * 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, version 2 of the License. + */ + +#include +#include +#include + +int ima_init_namespace(struct ima_namespace *ns) +{ + return 0; +} + +int __init ima_ns_init(void) +{ + return ima_init_namespace(&init_ima_ns); +} + +struct ima_namespace init_ima_ns = { + .kref = KREF_INIT(1), + .parent = NULL, +}; +EXPORT_SYMBOL(init_ima_ns); + +void imans_install(struct ns_common *new) +{ + struct ima_namespace *ns = to_ima_ns(new); + + get_ima_ns(ns); +} diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c new file mode 100644 index 000000000000..62148908015a --- /dev/null +++ b/security/integrity/ima/ima_ns.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + * + * 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, version 2 of the License. + */ + +#include +#include +#include +#include + +#include "ima.h" + +static struct ima_namespace *create_ima_ns(void) +{ + struct ima_namespace *ima_ns; + + ima_ns = kmalloc(sizeof(*ima_ns), GFP_KERNEL); + if (ima_ns) + kref_init(&ima_ns->kref); + + return ima_ns; +} + +/** + * Clone a new ns copying an original ima namespace, setting refcount to 1 + * + * @old_ns: old ima namespace to clone + * Return ERR_PTR(-ENOMEM) on error (failure to kmalloc), new ns otherwise + */ +static struct ima_namespace *clone_ima_ns(struct ima_namespace *old_ns) +{ + struct ima_namespace *ns; + + ns = create_ima_ns(); + if (!ns) + return ERR_PTR(-ENOMEM); + + get_ima_ns(old_ns); + ns->parent = old_ns; + + ima_init_namespace(ns); + + return ns; +} + +/** + * Copy task's ima namespace, or clone it if flags specifies CLONE_NEWNS. + * + * @flags: flags used in the clone syscall + * @old_ns: old ima namespace to clone + */ + +struct ima_namespace *copy_ima(struct ima_namespace *old_ns) +{ + struct ima_namespace *new_ns; + + BUG_ON(!old_ns); + get_ima_ns(old_ns); + + new_ns = clone_ima_ns(old_ns); + put_ima_ns(old_ns); + + return new_ns; +} + +static void destroy_ima_ns(struct ima_namespace *ns) +{ + put_ima_ns(ns->parent); + kfree(ns); +} + +void free_ima_ns(struct kref *kref) +{ + struct ima_namespace *ns; + + ns = container_of(kref, struct ima_namespace, kref); + BUG_ON(ns == &init_ima_ns); + + destroy_ima_ns(ns); +} -- 2.14.3 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752850AbeC0N53 (ORCPT ); Tue, 27 Mar 2018 09:57:29 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:49720 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752275AbeC0N51 (ORCPT ); Tue, 27 Mar 2018 09:57:27 -0400 From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: containers@lists.linux-foundation.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, tycho@docker.com, serge@hallyn.com, sunyuqiong1988@gmail.com, david.safford@ge.com, mkayaalp@cs.binghamton.edu, James.Bottomley@HansenPartnership.com, zohar@linux.vnet.ibm.com, ebiederm@xmission.com, Yuqiong Sun , Mehmet Kayaalp , Stefan Berger Subject: [RFC PATCH v3 1/3] ima: extend clone() with IMA namespace support Date: Tue, 27 Mar 2018 09:57:16 -0400 X-Mailer: git-send-email 2.5.5 In-Reply-To: <1522159038-14175-1-git-send-email-stefanb@linux.vnet.ibm.com> References: <1522159038-14175-1-git-send-email-stefanb@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18032713-0024-0000-0000-0000033C975B X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008753; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000255; SDB=6.01009168; UDB=6.00514062; IPR=6.00788450; MB=3.00020268; MTD=3.00000008; XFM=3.00000015; UTC=2018-03-27 13:57:24 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18032713-0025-0000-0000-000047760B05 Message-Id: <1522159038-14175-2-git-send-email-stefanb@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2018-03-27_06:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=3 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1803270141 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Yuqiong Sun Add new CONFIG_IMA_NS config option. Let clone() create a new IMA namespace upon CLONE_NEWUSER flag. Attach the ima_ns data structure to user_namespace. ima_ns is allocated and freed upon IMA namespace creation and exit, which is tied to USER namespace creation and exit. Currently, the ima_ns contains no useful IMA data but only a dummy interface. This patch creates the framework for namespacing the different aspects of IMA (eg. IMA-audit, IMA-measurement, IMA-appraisal). Changelog: v3: * Use CLONE_NEWUSER instead of CLONE_NEWNW flag v2: * Moved ima_init_ns and related functions into own file that is always compiled; init_ima_ns will always be there * Fixed putting of imans->parent * Move IMA namespace creation from nsproxy into mount namespace code; get rid of procfs operations for IMA namespace v1: * Use CLONE_NEWNS instead of a new CLONE_NEWIMA flag * Use existing ima.h headers * Move the ima_namespace.c to security/integrity/ima/ima_ns.c * Fix typo INFO->INO * Each namespace free's itself, removed recursively free'ing until init_ima_ns from free_ima_ns() Signed-off-by: Yuqiong Sun Signed-off-by: Mehmet Kayaalp Signed-off-by: Stefan Berger --- include/linux/ima.h | 64 ++++++++++++++++++++++++ include/linux/user_namespace.h | 4 ++ init/Kconfig | 8 +++ kernel/user.c | 7 +++ kernel/user_namespace.c | 18 +++++++ security/integrity/ima/Makefile | 3 +- security/integrity/ima/ima.h | 4 ++ security/integrity/ima/ima_init.c | 4 ++ security/integrity/ima/ima_init_ima_ns.c | 37 ++++++++++++++ security/integrity/ima/ima_ns.c | 86 ++++++++++++++++++++++++++++++++ 10 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 security/integrity/ima/ima_init_ima_ns.c create mode 100644 security/integrity/ima/ima_ns.c diff --git a/include/linux/ima.h b/include/linux/ima.h index 0e4647e0eb60..8bca67df0ad3 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -12,6 +12,7 @@ #include #include +#include struct linux_binprm; #ifdef CONFIG_IMA @@ -105,4 +106,67 @@ static inline int ima_inode_removexattr(struct dentry *dentry, return 0; } #endif /* CONFIG_IMA_APPRAISE */ + +struct ima_namespace { + struct kref kref; + struct ima_namespace *parent; +}; + +extern struct ima_namespace init_ima_ns; + +void imans_install(struct ns_common *new); + +static inline struct ima_namespace *to_ima_ns(struct ns_common *ns) +{ + return container_of(ns, struct user_namespace, ns)->ima_ns; +} + +#ifdef CONFIG_IMA_NS + +void free_ima_ns(struct kref *kref); + +static inline struct ima_namespace *get_ima_ns(struct ima_namespace *ns) +{ + BUG_ON(!ns); + if (ns) + kref_get(&ns->kref); + return ns; +} + +static inline void put_ima_ns(struct ima_namespace *ns) +{ + BUG_ON(!ns); + if (ns) + kref_put(&ns->kref, free_ima_ns); +} + +struct ima_namespace *copy_ima(struct ima_namespace *old_ns); + +static inline struct ima_namespace *get_current_ns(void) +{ + return current_user_ns()->ima_ns; +} + +#else + +static inline struct ima_namespace *get_ima_ns(struct ima_namespace *ns) +{ + return ns; +} + +static inline void put_ima_ns(struct ima_namespace *ns) +{ + return; +} + +static inline struct ima_namespace *copy_ima(struct ima_namespace *old_ns) +{ + return old_ns; +} + +static inline struct ima_namespace *get_current_ns(void) +{ + return NULL; +} +#endif /* CONFIG_IMA_NS */ #endif /* _LINUX_IMA_H */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index d6b74b91096b..8884b22d991c 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -36,6 +36,7 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */ #define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED struct ucounts; +struct ima_namespace; enum ucount_type { UCOUNT_USER_NAMESPACES, @@ -76,6 +77,9 @@ struct user_namespace { #endif struct ucounts *ucounts; int ucount_max[UCOUNT_COUNTS]; +#ifdef CONFIG_IMA + struct ima_namespace *ima_ns; +#endif } __randomize_layout; struct ucounts { diff --git a/init/Kconfig b/init/Kconfig index a9a2e2c86671..a1ad5384e081 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -931,6 +931,14 @@ config NET_NS help Allow user space to create what appear to be multiple instances of the network stack. +config IMA_NS + bool "IMA namespace" + depends on IMA + default y + help + Allow the creation of IMA namespaces for each mount namespace. + Namespaced IMA data enables having IMA features work separately + for each mount namespace. endif # NAMESPACES diff --git a/kernel/user.c b/kernel/user.c index 9a20acce460d..31c946f3adce 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -19,6 +19,10 @@ #include #include +#ifdef CONFIG_IMA +extern struct ima_namespace init_ima_ns; +#endif + /* * userns count is 1 for root user, 1 for init_uts_ns, * and 1 for... ? @@ -66,6 +70,9 @@ struct user_namespace init_user_ns = { .persistent_keyring_register_sem = __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), #endif +#ifdef CONFIG_IMA + .ima_ns = &init_ima_ns, +#endif }; EXPORT_SYMBOL_GPL(init_user_ns); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 246d4d4ce5c7..7d6e7d6e6a34 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -25,6 +25,7 @@ #include #include #include +#include static struct kmem_cache *user_ns_cachep __read_mostly; static DEFINE_MUTEX(userns_state_mutex); @@ -140,8 +141,20 @@ int create_user_ns(struct cred *new) if (!setup_userns_sysctls(ns)) goto fail_keyring; +#if CONFIG_IMA + ns->ima_ns = copy_ima(parent_ns->ima_ns); + if (IS_ERR(ns->ima_ns)) { + ret = PTR_ERR(ns->ima_ns); + goto fail_userns_sysctls; + } +#endif + set_cred_user_ns(new, ns); return 0; +#if CONFIG_IMA +fail_userns_sysctls: + retire_userns_sysctls(ns); +#endif fail_keyring: #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); @@ -195,6 +208,9 @@ static void free_user_ns(struct work_struct *work) kfree(ns->projid_map.forward); kfree(ns->projid_map.reverse); } +#ifdef CONFIG_IMA + put_ima_ns(ns->ima_ns); +#endif retire_userns_sysctls(ns); #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); @@ -1285,6 +1301,8 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns) put_user_ns(cred->user_ns); set_cred_user_ns(cred, get_user_ns(user_ns)); + imans_install(ns); + return commit_creds(cred); } diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index d921dc4f9eb0..cc60f726e651 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -7,7 +7,8 @@ obj-$(CONFIG_IMA) += ima.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ - ima_policy.o ima_template.o ima_template_lib.o + ima_policy.o ima_template.o ima_template_lib.o ima_init_ima_ns.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o +ima-$(CONFIG_IMA_NS) += ima_ns.o ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index d52b487ad259..e98c11c7cf75 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -291,6 +291,10 @@ static inline int ima_read_xattr(struct dentry *dentry, #endif /* CONFIG_IMA_APPRAISE */ +int ima_ns_init(void); +struct ima_namespace; +int ima_init_namespace(struct ima_namespace *ns); + /* LSM based policy rules require audit */ #ifdef CONFIG_IMA_LSM_RULES diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 2967d497a665..7f884a71fa1c 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -137,5 +137,9 @@ int __init ima_init(void) ima_init_policy(); + rc = ima_ns_init(); + if (rc != 0) + return rc; + return ima_fs_init(); } diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c new file mode 100644 index 000000000000..52cb94b1d392 --- /dev/null +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + * + * 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, version 2 of the License. + */ + +#include +#include +#include + +int ima_init_namespace(struct ima_namespace *ns) +{ + return 0; +} + +int __init ima_ns_init(void) +{ + return ima_init_namespace(&init_ima_ns); +} + +struct ima_namespace init_ima_ns = { + .kref = KREF_INIT(1), + .parent = NULL, +}; +EXPORT_SYMBOL(init_ima_ns); + +void imans_install(struct ns_common *new) +{ + struct ima_namespace *ns = to_ima_ns(new); + + get_ima_ns(ns); +} diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c new file mode 100644 index 000000000000..62148908015a --- /dev/null +++ b/security/integrity/ima/ima_ns.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + * + * 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, version 2 of the License. + */ + +#include +#include +#include +#include + +#include "ima.h" + +static struct ima_namespace *create_ima_ns(void) +{ + struct ima_namespace *ima_ns; + + ima_ns = kmalloc(sizeof(*ima_ns), GFP_KERNEL); + if (ima_ns) + kref_init(&ima_ns->kref); + + return ima_ns; +} + +/** + * Clone a new ns copying an original ima namespace, setting refcount to 1 + * + * @old_ns: old ima namespace to clone + * Return ERR_PTR(-ENOMEM) on error (failure to kmalloc), new ns otherwise + */ +static struct ima_namespace *clone_ima_ns(struct ima_namespace *old_ns) +{ + struct ima_namespace *ns; + + ns = create_ima_ns(); + if (!ns) + return ERR_PTR(-ENOMEM); + + get_ima_ns(old_ns); + ns->parent = old_ns; + + ima_init_namespace(ns); + + return ns; +} + +/** + * Copy task's ima namespace, or clone it if flags specifies CLONE_NEWNS. + * + * @flags: flags used in the clone syscall + * @old_ns: old ima namespace to clone + */ + +struct ima_namespace *copy_ima(struct ima_namespace *old_ns) +{ + struct ima_namespace *new_ns; + + BUG_ON(!old_ns); + get_ima_ns(old_ns); + + new_ns = clone_ima_ns(old_ns); + put_ima_ns(old_ns); + + return new_ns; +} + +static void destroy_ima_ns(struct ima_namespace *ns) +{ + put_ima_ns(ns->parent); + kfree(ns); +} + +void free_ima_ns(struct kref *kref) +{ + struct ima_namespace *ns; + + ns = container_of(kref, struct ima_namespace, kref); + BUG_ON(ns == &init_ima_ns); + + destroy_ima_ns(ns); +} -- 2.14.3 From mboxrd@z Thu Jan 1 00:00:00 1970 From: stefanb@linux.vnet.ibm.com (Stefan Berger) Date: Tue, 27 Mar 2018 09:57:16 -0400 Subject: [RFC PATCH v3 1/3] ima: extend clone() with IMA namespace support In-Reply-To: <1522159038-14175-1-git-send-email-stefanb@linux.vnet.ibm.com> References: <1522159038-14175-1-git-send-email-stefanb@linux.vnet.ibm.com> Message-ID: <1522159038-14175-2-git-send-email-stefanb@linux.vnet.ibm.com> To: linux-security-module@vger.kernel.org List-Id: linux-security-module.vger.kernel.org From: Yuqiong Sun Add new CONFIG_IMA_NS config option. Let clone() create a new IMA namespace upon CLONE_NEWUSER flag. Attach the ima_ns data structure to user_namespace. ima_ns is allocated and freed upon IMA namespace creation and exit, which is tied to USER namespace creation and exit. Currently, the ima_ns contains no useful IMA data but only a dummy interface. This patch creates the framework for namespacing the different aspects of IMA (eg. IMA-audit, IMA-measurement, IMA-appraisal). Changelog: v3: * Use CLONE_NEWUSER instead of CLONE_NEWNW flag v2: * Moved ima_init_ns and related functions into own file that is always compiled; init_ima_ns will always be there * Fixed putting of imans->parent * Move IMA namespace creation from nsproxy into mount namespace code; get rid of procfs operations for IMA namespace v1: * Use CLONE_NEWNS instead of a new CLONE_NEWIMA flag * Use existing ima.h headers * Move the ima_namespace.c to security/integrity/ima/ima_ns.c * Fix typo INFO->INO * Each namespace free's itself, removed recursively free'ing until init_ima_ns from free_ima_ns() Signed-off-by: Yuqiong Sun Signed-off-by: Mehmet Kayaalp Signed-off-by: Stefan Berger --- include/linux/ima.h | 64 ++++++++++++++++++++++++ include/linux/user_namespace.h | 4 ++ init/Kconfig | 8 +++ kernel/user.c | 7 +++ kernel/user_namespace.c | 18 +++++++ security/integrity/ima/Makefile | 3 +- security/integrity/ima/ima.h | 4 ++ security/integrity/ima/ima_init.c | 4 ++ security/integrity/ima/ima_init_ima_ns.c | 37 ++++++++++++++ security/integrity/ima/ima_ns.c | 86 ++++++++++++++++++++++++++++++++ 10 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 security/integrity/ima/ima_init_ima_ns.c create mode 100644 security/integrity/ima/ima_ns.c diff --git a/include/linux/ima.h b/include/linux/ima.h index 0e4647e0eb60..8bca67df0ad3 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -12,6 +12,7 @@ #include #include +#include struct linux_binprm; #ifdef CONFIG_IMA @@ -105,4 +106,67 @@ static inline int ima_inode_removexattr(struct dentry *dentry, return 0; } #endif /* CONFIG_IMA_APPRAISE */ + +struct ima_namespace { + struct kref kref; + struct ima_namespace *parent; +}; + +extern struct ima_namespace init_ima_ns; + +void imans_install(struct ns_common *new); + +static inline struct ima_namespace *to_ima_ns(struct ns_common *ns) +{ + return container_of(ns, struct user_namespace, ns)->ima_ns; +} + +#ifdef CONFIG_IMA_NS + +void free_ima_ns(struct kref *kref); + +static inline struct ima_namespace *get_ima_ns(struct ima_namespace *ns) +{ + BUG_ON(!ns); + if (ns) + kref_get(&ns->kref); + return ns; +} + +static inline void put_ima_ns(struct ima_namespace *ns) +{ + BUG_ON(!ns); + if (ns) + kref_put(&ns->kref, free_ima_ns); +} + +struct ima_namespace *copy_ima(struct ima_namespace *old_ns); + +static inline struct ima_namespace *get_current_ns(void) +{ + return current_user_ns()->ima_ns; +} + +#else + +static inline struct ima_namespace *get_ima_ns(struct ima_namespace *ns) +{ + return ns; +} + +static inline void put_ima_ns(struct ima_namespace *ns) +{ + return; +} + +static inline struct ima_namespace *copy_ima(struct ima_namespace *old_ns) +{ + return old_ns; +} + +static inline struct ima_namespace *get_current_ns(void) +{ + return NULL; +} +#endif /* CONFIG_IMA_NS */ #endif /* _LINUX_IMA_H */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index d6b74b91096b..8884b22d991c 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -36,6 +36,7 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */ #define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED struct ucounts; +struct ima_namespace; enum ucount_type { UCOUNT_USER_NAMESPACES, @@ -76,6 +77,9 @@ struct user_namespace { #endif struct ucounts *ucounts; int ucount_max[UCOUNT_COUNTS]; +#ifdef CONFIG_IMA + struct ima_namespace *ima_ns; +#endif } __randomize_layout; struct ucounts { diff --git a/init/Kconfig b/init/Kconfig index a9a2e2c86671..a1ad5384e081 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -931,6 +931,14 @@ config NET_NS help Allow user space to create what appear to be multiple instances of the network stack. +config IMA_NS + bool "IMA namespace" + depends on IMA + default y + help + Allow the creation of IMA namespaces for each mount namespace. + Namespaced IMA data enables having IMA features work separately + for each mount namespace. endif # NAMESPACES diff --git a/kernel/user.c b/kernel/user.c index 9a20acce460d..31c946f3adce 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -19,6 +19,10 @@ #include #include +#ifdef CONFIG_IMA +extern struct ima_namespace init_ima_ns; +#endif + /* * userns count is 1 for root user, 1 for init_uts_ns, * and 1 for... ? @@ -66,6 +70,9 @@ struct user_namespace init_user_ns = { .persistent_keyring_register_sem = __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), #endif +#ifdef CONFIG_IMA + .ima_ns = &init_ima_ns, +#endif }; EXPORT_SYMBOL_GPL(init_user_ns); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 246d4d4ce5c7..7d6e7d6e6a34 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -25,6 +25,7 @@ #include #include #include +#include static struct kmem_cache *user_ns_cachep __read_mostly; static DEFINE_MUTEX(userns_state_mutex); @@ -140,8 +141,20 @@ int create_user_ns(struct cred *new) if (!setup_userns_sysctls(ns)) goto fail_keyring; +#if CONFIG_IMA + ns->ima_ns = copy_ima(parent_ns->ima_ns); + if (IS_ERR(ns->ima_ns)) { + ret = PTR_ERR(ns->ima_ns); + goto fail_userns_sysctls; + } +#endif + set_cred_user_ns(new, ns); return 0; +#if CONFIG_IMA +fail_userns_sysctls: + retire_userns_sysctls(ns); +#endif fail_keyring: #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); @@ -195,6 +208,9 @@ static void free_user_ns(struct work_struct *work) kfree(ns->projid_map.forward); kfree(ns->projid_map.reverse); } +#ifdef CONFIG_IMA + put_ima_ns(ns->ima_ns); +#endif retire_userns_sysctls(ns); #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); @@ -1285,6 +1301,8 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns) put_user_ns(cred->user_ns); set_cred_user_ns(cred, get_user_ns(user_ns)); + imans_install(ns); + return commit_creds(cred); } diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index d921dc4f9eb0..cc60f726e651 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -7,7 +7,8 @@ obj-$(CONFIG_IMA) += ima.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ - ima_policy.o ima_template.o ima_template_lib.o + ima_policy.o ima_template.o ima_template_lib.o ima_init_ima_ns.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o +ima-$(CONFIG_IMA_NS) += ima_ns.o ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index d52b487ad259..e98c11c7cf75 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -291,6 +291,10 @@ static inline int ima_read_xattr(struct dentry *dentry, #endif /* CONFIG_IMA_APPRAISE */ +int ima_ns_init(void); +struct ima_namespace; +int ima_init_namespace(struct ima_namespace *ns); + /* LSM based policy rules require audit */ #ifdef CONFIG_IMA_LSM_RULES diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 2967d497a665..7f884a71fa1c 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -137,5 +137,9 @@ int __init ima_init(void) ima_init_policy(); + rc = ima_ns_init(); + if (rc != 0) + return rc; + return ima_fs_init(); } diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c new file mode 100644 index 000000000000..52cb94b1d392 --- /dev/null +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + * + * 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, version 2 of the License. + */ + +#include +#include +#include + +int ima_init_namespace(struct ima_namespace *ns) +{ + return 0; +} + +int __init ima_ns_init(void) +{ + return ima_init_namespace(&init_ima_ns); +} + +struct ima_namespace init_ima_ns = { + .kref = KREF_INIT(1), + .parent = NULL, +}; +EXPORT_SYMBOL(init_ima_ns); + +void imans_install(struct ns_common *new) +{ + struct ima_namespace *ns = to_ima_ns(new); + + get_ima_ns(ns); +} diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c new file mode 100644 index 000000000000..62148908015a --- /dev/null +++ b/security/integrity/ima/ima_ns.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + * + * 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, version 2 of the License. + */ + +#include +#include +#include +#include + +#include "ima.h" + +static struct ima_namespace *create_ima_ns(void) +{ + struct ima_namespace *ima_ns; + + ima_ns = kmalloc(sizeof(*ima_ns), GFP_KERNEL); + if (ima_ns) + kref_init(&ima_ns->kref); + + return ima_ns; +} + +/** + * Clone a new ns copying an original ima namespace, setting refcount to 1 + * + * @old_ns: old ima namespace to clone + * Return ERR_PTR(-ENOMEM) on error (failure to kmalloc), new ns otherwise + */ +static struct ima_namespace *clone_ima_ns(struct ima_namespace *old_ns) +{ + struct ima_namespace *ns; + + ns = create_ima_ns(); + if (!ns) + return ERR_PTR(-ENOMEM); + + get_ima_ns(old_ns); + ns->parent = old_ns; + + ima_init_namespace(ns); + + return ns; +} + +/** + * Copy task's ima namespace, or clone it if flags specifies CLONE_NEWNS. + * + * @flags: flags used in the clone syscall + * @old_ns: old ima namespace to clone + */ + +struct ima_namespace *copy_ima(struct ima_namespace *old_ns) +{ + struct ima_namespace *new_ns; + + BUG_ON(!old_ns); + get_ima_ns(old_ns); + + new_ns = clone_ima_ns(old_ns); + put_ima_ns(old_ns); + + return new_ns; +} + +static void destroy_ima_ns(struct ima_namespace *ns) +{ + put_ima_ns(ns->parent); + kfree(ns); +} + +void free_ima_ns(struct kref *kref) +{ + struct ima_namespace *ns; + + ns = container_of(kref, struct ima_namespace, kref); + BUG_ON(ns == &init_ima_ns); + + destroy_ima_ns(ns); +} -- 2.14.3 -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html