Received: by 10.223.185.111 with SMTP id b44csp714849wrg; Fri, 9 Mar 2018 12:18:05 -0800 (PST) X-Google-Smtp-Source: AG47ELtXSAO/ziUX7eZ0ZqlguhWWT37/6J9VqkPWCSR9xIKCiksU4sBvjuYmuRzZNFRRW+1V/bqz X-Received: by 2002:a17:902:5482:: with SMTP id e2-v6mr28807628pli.65.1520626685452; Fri, 09 Mar 2018 12:18:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520626685; cv=none; d=google.com; s=arc-20160816; b=MUVvz3us3dcrOA0vUjuOkV+skXNKwqxcryZErDe64BWg4SEs77vgzHmO5hFQiieDSI rcpPG4okNhJ0je/OEA1zPplKqAPU28OiMEx0zbFj3sP5rcUTXl47eXXhR0/JcOfEPcDD VmCPS6a6S+1J222D4inm6oWzvNmiOH0RzvmAV+WrsRelscEnarOkgWz0n2JotNmGepsg fOtBk50tsbDpvy0c0vN2Zo57Q78VgfkJIrrL4C1BSSbDfhCCUw2mb1onoVAPMl2HnW3F g7P/0WOWiTcrL05lqApsipmtfvxeygUTi27KZAkBUfkG3xyfUTGxJZHk5MY70gaNU+r4 xx6w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:references:in-reply-to:date :subject:cc:to:from:arc-authentication-results; bh=06iHfgsoY0mrjIxXr/A1OnlYiJD150r0G9QU3r2KN9g=; b=RhtxDDSsUzSBBdU1Ux1BJk/lAbEB/RAb2p8OIOE31eN0OlGC8W/6EX9uZc9aE5v+KS 6d1dNoquuXImBqUp1STo3hkaUhdo0fp60MY9/Tiz8+dTJIgLXrP0mvNMW/+m4+MQCtq9 T9mHByuIaxrKPzD3YvEa8/ma5/Zp/7u2l8fePwMHsTYV2UjTrBpkhBGqXbqaJf0gxdhQ 8khebcrjRzevX8pPysTdY66vNkUo9MeQkhdGkfhWFvbkPC0alMv4LbZh/l4FtOlq01XX 0aSZKWz50gvSVUwuH8gw8Xc9pTEwDK+c/neXJkJwxyDgKJQTaWQUwAvf7Ngo3EZfDRBZ 9Zzg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f185si1194070pgc.202.2018.03.09.12.17.50; Fri, 09 Mar 2018 12:18:05 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932520AbeCIUOr (ORCPT + 99 others); Fri, 9 Mar 2018 15:14:47 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:47992 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932371AbeCIUOm (ORCPT ); Fri, 9 Mar 2018 15:14:42 -0500 Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w29KD8mQ105350 for ; Fri, 9 Mar 2018 15:14:41 -0500 Received: from e13.ny.us.ibm.com (e13.ny.us.ibm.com [129.33.205.203]) by mx0a-001b2d01.pphosted.com with ESMTP id 2gm0t80q1w-1 (version=TLSv1.2 cipher=AES256-SHA256 bits=256 verify=NOT) for ; Fri, 09 Mar 2018 15:14:41 -0500 Received: from localhost by e13.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 9 Mar 2018 15:14:40 -0500 Received: from b01cxnp23032.gho.pok.ibm.com (9.57.198.27) by e13.ny.us.ibm.com (146.89.104.200) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 9 Mar 2018 15:14:36 -0500 Received: from b01ledav004.gho.pok.ibm.com (b01ledav004.gho.pok.ibm.com [9.57.199.109]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w29KEZNM43450382; Fri, 9 Mar 2018 20:14:35 GMT Received: from b01ledav004.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 107CD11204B; Fri, 9 Mar 2018 15:13:06 -0500 (EST) Received: from localhost.localdomain (unknown [9.47.158.154]) by b01ledav004.gho.pok.ibm.com (Postfix) with ESMTP id DAEB9112040; Fri, 9 Mar 2018 15:13:05 -0500 (EST) From: Stefan Berger To: linux-ima-devel@lists.sourceforge.net 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, linux-integrity@vger.kernel.org, James.Bottomley@HansenPartnership.com, zohar@linux.vnet.ibm.com, Yuqiong Sun , Mehmet Kayaalp , Stefan Berger Subject: [RFC PATCH v2 1/3] ima: extend clone() with IMA namespace support Date: Fri, 9 Mar 2018 15:14:19 -0500 X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180309201421.6150-1-stefanb@linux.vnet.ibm.com> References: <20180309201421.6150-1-stefanb@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18030920-0008-0000-0000-000002E2C1D3 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008642; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000254; SDB=6.01000666; UDB=6.00509012; IPR=6.00779996; MB=3.00019944; MTD=3.00000008; XFM=3.00000015; UTC=2018-03-09 20:14:39 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18030920-0009-0000-0000-0000388350F7 Message-Id: <20180309201421.6150-2-stefanb@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2018-03-09_10:,, 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-1803090239 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk 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_NEWNS flag. Add ima_ns data structure in nsproxy. ima_ns is allocated and freed upon IMA 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: * 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() * Moved ima_init_ns and related functions into own file that is always compiled * Fixed putting of imans->parent * Move IMA namespace creation from nsproxy into mount namespace code Signed-off-by: Yuqiong Sun Signed-off-by: Mehmet Kayaalp Signed-off-by: Stefan Berger --- fs/mount.h | 14 ----- fs/namespace.c | 29 ++++++++-- include/linux/ima.h | 67 +++++++++++++++++++++++ include/linux/mount.h | 20 ++++++- init/Kconfig | 8 +++ kernel/nsproxy.c | 1 + 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 | 38 +++++++++++++ security/integrity/ima/ima_ns.c | 91 ++++++++++++++++++++++++++++++++ 11 files changed, 260 insertions(+), 19 deletions(-) create mode 100644 security/integrity/ima/ima_init_ima_ns.c create mode 100644 security/integrity/ima/ima_ns.c diff --git a/fs/mount.h b/fs/mount.h index f39bc9da4d73..e19ebde97756 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -5,20 +5,6 @@ #include #include -struct mnt_namespace { - atomic_t count; - struct ns_common ns; - struct mount * root; - struct list_head list; - struct user_namespace *user_ns; - struct ucounts *ucounts; - u64 seq; /* Sequence number to prevent loops */ - wait_queue_head_t poll; - u64 event; - unsigned int mounts; /* # of mounts in the namespace */ - unsigned int pending_mounts; -} __randomize_layout; - struct mnt_pcp { int mnt_count; int mnt_writers; diff --git a/fs/namespace.c b/fs/namespace.c index 9d1374ab6e06..7f886c02278b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "pnode.h" #include "internal.h" @@ -2858,6 +2859,7 @@ static void dec_mnt_namespaces(struct ucounts *ucounts) static void free_mnt_ns(struct mnt_namespace *ns) { + put_ima_ns(ns->ima_ns); ns_free_inum(&ns->ns); dec_mnt_namespaces(ns->ucounts); put_user_ns(ns->user_ns); @@ -2873,11 +2875,13 @@ static void free_mnt_ns(struct mnt_namespace *ns) */ static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); -static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) +static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, + struct ima_namespace *ima_ns) { struct mnt_namespace *new_ns; struct ucounts *ucounts; int ret; + int err; ucounts = inc_mnt_namespaces(user_ns); if (!ucounts) @@ -2894,6 +2898,20 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) dec_mnt_namespaces(ucounts); return ERR_PTR(ret); } + + if (ima_ns == NULL) { + new_ns->ima_ns = get_ima_ns(&init_ima_ns); + } else { + new_ns->ima_ns = copy_ima(user_ns, ima_ns); + if (IS_ERR(new_ns->ima_ns)) { + err = PTR_ERR(new_ns->ima_ns); + ns_free_inum(&new_ns->ns); + kfree(new_ns); + dec_mnt_namespaces(ucounts); + return ERR_PTR(err); + } + } + new_ns->ns.ops = &mntns_operations; new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); atomic_set(&new_ns->count, 1); @@ -2920,6 +2938,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, int copy_flags; BUG_ON(!ns); + BUG_ON(!ns->ima_ns); if (likely(!(flags & CLONE_NEWNS))) { get_mnt_ns(ns); @@ -2928,7 +2947,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, old = ns->root; - new_ns = alloc_mnt_ns(user_ns); + new_ns = alloc_mnt_ns(user_ns, ns->ima_ns); if (IS_ERR(new_ns)) return new_ns; @@ -2989,7 +3008,8 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, */ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) { - struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns); + struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns, + NULL); if (!IS_ERR(new_ns)) { struct mount *mnt = real_mount(m); mnt->mnt_ns = new_ns; @@ -3497,6 +3517,9 @@ static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns) set_fs_root(fs, &root); path_put(&root); + + imans_install(nsproxy, ns); + return 0; } diff --git a/include/linux/ima.h b/include/linux/ima.h index 0e4647e0eb60..fd150dfde277 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,70 @@ static inline int ima_inode_removexattr(struct dentry *dentry, return 0; } #endif /* CONFIG_IMA_APPRAISE */ + +struct ima_namespace { + struct kref kref; + struct user_namespace *user_ns; + struct ima_namespace *parent; +}; + +extern struct ima_namespace init_ima_ns; + +void imans_install(struct nsproxy *nsproxy, struct ns_common *new); + +static inline struct ima_namespace *to_ima_ns(struct ns_common *ns) +{ + return container_of(ns, struct mnt_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 user_namespace *user_ns, + struct ima_namespace *old_ns); + +static inline struct ima_namespace *get_current_ns(void) +{ + return current->nsproxy->mnt_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 user_namespace *user_ns, + 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/mount.h b/include/linux/mount.h index 45b1f56c6c2f..361c962ebd3d 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -16,11 +16,29 @@ #include #include #include +#include +#include struct super_block; struct vfsmount; struct dentry; -struct mnt_namespace; +struct ima_namespace; + +struct mnt_namespace { + atomic_t count; + struct ns_common ns; + struct mount * root; + struct list_head list; + struct user_namespace *user_ns; + struct ucounts *ucounts; + u64 seq; /* Sequence number to prevent loops */ + wait_queue_head_t poll; + u64 event; + unsigned int mounts; /* # of mounts in the namespace */ + unsigned int pending_mounts; + struct ima_namespace *ima_ns; +} __randomize_layout; + #define MNT_NOSUID 0x01 #define MNT_NODEV 0x02 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/nsproxy.c b/kernel/nsproxy.c index f6c5d330059a..7d1a35362186 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -27,6 +27,7 @@ #include #include #include +#include static struct kmem_cache *nsproxy_cachep; 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..4b081dbfac07 --- /dev/null +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: Yuqiong Sun + * + * 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(2), + .user_ns = &init_user_ns, + .parent = NULL, +}; +EXPORT_SYMBOL(init_ima_ns); + +void imans_install(struct nsproxy *nsproxy, struct ns_common *new) +{ + struct ima_namespace *ns = to_ima_ns(new); + + get_ima_ns(ns); + put_ima_ns(nsproxy->mnt_ns->ima_ns); + nsproxy->mnt_ns->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..7ab4322c88ae --- /dev/null +++ b/security/integrity/ima/ima_ns.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2016-2018 IBM Corporation + * Author: Yuqiong Sun + * + * 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 + +#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 + * @user_ns: user namespace that current task runs in + * Return ERR_PTR(-ENOMEM) on error (failure to kmalloc), new ns otherwise + */ +static struct ima_namespace *clone_ima_ns(struct user_namespace *user_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; + ns->user_ns = get_user_ns(user_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 + * @user_ns: user namespace that current task runs in + * @old_ns: old ima namespace to clone + */ + +struct ima_namespace *copy_ima(struct user_namespace *user_ns, + struct ima_namespace *old_ns) +{ + struct ima_namespace *new_ns; + + BUG_ON(!old_ns); + get_ima_ns(old_ns); + + new_ns = clone_ima_ns(user_ns, old_ns); + put_ima_ns(old_ns); + + return new_ns; +} + +static void destroy_ima_ns(struct ima_namespace *ns) +{ + put_user_ns(ns->user_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.13.6