Received: by 10.213.65.68 with SMTP id h4csp312037imn; Wed, 28 Mar 2018 04:11:47 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+XeffeM174e7nrlCfWmV4F2rO3kPMuHVykeV7uCiDutA4/ds24CY3T4GMZqKAT0f1Tm6cP X-Received: by 2002:a17:902:1e2:: with SMTP id b89-v6mr3280577plb.389.1522235507638; Wed, 28 Mar 2018 04:11:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522235507; cv=none; d=google.com; s=arc-20160816; b=VpV6jCJK8NBNe1IXW6ms9SowuaWs5vC4uD7rjpmVBe+8DLUUuYwvGtI9D9JlpBz9NH LeSLHYNf9VJcP3tPZpOkcfpEL42KsYVrBpfwFQsEPLWo3ob6cct4i/K8O57B6ygb2jJy E+xb7m/RDn+5Lcp47i2125mI1yw8AskdWthiGXYkOi1/PwybQKKu9MBcAzlsa7EO3IgX KCmpQcrk+Mhf/exeM+gLD/EiRdYrHnYElLJ9dkwGzmRiwyEKpQ9NGE7j4crot5QmKYyv Uq5KxDahx3gSbNDZC26zf5Sc9F+lvpmA4COYlU4PrRQ6xee1z5bw0D+L3jHZws4EekZx 7iIA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:content-transfer-encoding :in-reply-to:mime-version:user-agent:date:from:cc:references:to :subject:arc-authentication-results; bh=vOlDr+o7FohAhnMtFN55atYXB30r4IyF7utdxm4SYy8=; b=RFoavFQQY1Qg0vQi13JVfvYsjczeBrV+5qXYCD3imzeuaC88pCzd9Hcu9s0Lc0cIMq F0NPEbXHDftFisqnp4PFNPqg/KpD6oAD+TWh2wPEL6jYksrliA6AHzDa9s69WFuv6dB2 iiNoc9jH6yq2miDALUmQEs8GJTfTGuMGmT6JJxmcAeR8IzzSjjqwJiRF+auPlXf4UlrQ gVYAjAkGxqKWGj/DZfZrxTxJkvx5rmSAQx16qMaPAt4Lg6V0wgBU98jaZVEfKzk5Igjs 084GQPugq3uJlwjTAwlmPka/ysWbmMIbcjnZ7EXVYolaHNx349N4dKrtqQdarCC30AHZ 6MSw== 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 3-v6si3342486plq.142.2018.03.28.04.11.32; Wed, 28 Mar 2018 04:11:47 -0700 (PDT) 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 S1752802AbeC1LKV (ORCPT + 99 others); Wed, 28 Mar 2018 07:10:21 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:42598 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752486AbeC1LKT (ORCPT ); Wed, 28 Mar 2018 07:10:19 -0400 Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w2SB9ttJ065066 for ; Wed, 28 Mar 2018 07:10:18 -0400 Received: from e18.ny.us.ibm.com (e18.ny.us.ibm.com [129.33.205.208]) by mx0b-001b2d01.pphosted.com with ESMTP id 2h0901tfwg-1 (version=TLSv1.2 cipher=AES256-SHA256 bits=256 verify=NOT) for ; Wed, 28 Mar 2018 07:10:17 -0400 Received: from localhost by e18.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 28 Mar 2018 07:10:16 -0400 Received: from b01cxnp22035.gho.pok.ibm.com (9.57.198.25) by e18.ny.us.ibm.com (146.89.104.205) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 28 Mar 2018 07:10:13 -0400 Received: from b01ledav004.gho.pok.ibm.com (b01ledav004.gho.pok.ibm.com [9.57.199.109]) by b01cxnp22035.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w2SBACsw56623188; Wed, 28 Mar 2018 11:10:12 GMT Received: from b01ledav004.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2128B112057; Wed, 28 Mar 2018 07:09:09 -0400 (EDT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav004.gho.pok.ibm.com (Postfix) with ESMTP id B347C112054; Wed, 28 Mar 2018 07:09:08 -0400 (EDT) Subject: Re: [RFC PATCH v3 1/3] ima: extend clone() with IMA namespace support To: "Eric W. Biederman" References: <1522159038-14175-1-git-send-email-stefanb@linux.vnet.ibm.com> <1522159038-14175-2-git-send-email-stefanb@linux.vnet.ibm.com> <87sh8lcecn.fsf@xmission.com> Cc: linux-integrity@vger.kernel.org, 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, Yuqiong Sun , Mehmet Kayaalp From: Stefan Berger Date: Wed, 28 Mar 2018 07:10:12 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: <87sh8lcecn.fsf@xmission.com> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-TM-AS-GCONF: 00 x-cbid: 18032811-0044-0000-0000-000003F9F10F X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008758; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000255; SDB=6.01009592; UDB=6.00514317; IPR=6.00788874; MB=3.00020288; MTD=3.00000008; XFM=3.00000015; UTC=2018-03-28 11:10:15 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18032811-0045-0000-0000-00000829FE2F Message-Id: X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2018-03-28_04:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=2 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-1803280122 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 03/27/2018 07:01 PM, Eric W. Biederman wrote: > Stefan Berger writes: > >> 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). > Tying IMA to the user namespace is far better than tying IMA > to the mount namespace. It may even be the proper answer. > > > You had asked what it would take to unstick this so you won't have > problems next time you post and I did not get as far as answering. > > I had a conversation a while back with Mimi and I believe what was > agreed was that IMA to start doing it's thing early needs a write > to securityfs/imafs. Above you say 'proper answer' for user namespace. Now this sounds like making it independent. > > As such I expect the best way to create the ima namespace is by simply > writing to securityfs/imafs. Possibly before the user namespace is > even unshared. That would allow IMA to keep track of things from > before a container is created. So you are saying to not tie it to user namespace but make it an independent namespace and to not use a clone flag (0x1000) but use the filesystem to spawn a new namespace. Should that be an IMA specific file or a file that can be shared with other subsystems? Stefan > > Eric > >> 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; > Having the functions be #ifdef'd rather than the code would > be preferabble. >> >> +#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); >> +}