From patchwork Fri Feb 22 16:30:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Smalley X-Patchwork-Id: 10826621 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E0ACE1575 for ; Fri, 22 Feb 2019 16:31:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CED153268A for ; Fri, 22 Feb 2019 16:31:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C2B8332701; Fri, 22 Feb 2019 16:31:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2D90B3268A for ; Fri, 22 Feb 2019 16:31:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726848AbfBVQbM (ORCPT ); Fri, 22 Feb 2019 11:31:12 -0500 Received: from uphb19pa10.eemsg.mail.mil ([214.24.26.84]:17047 "EHLO USFB19PA13.eemsg.mail.mil" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726757AbfBVQbM (ORCPT ); Fri, 22 Feb 2019 11:31:12 -0500 X-EEMSG-check-017: 236547060|USFB19PA13_EEMSG_MP9.csd.disa.mil Received: from emsm-gh1-uea10.ncsc.mil ([214.29.60.2]) by USFB19PA13.eemsg.mail.mil with ESMTP/TLS/DHE-RSA-AES256-SHA256; 22 Feb 2019 16:31:09 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=tycho.nsa.gov; i=@tycho.nsa.gov; q=dns/txt; s=tycho.nsa.gov; t=1550853070; x=1582389070; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=pPckhgMWKf8VGkvWee5ARH/4TPBLOb0EBo5mwM+VMGY=; b=ZuJ+NSI1900DtdGWTQ8yDLGorZFbLVAv+vYEO1ZGfKs429Ui9qguqQ+d HuvU3NNROiIYrIb+lFypiaUb2JYRzHgFvJWGAZz9oLPSRdELA23t8HaOs FTgoKp2f45dsVuSPnVKb+jfmZFV7+ft4wHs2DS8qUsol6VZTabRu2utb4 MbJmxrOyASpH7BY+pvuhe6fkQGUXA6oV8FnCDWaRwSG9EfyiE2jj1OfpA bBH0HZcvaq5ac2rLpZfRr/Wi4HDIXVv43DMizMENh0fMnBoJ6Wxac4qr+ alkJt4FpFV3FY6IBn/2cRcCfrFCBeaTHbjcC042kte/k5FIP97lwyW0Qv w==; X-IronPort-AV: E=Sophos;i="5.58,400,1544486400"; d="scan'208";a="20798751" IronPort-PHdr: 9a23:Hlxubhxsg1Bw/5/XCy+O+j09IxM/srCxBDY+r6Qd2+8TIJqq85mqBkHD//Il1AaPAd2Lraocw8Pt8InYEVQa5piAtH1QOLdtbDQizfssogo7HcSeAlf6JvO5JwYzHcBFSUM3tyrjaRsdF8nxfUDdrWOv5jAOBBr/KRB1JuPoEYLOksi7ze+/94HQbglSmDaxfa55IQmrownWqsQYm5ZpJLwryhvOrHtIeuBWyn1tKFmOgRvy5dq+8YB6/ShItP0v68BPUaPhf6QlVrNYFygpM3o05MLwqxbOSxaE62YGXWUXlhpIBBXF7A3/U5zsvCb2qvZx1S+HNsL4V7A0XSmp4bltRhHmlSwLMyc1/H/LhsB1iq9QvRCvqAFlw4PMYI+bKudwcK3ec90dSmVPUd1cWzBCD46mc4cCFfYNMfpeooLgp1UOtxy+BQy0Ce3y1j9HmGf23a0k3OQnDArIwQkgEMgKsHTQstr0NLoZXOeuzKbV1jXOdO9W2Dfh54jIdRAtu/eMXalqfsbLxkkvEB3Fg0yWpIf4PD2VzvwAv3WU4udvT+6ii3MrpxtvrjWg2MsgkJTFi4QIwV7e7yp52pw6JdigRU5+Zt6rDYVfujmBN4tzXsMiW2ZouDsmyrEeuZ60YiwKyJM/yh7DcfOHaYmI4g/4VOqLPTd5hG5qeLK4hxqo90iv1vb8WdWu3FZPrypFlsHAtnEL1xPN9siKUuZx80iu1DqV1w3f9/tILV47mKbFMZIt36Y8lp8JvkTCGi/2ll/2jKiTdkg84ein9v/nb676pp6cK4B0igb+Pr4omsykG+s0KAcOX2+F+eikzr3s4VX5QKlWjv0xiqTZq47VJcAapq6/Hg9U3Z0u6wiwDzi4ytQUh3oHI0xfeBKBkYfpP0vCIPfiDfewm16siitkx+jaPr39BZXANmXMkLDkfbZ87U5cyRY8zdNF65JbELEBIfzzWlPqudPFEBA5PRK7w+D8CNpjyowSQ2SPAquBOqPIrVCI/v4vI/WLZIINoDbyMeUl5/r1gH8hg1AdYK2p0YISaHC/GfRmOVuWbWDwjdcGFGdZ9jY5GfTjlVmqSTdOYzO3WKUm63cwD4f1I53EQ9WWnLGZ3Cq9VqZTb2RCB0HERWzkbK2YSvwMb2SUOcYnnTsaA+vyA7Q93A2j4Vepg4FsKfDZr2hC7Z8= X-IPAS-Result: A2BAAABnI3Bc/wHyM5BlHgEGBwaBUQkLAYFZKoE3ATInmEcBAQEBAQEGinCJU4UQgXsgGAGEQIQAIjQJDQEDAQEBAQEBAgFsKII6KYMVCwFGgVGCYz2BZg2sdTOFRIRpiAWEQxd4gQeBEY10Aol1EYZJgQZakSoJklQMGYFxiRyIAi2LMY1WhRY4gVYrCAIYCCEPgyeCKBcTbQECjTkhAzCBBQEBjwQBAQ Received: from tarius.tycho.ncsc.mil ([144.51.242.1]) by EMSM-GH1-UEA10.NCSC.MIL with ESMTP; 22 Feb 2019 16:31:08 +0000 Received: from moss-pluto.infosec.tycho.ncsc.mil (moss-pluto [192.168.25.131]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id x1MGV73Z028212; Fri, 22 Feb 2019 11:31:07 -0500 From: Stephen Smalley To: paul@paul-moore.com Cc: dominick.grift@defensec.nl, selinux@vger.kernel.org, Stephen Smalley Subject: [PATCH v2] libselinux: selinux_set_mapping: fix handling of unknown classes/perms Date: Fri, 22 Feb 2019 11:30:47 -0500 Message-Id: <20190222163047.10983-1-sds@tycho.nsa.gov> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The libselinux selinux_set_mapping() implementation was never updated to handle unknown classes/permissions based on the policy handle_unknown flag. Update it and the internal mapping functions to gracefully handle unknown classes/permissions. Add a security_reject_unknown() interface to expose the corresponding selinuxfs node and use it when creating a mapping to decide whether to fail immediately or proceed. This enables dbus-daemon and XSELinux, which use selinux_set_mapping(), to continue working with the dummy policy or other policies that lack their userspace class/permission definitions as long as the policy was built with -U allow. Signed-off-by: Stephen Smalley --- v2 moves the call to security_deny_unknown() inside of map_decision(), thereby avoiding the overhead of calling it unless the caller has set a mapping. libselinux/include/selinux/selinux.h | 5 +- libselinux/src/compute_av.c | 14 ++++-- libselinux/src/mapping.c | 70 ++++++++++++++++++++++------ libselinux/src/reject_unknown.c | 40 ++++++++++++++++ libselinux/src/selinux_internal.h | 1 + 5 files changed, 113 insertions(+), 17 deletions(-) create mode 100644 libselinux/src/reject_unknown.c diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h index 01201eee..a34d54fc 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h @@ -328,7 +328,10 @@ extern int security_getenforce(void); /* Set the enforce flag value. */ extern int security_setenforce(int value); -/* Get the behavior for undefined classes/permissions */ +/* Get the load-time behavior for undefined classes/permissions */ +extern int security_reject_unknown(void); + +/* Get the runtime behavior for undefined classes/permissions */ extern int security_deny_unknown(void); /* Get the checkreqprot value */ diff --git a/libselinux/src/compute_av.c b/libselinux/src/compute_av.c index 1d05e7b6..a47cffe9 100644 --- a/libselinux/src/compute_av.c +++ b/libselinux/src/compute_av.c @@ -20,6 +20,7 @@ int security_compute_av_flags_raw(const char * scon, char *buf; size_t len; int fd, ret; + security_class_t kclass; if (!selinux_mnt) { errno = ENOENT; @@ -38,8 +39,9 @@ int security_compute_av_flags_raw(const char * scon, goto out; } + kclass = unmap_class(tclass); snprintf(buf, len, "%s %s %hu %x", scon, tcon, - unmap_class(tclass), unmap_perm(tclass, requested)); + kclass, unmap_perm(tclass, requested)); ret = write(fd, buf, strlen(buf)); if (ret < 0) @@ -60,8 +62,14 @@ int security_compute_av_flags_raw(const char * scon, } else if (ret < 6) avd->flags = 0; - /* If tclass invalid, kernel sets avd according to deny_unknown flag */ - if (tclass != 0) + /* + * If the tclass could not be mapped to a kernel class at all, the + * kernel will have already set avd according to the + * handle_unknown flag and we do not need to do anything further. + * Otherwise, we must map the permissions within the returned + * avd to the userspace permission values. + */ + if (kclass != 0) map_decision(tclass, avd); ret = 0; diff --git a/libselinux/src/mapping.c b/libselinux/src/mapping.c index f205804b..b450a5af 100644 --- a/libselinux/src/mapping.c +++ b/libselinux/src/mapping.c @@ -6,9 +6,12 @@ #include #include #include +#include #include #include +#include "callbacks.h" #include "mapping.h" +#include "selinux_internal.h" /* * Class and permission mappings @@ -33,6 +36,9 @@ selinux_set_mapping(struct security_class_mapping *map) size_t size = sizeof(struct selinux_mapping); security_class_t i, j; unsigned k; + bool print_unknown_handle = false; + bool reject = (security_reject_unknown() == 1); + bool deny = (security_deny_unknown() == 1); free(current_mapping); current_mapping = NULL; @@ -62,8 +68,16 @@ selinux_set_mapping(struct security_class_mapping *map) struct selinux_mapping *p_out = current_mapping + j; p_out->value = string_to_security_class(p_in->name); - if (!p_out->value) - goto err2; + if (!p_out->value) { + selinux_log(SELINUX_INFO, + "SELinux: Class %s not defined in policy.\n", + p_in->name); + if (reject) + goto err2; + p_out->num_perms = 0; + print_unknown_handle = true; + continue; + } k = 0; while (p_in->perms[k]) { @@ -74,13 +88,24 @@ selinux_set_mapping(struct security_class_mapping *map) } p_out->perms[k] = string_to_av_perm(p_out->value, p_in->perms[k]); - if (!p_out->perms[k]) - goto err2; + if (!p_out->perms[k]) { + selinux_log(SELINUX_INFO, + "SELinux: Permission %s in class %s not defined in policy.\n", + p_in->perms[k], p_in->name); + if (reject) + goto err2; + print_unknown_handle = true; + } k++; } p_out->num_perms = k; } + if (print_unknown_handle) + selinux_log(SELINUX_INFO, + "SELinux: the above unknown classes and permissions will be %s\n", + deny ? "denied" : "allowed"); + /* Set the mapping size here so the above lookups are "raw" */ current_mapping_size = i; return 0; @@ -184,27 +209,46 @@ void map_decision(security_class_t tclass, struct av_decision *avd) { if (tclass < current_mapping_size) { - unsigned i; + bool allow_unknown = (security_deny_unknown() == 0); + struct selinux_mapping *mapping = ¤t_mapping[tclass]; + unsigned int i, n = mapping->num_perms; access_vector_t result; - for (i=0, result=0; iallowed & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) { + if (avd->allowed & mapping->perms[i]) + result |= 1<perms[i]) result |= 1<allowed = result; - for (i=0, result=0; idecided & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) { + if (avd->decided & mapping->perms[i]) + result |= 1<perms[i]) result |= 1<decided = result; - for (i=0, result=0; iauditallow & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) + if (avd->auditallow & mapping->perms[i]) result |= 1<auditallow = result; - for (i=0, result=0; iauditdeny & current_mapping[tclass].perms[i]) + for (i = 0, result = 0; i < n; i++) { + if (avd->auditdeny & mapping->perms[i]) result |= 1<perms[i]) + result |= 1<num_perms since this indicates + * a bug in the object manager. + */ + for (; i < (sizeof(result)*8); i++) + result |= 1<auditdeny = result; } } diff --git a/libselinux/src/reject_unknown.c b/libselinux/src/reject_unknown.c new file mode 100644 index 00000000..5c1d3605 --- /dev/null +++ b/libselinux/src/reject_unknown.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include "selinux_internal.h" +#include "policy.h" +#include +#include + +int security_reject_unknown(void) +{ + int fd, ret, reject_unknown = 0; + char path[PATH_MAX]; + char buf[20]; + + if (!selinux_mnt) { + errno = ENOENT; + return -1; + } + + snprintf(path, sizeof(path), "%s/reject_unknown", selinux_mnt); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; + + memset(buf, 0, sizeof(buf)); + ret = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (ret < 0) + return -1; + + if (sscanf(buf, "%d", &reject_unknown) != 1) + return -1; + + return reject_unknown; +} + +hidden_def(security_reject_unknown); diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h index dfc421cc..70b5025d 100644 --- a/libselinux/src/selinux_internal.h +++ b/libselinux/src/selinux_internal.h @@ -59,6 +59,7 @@ hidden_proto(selinux_mkload_policy) hidden_proto(security_getenforce) hidden_proto(security_setenforce) hidden_proto(security_deny_unknown) + hidden_proto(security_reject_unknown) hidden_proto(security_get_checkreqprot) hidden_proto(selinux_boolean_sub) hidden_proto(selinux_current_policy_path)