From patchwork Thu Oct 20 23:55:19 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mat Martineau X-Patchwork-Id: 9387763 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9CCCA607F0 for ; Thu, 20 Oct 2016 23:55:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9CE1C29B14 for ; Thu, 20 Oct 2016 23:55:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 91C7829B23; Thu, 20 Oct 2016 23:55:36 +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=-6.9 required=2.0 tests=BAYES_00,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 1A31D29B14 for ; Thu, 20 Oct 2016 23:55:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753808AbcJTXze (ORCPT ); Thu, 20 Oct 2016 19:55:34 -0400 Received: from mga04.intel.com ([192.55.52.120]:31837 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753765AbcJTXza (ORCPT ); Thu, 20 Oct 2016 19:55:30 -0400 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga104.fm.intel.com with ESMTP; 20 Oct 2016 16:55:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,521,1473145200"; d="scan'208";a="1056884014" Received: from mjmartin-nuc01.wa.intel.com ([10.232.97.135]) by fmsmga001.fm.intel.com with ESMTP; 20 Oct 2016 16:55:28 -0700 From: Mat Martineau To: keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, dhowells@redhat.com Cc: Mat Martineau , zohar@linux.vnet.ibm.com Subject: [PATCH v8 07/11] KEYS: Parse keyring payload for restrict options Date: Thu, 20 Oct 2016 16:55:19 -0700 Message-Id: <20161020235523.11703-8-mathew.j.martineau@linux.intel.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20161020235523.11703-1-mathew.j.martineau@linux.intel.com> References: <20161020235523.11703-1-mathew.j.martineau@linux.intel.com> Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Keyrings recently gained restrict_link capabilities that allow individual keys to be validated prior to linking. This functionality was only available using internal kernel APIs. Configuring keyring restrictions from userspace must work around these constraints: - The restrict_link pointer must be set through keyring_alloc(). - The add_key system call has a fixed set of parameters. When creating keyrings, the payload was previously required to be NULL. To support restrict_link configuration, the payload is now parsed for keyring options if a payload is provided. The expected option payload format is: "restrict=[:]" The format of the restriction information is specified by each key type. Signed-off-by: Mat Martineau --- Documentation/security/keys.txt | 13 +++++- security/keys/keyring.c | 91 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index 85883e3..ec6be3f 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt @@ -418,8 +418,17 @@ The main syscalls are: the type. The payload is plen in size, and plen can be zero for an empty payload. - A new keyring can be generated by setting type "keyring", the keyring name - as the description (or NULL) and setting the payload to NULL. + A new keyring can be generated by setting type "keyring" and the keyring + name as the description (or NULL). The payload can be NULL or contain + keyring link restriction parameters using the following format: + + "restrict=:" + + "type" is a registered key type. "options" vary depending on the key type, + and are passed to the lookup_restrict function for the requested type. + The options may specify a specific method and relevant data for the + restriction (such as signature verification or constraints on key + payload). User defined keys can be created by specifying type "user". It is recommended that a user defined key's description by prefixed with a type diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 07f680b..f32da6b 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -23,6 +23,13 @@ #include "internal.h" /* + * Layout of preparse payload + */ +enum { + keyring_restrict_link, +}; + +/* * When plumbing the depths of the key tree, this sets a hard limit * set on how deep we're willing to go. */ @@ -126,28 +133,106 @@ static void keyring_publish_name(struct key *keyring) } /* + * Parse the keyring options and fill in the required keyring members. + * + * Expected format is: "restrict=[:]" + * + * Returns 0 if the option string is valid (including the empty case), + * otherwise -EINVAL. + */ +static int keyring_datablob_parse(char *datablob, + struct key_preparsed_payload *prep) +{ + char *type_name; + struct key_type *restrict_type = NULL; + struct key_restriction *restrict_link; + struct key_restriction *(*lookup_restrict)(char *params) = NULL; + int ret = -EINVAL; + const char restrict_prefix[] = "restrict="; + + if (*datablob == '\0') + return 0; + + if (!strstarts(datablob, restrict_prefix)) + return -EINVAL; + + datablob += strlen(restrict_prefix); + + type_name = strsep(&datablob, ":"); + + restrict_type = key_type_lookup(type_name); + if (IS_ERR(restrict_type)) + return -EINVAL; + + lookup_restrict = restrict_type->lookup_restrict; + + if (!lookup_restrict) + goto error; + + restrict_link = lookup_restrict(datablob); + if (IS_ERR(restrict_link)) + goto error; + + prep->payload.data[keyring_restrict_link] = restrict_link; + ret = 0; + +error: + key_type_put(restrict_type); + + return ret; +} + +/* * Preparse a keyring payload */ static int keyring_preparse(struct key_preparsed_payload *prep) { - return prep->datalen != 0 ? -EINVAL : 0; + char *datablob; + size_t datalen = prep->datalen; + int ret = 0; + + if (datalen) { + datablob = kmalloc(datalen + 1, GFP_KERNEL); + if (!datablob) + return -ENOMEM; + + memcpy(datablob, prep->data, datalen); + datablob[datalen] = '\0'; + + ret = keyring_datablob_parse(datablob, prep); + + kfree(datablob); + } + + return ret; } /* - * Free a preparse of a user defined key payload + * Free a preparse of a keyring payload */ static void keyring_free_preparse(struct key_preparsed_payload *prep) { + struct key_restriction *keyres; + + keyres = prep->payload.data[keyring_restrict_link]; + + if (keyres && keyres->free_data) { + keyres->free_data(keyres->data); + kfree(keyres); + } } /* * Initialise a keyring. * - * Returns 0 on success, -EINVAL if given any data. + * Returns 0 on success. */ static int keyring_instantiate(struct key *keyring, struct key_preparsed_payload *prep) { + keyring->restrict_link = prep->payload.data[keyring_restrict_link]; + prep->payload.data[keyring_restrict_link] = NULL; + assoc_array_init(&keyring->keys); /* make the keyring available by name if it has one */ keyring_publish_name(keyring);