Received: by 2002:a05:6a10:6d10:0:0:0:0 with SMTP id gq16csp31108pxb; Thu, 21 Apr 2022 16:11:40 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxvAsJGrFtYZWAdbbrD8VnY0ZnFLcV0uAJ5WAL1ifRWm+tur+jajda0WXlq5J7Cp6Jop2fb X-Received: by 2002:a05:6402:5191:b0:423:fa7f:f4c2 with SMTP id q17-20020a056402519100b00423fa7ff4c2mr1977749edd.9.1650582700562; Thu, 21 Apr 2022 16:11:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650582700; cv=none; d=google.com; s=arc-20160816; b=NX4WSOrTAoLJ8uvMoM8MvrqrTetJrzrjmFLBrLmG50nLvgsUmhif3VWD/OUa6E7VrH cLsqiua/251i/SHXOTErDt2wMcJ0MX91bMcyzBlpB0kIJnrNyyrbqB1zjCH2ZDYsqIPJ v3TQTOwWeFdo12W/wjcOC5YVrXxLGLwLo9JyxIALxpqxICk8PBsa7m4VNgtCVNt/W9K3 uTwatna59FOyEQR4PTzSyXTCi6BrR9AwelOvOj74El56cXR2Dk2TKCgQS4nHegh5SLv3 S1vaxn3M5V2OOqRLrMzWPqhP7P7aOx9a5/YD1LusXUYnxkRQdQ4kBNRniyVNEAcKyCPh 1Oqw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=xPF7DEG1xCo7psfNlZ5noEInP4YPXTc1c8CoK+lx30I=; b=xZJy8cQH5lpE5n1qvOOOtBo3KzkReTN1zZxYYu7KTWwuK2QLURWDhgeJGuek9YcrE3 ONCcKKmfSINhTWfZxbjWFeSzN2xpOjUgseThnrHrsL8YH6mxoYWqR6UC4TaRHNggw/RO G4gX0eDHt79LTcr01ZH77L8LdMg2CLYSF+3TF/2AJtNSJub3nHQRn+TdgzgRjxVSv4B9 KVWCBHolMM6iT8GPW0/KpInDokd5rhPX/lcI2/TTvQLwhKkp9uERu0VE6WQAXPtdIoiz GcLY3eDVdr6Pyiuz4IefQt80cgtHfPCGme/he756sKLn4TuJlos8rOPaZcr6NtYkVQBZ UTsA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@yahoo.com header.s=s2048 header.b=SBlj7Zjx; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t4-20020a056402524400b0041d7be57872si5136573edd.454.2022.04.21.16.11.01; Thu, 21 Apr 2022 16:11:40 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@yahoo.com header.s=s2048 header.b=SBlj7Zjx; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345457AbiDRPmH (ORCPT + 99 others); Mon, 18 Apr 2022 11:42:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53246 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345411AbiDRPlz (ORCPT ); Mon, 18 Apr 2022 11:41:55 -0400 Received: from sonic317-38.consmr.mail.ne1.yahoo.com (sonic317-38.consmr.mail.ne1.yahoo.com [66.163.184.49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1BE6F3587A for ; Mon, 18 Apr 2022 08:06:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1650294386; bh=xPF7DEG1xCo7psfNlZ5noEInP4YPXTc1c8CoK+lx30I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From:Subject:Reply-To; b=SBlj7Zjx6APKvMDqrIWay0nsWcew587qvpfcHj3MxdYWc0QJ1wg4yOALfhRi005XzozxLRLdxdvyOflqnnuVXlNb15nX1LdkYg4QaNO0k6KYs33KylRtdchh6M483RRBZ+glszb5IbSmEeSj5XsNqQ1Z+BJr2eCfpAtyeAL+TGYzQqA49neSNvj9OJeujaYyF70cIZQYTtVwYBher4rodBZzveI5H36pBT4BQjm09f/I7Tjb+eAXf0K1wJp3VTsi5g5j7kwG1nPzB9MczB1Qz/8fsMDqzdvh1zr6znTdIceei4AgVpcrnvcGHbgUer3C5iGBgvFuE53tmIaWFVQfmg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1650294386; bh=8in36/nCWhFHelAhhchAIssIObbye3ZzpmB+K8Jcw1s=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=Bk/xltaOIo0KcezJ24aW/wa9bHDZQP2Gh78Qs7D85GPcpFhETBXbjvoHVl3Y6sWxR7b3yrqY5t2TMeehNu7miSu8WSlXkJ9q5g2DtqSTtq+9FD91GsmRE3xlQlMUTYuK7oxC/gOzyb+Jb49jWbPw+nu99OUfE6lZIUGbPW2YSie0hysDuI0A/RFJvHz4Viyf6VYxX+hc4Wr3f1PL8yssHP+PX9EvSAC8z9y/iQAp/o5CU7/T0i19k+8x+fdkYcj4u5h5t7Cm+fYKuL0gRyleC5TpNBj2FewXeSEyXIUm7bIh+CUKxSb5jqU0mCK6syRDBAfxugt0TYkpDIvgMEsKKg== X-YMail-OSG: u95XZL0VM1lLwKGROLVRwuFcsBfr0PJ2KEqsKailqhWck29ZMgOsss5xBn.Ua6E kCJnPF76aG.NQEAmCENN41.Z8wJ_s9qKaQTfSo7NCrw5DKiDmofGSmqlPsFYh54kyLpMWOnFjK1i tD6_Bjk7a3eEXGdE6DouCBtqaq6MYKgd8DZgPMOP47jHVK1hSCmIcvKARQQqBqwsrxxseG9hD2nn x4UpyuBPbRQajg8rkr0Y5FUbqexQj7kkv1xB0dn0GL3wd8o43aZrKaFGVoPoiq1lFL2dXemm8FCx Rh4q0I8gNktkFTCx6QBsSIPxZkVxXUsGSRQBs.zlYchYfcDxb5rK.VOLw9ezgLw94UZfqr2n4Bhk N3ueXUqyf23PaYLFq7Unu8q3fTgp49qj26exjD.fk9r2fMAO0JtzU1sLCv.EIFwpBQiPeCp3uD3L _dP9CsaIDCCpkLX73WJq_sMWX1sxrJ1PESZ71s9lZkSCGcC1i65achFE93iloCRvd7OKIGIIMyIQ SSdgrixRrSTjMBgpDLil3MEO1mKSgSYkKlbRNNDqbqNRy0KlZw8DZh3aubDrBxCMEzmF.gEVg13y _brUEo6YgR1ZaPF_GDwnMZDs1d_4KCCrSXxyHZyzXb3qqZDd4zcKfjRKbmgItzTIT_3nTmAZLifS leuZD5GD6GI069_la9o9tcDANfhDT8bM4M1Lt1TOJYrsx.DsS7H4zDuQ4IegF_bG1ypAJVBOpd8B l4mnKk5En0TkKqoD9ELZa1E_7vbu4dLsuL7Qoy6GPVNFcNrD7_lW8leIfR.pKrrr8kzyWQV0gnc7 gHX9EI4nMObP5auUMT4KY6AIy692cyksLoPrjGRCc3gf1q6NSgC47zUFjlz50GezETiNbwclb1z6 9.xug5G1lwsG_BKmhaPqJDR0hqi7zfh.MCcB320BBVmBnYhtCY2W3c47U81Zg5_kZpzmE6IhixW5 NLTdXy9bblRONQ5gdQbJCf3f.4d5vXXt6TVqzwa_ssoXmNouIEyBYTpxZXRah5yFlcct7i0LIi_2 u5tWh9DZkkF.jwVNFx0PERx1ppeK_Nka9s6EvDzf9NnCqIbNK9X8ta.C6SDA70SBJzcUOFYcfFj8 dzd3wuCxgKXKuafrC8K04lPWzyTf0TcUwwvrgt8GkDsZ4y8I5MKUrszGPXXhwKKDsfCqbRZo1dUh xz.aPmb8vffRWb34m19x_ecM28XhGHBl9ZU6oVeaDP0SBt37100XO6oViEh5LBDhKbk1g_PUrFui gOzaIHovvXd.ew9UAnwNSOBTRU2QziFNvhuFG4PhkCOZcDBhV87UCXznFD4fLqnf0Bz5OdgbwuJc D8L6eH0YmOyENOvl9_RJvYm3wdiecQZdxbSgUoHiBrNvwd8AIbWfSbTkwqaWv_80BzyUeSdhHvrk r7AexQjFlgYrDnY2qq_9DHojba5q1bOxDsWRftkr5q.EOE5F6.UANvCuOBUH9egaiUfzDs7v_CY7 s0xRsPg_mQa4xb5j_HH_yw2_XwIbizXTlXU9be.b5v0kN9TPnMaemnG9ToYceGa.DtCbJk8DbtEi GGhzPRDg6em2dHK0JYQT5iElbMudZhXST5kZQQAnh9mEr83wNkYZ9xmOoiYIlw896Z0AbAqziaHW hN9PAkUZKrXgeEe7AQMn..PxNpUCeB0nNq8azwdp1gQqyOnTvEnmII6i8bN7Hkq..sw8H9A4u1mY QjBtywO_TFertD5PmNulcUnedkjnPZtlhL8kklPHzmfoQEvSduyWpAu17xXivsuuFL1JhOTV9I.x DXFFHZqX0i8WHbluedNxpePft5w55Ee7_SDvo5lvpfSfCndUt_AlVe0LRkRMTA4krk2GvhWdQ6IO cJreZMFmZtO.lXVA862IJs85HzrnMl9ahGREW1erLILb4F3Cra1mEpQ.4dFCLBJnVA8sSsbFzQZJ eLfkgfxSgvNvir_wsfmr1slJFd3UOUiYXuQvjSB9ztIjJGczISVdYMLaZ8AF0N.oZajxPdZt1fDj eL5ox5lh0vFkCZz6S1Ny9TAeBBF6VEhricE4O.FGVgsuNExOG6O89FOe45rD0e1Qz9flwwzG_TYk iiXuORuWxhq_vdwV8mKKUmBGPYpVgmzBRQZ6uGhRshbgM9_Wy7f_QFFpYiTMe0o5fFJr1DYXzIHw ao5kJ9RBqI283eQFwhH9BzqLYK6mJm73XsyRGJJIHNLlHYz6k1CkKboMh2OFVvWJXnoemlaUlPyk ZFBlY9NpbTorcBK6Wc6BLivUgZDdtn0rdkgNxdj.u4hwrWRC6p.hy9UKvvhSGsIjWjzUsboOJO8Z KWDTVMM1TDCFtmOHVBR1IgHPSHDo3ZigD8rSBAz87Ok__DIwowSxMrovn1kywJQabUnB8Lw-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic317.consmr.mail.ne1.yahoo.com with HTTP; Mon, 18 Apr 2022 15:06:26 +0000 Received: by hermes--canary-production-gq1-665697845d-srvxf (VZM Hermes SMTP Server) with ESMTPA ID facb0f2176037c185ff3b4e507d76c59; Mon, 18 Apr 2022 15:06:23 +0000 (UTC) From: Casey Schaufler To: casey.schaufler@intel.com, jmorris@namei.org, linux-security-module@vger.kernel.org, selinux@vger.kernel.org Cc: casey@schaufler-ca.com, linux-audit@redhat.com, keescook@chromium.org, john.johansen@canonical.com, penguin-kernel@i-love.sakura.ne.jp, paul@paul-moore.com, stephen.smalley.work@gmail.com, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , linux-api@vger.kernel.org, linux-doc@vger.kernel.org Subject: [PATCH v35 14/29] LSM: Specify which LSM to display Date: Mon, 18 Apr 2022 07:59:30 -0700 Message-Id: <20220418145945.38797-15-casey@schaufler-ca.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220418145945.38797-1-casey@schaufler-ca.com> References: <20220418145945.38797-1-casey@schaufler-ca.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Create a new entry "interface_lsm" in the procfs attr directory for controlling which LSM security information is displayed for a process. A process can only read or write its own display value. The name of an active LSM that supplies hooks for human readable data may be written to "interface_lsm" to set the value. The name of the LSM currently in use can be read from "interface_lsm". At this point there can only be one LSM capable of display active. A helper function lsm_task_ilsm() is provided to get the interface lsm slot for a task_struct. Setting the "interface_lsm" requires that all security modules using setprocattr hooks allow the action. Each security module is responsible for defining its policy. AppArmor hook provided by John Johansen SELinux hook provided by Stephen Smalley Signed-off-by: Casey Schaufler Cc: Kees Cook Cc: Stephen Smalley Cc: Paul Moore Cc: John Johansen Cc: Greg Kroah-Hartman Cc: linux-api@vger.kernel.org Cc: linux-doc@vger.kernel.org --- .../ABI/testing/procfs-attr-lsm_display | 22 +++ Documentation/security/lsm.rst | 14 ++ fs/proc/base.c | 1 + include/linux/security.h | 17 ++ security/apparmor/include/apparmor.h | 3 +- security/apparmor/lsm.c | 32 ++++ security/security.c | 166 ++++++++++++++++-- security/selinux/hooks.c | 11 ++ security/selinux/include/classmap.h | 3 +- security/smack/smack_lsm.c | 7 + 10 files changed, 257 insertions(+), 19 deletions(-) create mode 100644 Documentation/ABI/testing/procfs-attr-lsm_display diff --git a/Documentation/ABI/testing/procfs-attr-lsm_display b/Documentation/ABI/testing/procfs-attr-lsm_display new file mode 100644 index 000000000000..0f60005c235c --- /dev/null +++ b/Documentation/ABI/testing/procfs-attr-lsm_display @@ -0,0 +1,22 @@ +What: /proc/*/attr/lsm_display +Contact: linux-security-module@vger.kernel.org, +Description: The name of the Linux security module (LSM) that will + provide information in the /proc/*/attr/current, + /proc/*/attr/prev and /proc/*/attr/exec interfaces. + The details of permissions required to read from + this interface are dependent on the LSMs active on the + system. + A process cannot write to this interface unless it + refers to itself. + The other details of permissions required to write to + this interface are dependent on the LSMs active on the + system. + The format of the data used by this interface is a + text string identifying the name of an LSM. The values + accepted are: + selinux - the SELinux LSM + smack - the Smack LSM + apparmor - The AppArmor LSM + By convention the LSM names are lower case and do not + contain special characters. +Users: LSM user-space diff --git a/Documentation/security/lsm.rst b/Documentation/security/lsm.rst index 6a2a2e973080..b77b4a540391 100644 --- a/Documentation/security/lsm.rst +++ b/Documentation/security/lsm.rst @@ -129,3 +129,17 @@ to identify it as the first security module to be registered. The capabilities security module does not use the general security blobs, unlike other modules. The reasons are historical and are based on overhead, complexity and performance concerns. + +LSM External Interfaces +======================= + +The LSM infrastructure does not generally provide external interfaces. +The individual security modules provide what external interfaces they +require. + +The file ``/sys/kernel/security/lsm`` provides a comma +separated list of the active security modules. + +The file ``/proc/pid/attr/interface_lsm`` contains the name of the security +module for which the ``/proc/pid/attr/current`` interface will +apply. This interface can be written to. diff --git a/fs/proc/base.c b/fs/proc/base.c index c1031843cc6a..f2d15348bdff 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2827,6 +2827,7 @@ static const struct pid_entry attr_dir_stuff[] = { ATTR(NULL, "fscreate", 0666), ATTR(NULL, "keycreate", 0666), ATTR(NULL, "sockcreate", 0666), + ATTR(NULL, "interface_lsm", 0666), #ifdef CONFIG_SECURITY_SMACK DIR("smack", 0555, proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), diff --git a/include/linux/security.h b/include/linux/security.h index fa413a5a2ccb..a6574d13c6fb 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -238,6 +238,23 @@ static inline u32 lsmblob_first(const struct lsmblob *blob) #endif } +/** + * lsm_task_ilsm - the "interface_lsm" for this task + * @task: The task to report on + * + * Returns the task's interface LSM slot. + */ +static inline int lsm_task_ilsm(struct task_struct *task) +{ +#ifdef CONFIG_SECURITY + int *ilsm = task->security; + + if (ilsm) + return *ilsm; +#endif + return LSMBLOB_INVALID; +} + /* These functions are in security/commoncap.c */ extern int cap_capable(const struct cred *cred, struct user_namespace *ns, int cap, unsigned int opts); diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 1fbabdb565a8..b1622fcb4394 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -28,8 +28,9 @@ #define AA_CLASS_SIGNAL 10 #define AA_CLASS_NET 14 #define AA_CLASS_LABEL 16 +#define AA_CLASS_DISPLAY_LSM 17 -#define AA_CLASS_LAST AA_CLASS_LABEL +#define AA_CLASS_LAST AA_CLASS_DISPLAY_LSM /* Control parameters settable through module/boot flags */ extern enum audit_mode aa_g_audit; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 1e53fea61335..29181bc8c693 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -621,6 +621,25 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, return error; } + +static int profile_interface_lsm(struct aa_profile *profile, + struct common_audit_data *sa) +{ + struct aa_perms perms = { }; + unsigned int state; + + state = PROFILE_MEDIATES(profile, AA_CLASS_DISPLAY_LSM); + if (state) { + aa_compute_perms(profile->policy.dfa, state, &perms); + aa_apply_modes_to_perms(profile, &perms); + aad(sa)->label = &profile->label; + + return aa_check_perms(profile, &perms, AA_MAY_WRITE, sa, NULL); + } + + return 0; +} + static int apparmor_setprocattr(const char *name, void *value, size_t size) { @@ -632,6 +651,19 @@ static int apparmor_setprocattr(const char *name, void *value, if (size == 0) return -EINVAL; + /* LSM infrastructure does actual setting of interface_lsm if allowed */ + if (!strcmp(name, "interface_lsm")) { + struct aa_profile *profile; + struct aa_label *label; + + aad(&sa)->info = "set interface lsm"; + label = begin_current_label_crit_section(); + error = fn_for_each_confined(label, profile, + profile_interface_lsm(profile, &sa)); + end_current_label_crit_section(label); + return error; + } + /* AppArmor requires that the buffer must be null terminated atm */ if (args[size - 1] != '\0') { /* null terminate */ diff --git a/security/security.c b/security/security.c index 2ad0d4eb24b3..ec4d1b3026d8 100644 --- a/security/security.c +++ b/security/security.c @@ -78,7 +78,16 @@ static struct kmem_cache *lsm_file_cache; static struct kmem_cache *lsm_inode_cache; char *lsm_names; -static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; + +/* + * The task blob includes the "interface_lsm" slot used for + * chosing which module presents contexts. + * Using a long to avoid potential alignment issues with + * module assigned task blobs. + */ +static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init = { + .lbs_task = sizeof(long), +}; /* Boot-time LSM user choice */ static __initdata const char *chosen_lsm_order; @@ -672,6 +681,8 @@ int lsm_inode_alloc(struct inode *inode) */ static int lsm_task_alloc(struct task_struct *task) { + int *ilsm; + if (blob_sizes.lbs_task == 0) { task->security = NULL; return 0; @@ -680,6 +691,15 @@ static int lsm_task_alloc(struct task_struct *task) task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL); if (task->security == NULL) return -ENOMEM; + + /* + * The start of the task blob contains the "interface" LSM slot number. + * Start with it set to the invalid slot number, indicating that the + * default first registered LSM be displayed. + */ + ilsm = task->security; + *ilsm = LSMBLOB_INVALID; + return 0; } @@ -1752,14 +1772,26 @@ int security_file_open(struct file *file) int security_task_alloc(struct task_struct *task, unsigned long clone_flags) { + int *oilsm = current->security; + int *nilsm; int rc = lsm_task_alloc(task); - if (rc) + if (unlikely(rc)) return rc; + rc = call_int_hook(task_alloc, 0, task, clone_flags); - if (unlikely(rc)) + if (unlikely(rc)) { security_task_free(task); - return rc; + return rc; + } + + if (oilsm) { + nilsm = task->security; + if (nilsm) + *nilsm = *oilsm; + } + + return 0; } void security_task_free(struct task_struct *task) @@ -2191,23 +2223,110 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name, char **value) { struct security_hook_list *hp; + int ilsm = lsm_task_ilsm(current); + int slot = 0; + + if (!strcmp(name, "interface_lsm")) { + /* + * lsm_slot will be 0 if there are no displaying modules. + */ + if (lsm_slot == 0) + return -EINVAL; + + /* + * Only allow getting the current process' interface_lsm. + * There are too few reasons to get another process' + * interface_lsm and too many LSM policy issues. + */ + if (current != p) + return -EINVAL; + + ilsm = lsm_task_ilsm(p); + if (ilsm != LSMBLOB_INVALID) + slot = ilsm; + *value = kstrdup(lsm_slotlist[slot]->lsm, GFP_KERNEL); + if (*value) + return strlen(*value); + return -ENOMEM; + } hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) { if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm)) continue; + if (lsm == NULL && ilsm != LSMBLOB_INVALID && + ilsm != hp->lsmid->slot) + continue; return hp->hook.getprocattr(p, name, value); } return LSM_RET_DEFAULT(getprocattr); } +/** + * security_setprocattr - Set process attributes via /proc + * @lsm: name of module involved, or NULL + * @name: name of the attribute + * @value: value to set the attribute to + * @size: size of the value + * + * Set the process attribute for the specified security module + * to the specified value. Note that this can only be used to set + * the process attributes for the current, or "self" process. + * The /proc code has already done this check. + * + * Returns 0 on success, an appropriate code otherwise. + */ int security_setprocattr(const char *lsm, const char *name, void *value, size_t size) { struct security_hook_list *hp; + char *termed; + char *copy; + int *ilsm = current->security; + int rc = -EINVAL; + int slot = 0; + + if (!strcmp(name, "interface_lsm")) { + /* + * Change the "interface_lsm" value only if all the security + * modules that support setting a procattr allow it. + * It is assumed that all such security modules will be + * cooperative. + */ + if (size == 0) + return -EINVAL; + + hlist_for_each_entry(hp, &security_hook_heads.setprocattr, + list) { + rc = hp->hook.setprocattr(name, value, size); + if (rc < 0 && rc != LSM_RET_DEFAULT(setprocattr)) + return rc; + } + + rc = -EINVAL; + + copy = kmemdup_nul(value, size, GFP_KERNEL); + if (copy == NULL) + return -ENOMEM; + + termed = strsep(©, " \n"); + + for (slot = 0; slot < lsm_slot; slot++) + if (!strcmp(termed, lsm_slotlist[slot]->lsm)) { + *ilsm = lsm_slotlist[slot]->slot; + rc = size; + break; + } + + kfree(termed); + return rc; + } hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) { if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm)) continue; + if (lsm == NULL && *ilsm != LSMBLOB_INVALID && + *ilsm != hp->lsmid->slot) + continue; return hp->hook.setprocattr(name, value, size); } return LSM_RET_DEFAULT(setprocattr); @@ -2227,15 +2346,15 @@ EXPORT_SYMBOL(security_ismaclabel); int security_secid_to_secctx(struct lsmblob *blob, char **secdata, u32 *seclen) { struct security_hook_list *hp; - int rc; + int ilsm = lsm_task_ilsm(current); hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) { if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot)) continue; - rc = hp->hook.secid_to_secctx(blob->secid[hp->lsmid->slot], - secdata, seclen); - if (rc != LSM_RET_DEFAULT(secid_to_secctx)) - return rc; + if (ilsm == LSMBLOB_INVALID || ilsm == hp->lsmid->slot) + return hp->hook.secid_to_secctx( + blob->secid[hp->lsmid->slot], + secdata, seclen); } return LSM_RET_DEFAULT(secid_to_secctx); @@ -2246,16 +2365,15 @@ int security_secctx_to_secid(const char *secdata, u32 seclen, struct lsmblob *blob) { struct security_hook_list *hp; - int rc; + int ilsm = lsm_task_ilsm(current); lsmblob_init(blob, 0); hlist_for_each_entry(hp, &security_hook_heads.secctx_to_secid, list) { if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot)) continue; - rc = hp->hook.secctx_to_secid(secdata, seclen, - &blob->secid[hp->lsmid->slot]); - if (rc != 0) - return rc; + if (ilsm == LSMBLOB_INVALID || ilsm == hp->lsmid->slot) + return hp->hook.secctx_to_secid(secdata, seclen, + &blob->secid[hp->lsmid->slot]); } return 0; } @@ -2263,7 +2381,14 @@ EXPORT_SYMBOL(security_secctx_to_secid); void security_release_secctx(char *secdata, u32 seclen) { - call_void_hook(release_secctx, secdata, seclen); + struct security_hook_list *hp; + int ilsm = lsm_task_ilsm(current); + + hlist_for_each_entry(hp, &security_hook_heads.release_secctx, list) + if (ilsm == LSMBLOB_INVALID || ilsm == hp->lsmid->slot) { + hp->hook.release_secctx(secdata, seclen); + return; + } } EXPORT_SYMBOL(security_release_secctx); @@ -2404,8 +2529,15 @@ EXPORT_SYMBOL(security_sock_rcv_skb); int security_socket_getpeersec_stream(struct socket *sock, char __user *optval, int __user *optlen, unsigned len) { - return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock, - optval, optlen, len); + int ilsm = lsm_task_ilsm(current); + struct security_hook_list *hp; + + hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream, + list) + if (ilsm == LSMBLOB_INVALID || ilsm == hp->lsmid->slot) + return hp->hook.socket_getpeersec_stream(sock, optval, + optlen, len); + return -ENOPROTOOPT; } int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 429309d8a910..3098a6459b68 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6388,6 +6388,17 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) /* * Basic control over ability to set these attributes at all. */ + + /* + * For setting interface_lsm, we only perform a permission check; + * the actual update to the interface_lsm value is handled by the + * LSM framework. + */ + if (!strcmp(name, "interface_lsm")) + return avc_has_perm(&selinux_state, + mysid, mysid, SECCLASS_PROCESS2, + PROCESS2__SETINTERFACE_LSM, NULL); + if (!strcmp(name, "exec")) error = avc_has_perm(&selinux_state, mysid, mysid, SECCLASS_PROCESS, diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 35aac62a662e..79b480983bdc 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -53,7 +53,8 @@ struct security_class_mapping secclass_map[] = { "execmem", "execstack", "execheap", "setkeycreate", "setsockcreate", "getrlimit", NULL } }, { "process2", - { "nnp_transition", "nosuid_transition", NULL } }, + { "nnp_transition", "nosuid_transition", "setinterface_lsm", + NULL } }, { "system", { "ipc_info", "syslog_read", "syslog_mod", "syslog_console", "module_request", "module_load", NULL } }, diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 6e0eaecd8256..552c4d4d8fac 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3516,6 +3516,13 @@ static int smack_setprocattr(const char *name, void *value, size_t size) struct smack_known_list_elem *sklep; int rc; + /* + * Allow the /proc/.../attr/current and SO_PEERSEC "interface_lsm" + * to be reset at will. + */ + if (strcmp(name, "interface_lsm") == 0) + return 0; + if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel)) return -EPERM; -- 2.35.1