Received: by 2002:ad5:4acb:0:0:0:0:0 with SMTP id n11csp4300393imw; Tue, 12 Jul 2022 05:45:20 -0700 (PDT) X-Google-Smtp-Source: AGRyM1uTP06Y19T/QOA6c262yWVYBCoo6943TBtK9dA2a4/e6n7eOmrEL8D6l1/2Zn04ITI940EO X-Received: by 2002:a17:90a:4704:b0:1ef:f369:bd0e with SMTP id h4-20020a17090a470400b001eff369bd0emr4121371pjg.20.1657629920496; Tue, 12 Jul 2022 05:45:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1657629920; cv=none; d=google.com; s=arc-20160816; b=jjRkiqVZH0+hjN+cTm0Ncq656OPPURO4n8UuRW7Xjz5V8VYGAOBqS6//LsX4tImmXt /dTpem+JofDck+7Bdzh2/rn8UpFhDtxOnh4P+6mOypnNwsVq/Fwa5c+EnXsoiCPXQR62 o+p/gh1DatAHxPyPEc1H02/vbMMfiFzksDAZI8hzLM2W2+rSrxReFI44u2ZbvgNixSoj gnk3ap1yTcUJDml0IgbCK4Y+ex3Py5ZJa8PRwfzBgIcEchLF8I2mtCZlwQr/8oQwktqo PTb7SiNrQjGfu0l27z380D+omJhuT6ZnMrCvcU27P1MIpSuamYsdobpbPWPHfQSxiSt8 lxYA== 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 :message-id:date:subject:cc:to:from:dkim-signature; bh=ZRNqvwEkQjWUz9SudAZmar3Unjg5boMD/ciY51IuWI8=; b=zxgaJkRqvPXmZOQ+dN1aUkcfWhqM8Lv5kXQYs8HEwCp3apS+rj7/UGWuqTzO7RW4kC qPAh6c9gZiWN56u2Ll8kDnccAe7uccjpEjip82kfrDFAAwSoW3S9DCom+HsFEMQS/XWL 9IyE04Z6VsXF4rqC1kzn+cYAbhO6nBgI4a98dFhiWDs6iXorwnOPkyvpLz+lJ3rVYNSS GFB24t+lvZNC7VMUbLEUFXBdTwSj36aAc7FmJqcR4L2dropU/6XovVegX1uXVgA9Eydq u05JSriHImnURXtF9Jx6vRvUtFIs0mRD8DrVqDvqqcCp7Bbc+ICKQ7uyLD7Aas7bXUHF uSPg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=gB4ZcsAH; spf=pass (google.com: domain of linux-nfs-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t5-20020a637805000000b0040db5dc1750si13957538pgc.853.2022.07.12.05.44.57; Tue, 12 Jul 2022 05:45:20 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-nfs-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=@redhat.com header.s=mimecast20190719 header.b=gB4ZcsAH; spf=pass (google.com: domain of linux-nfs-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230230AbiGLMf1 (ORCPT + 99 others); Tue, 12 Jul 2022 08:35:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52314 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231259AbiGLMf0 (ORCPT ); Tue, 12 Jul 2022 08:35:26 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9A3082B619 for ; Tue, 12 Jul 2022 05:35:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1657629323; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=ZRNqvwEkQjWUz9SudAZmar3Unjg5boMD/ciY51IuWI8=; b=gB4ZcsAHK9jDfveQQ8QiT3AK3hrjD50kCmCQSL9jXN/+8m/jvrMYRjCLWbTr7vQOqEvOqS zsBehL6VCCYtf7X4TX/xerdtZ6sAx3mIJJwZHJDEdm+sLV0iAa0k9bgPbA5ea4sv80e6om /j72e0KzBPYYFBL1CdkO8tjNVvIcwV8= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-454-Fr7dWCPbPbS7hKwO1fVVSw-1; Tue, 12 Jul 2022 08:35:22 -0400 X-MC-Unique: Fr7dWCPbPbS7hKwO1fVVSw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0FAF02919EBB; Tue, 12 Jul 2022 12:35:22 +0000 (UTC) Received: from bcodding.csb (unknown [10.22.48.8]) by smtp.corp.redhat.com (Postfix) with ESMTP id CDAE82026D64; Tue, 12 Jul 2022 12:35:21 +0000 (UTC) Received: by bcodding.csb (Postfix, from userid 24008) id 50C4A10C30E0; Tue, 12 Jul 2022 08:35:21 -0400 (EDT) From: Benjamin Coddington To: David Howells , linux-kernel@vger.kernel.org Cc: ebiederm@xmission.com, Ian Kent , Trond Myklebust , linux-nfs@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH 0/2] Keyagents: another call_usermodehelper approach for namespaces Date: Tue, 12 Jul 2022 08:35:19 -0400 Message-Id: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=ham 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-nfs@vger.kernel.org A persistent unsolved problem exists: how can the kernel find and/or create the appropriate "container" within which to execute a userspace program to construct keys or satisfy users of call_usermodehelper()? I believe the latest serious attempt to solve this problem was David's "Make containers kernel objects": https://lore.kernel.org/lkml/149547014649.10599.12025037906646164347.stgit@warthog.procyon.org.uk/ Over in NFS' space, we've most recently pondered this issue while looking at ways to pass a kernel socket to userspace in order to handle TLS events: https://lore.kernel.org/linux-nfs/E2BF9CFF-9361-400B-BDEE-CF5E0AFDCA63@redhat.com/ The problem is that containers are not kernel objects, rather a collection of namespaces, cgroups, etc. Attempts at making the kernel aware of containers have been mired in discussion and problems. It has been suggested that the best representation of a "container" from the kernel's perspective is a process. Keyagents are processes represented by a key. If a keyagent's key is linked to a session_keyring, it can be sent a realtime signal when a calling process requests a matching key_type. That signal will dispatch the process to construct the desired key within the keyagent process context. Keyagents are similar to ssh-agents. To use a keyagent, one must execute a keyagent process in the desired context, and then link the keyagent's key onto other process' session_keyrings. This method of linking keyagent keys to session_keyrings can be used to construct the various mappings of callers to keyagents that containers may need. A single keyagent process can answer request-key upcalls across container boundaries, or upcalls can be restricted to specific containers. I'm aware that building on realtime signals may not be a popular choice, but using realtime signals makes this work simple and ensures delivery. Realtime signals are able to convey everything needed to construct keys in userspace: the under-construction key's serial number. This work is not complete; it has security implications, it needs documentation, it has not been reviewed by anyone. Thanks for reading this RFC. I wish to collect criticism and validate this approach. Below the diffstat in this message is an example userspace program to answer keyagent requests for user keys. It can be compiled with: gcc -lkeyutils -o ka_simple ka_simple.c Benjamin Coddington (2): KEYS: Add key_type keyagent KEYS: Add keyagent request_key include/uapi/asm-generic/siginfo.h | 1 + security/keys/Kconfig | 9 ++ security/keys/Makefile | 1 + security/keys/internal.h | 4 + security/keys/keyagent.c | 158 +++++++++++++++++++++++++++++ security/keys/request_key.c | 9 ++ 6 files changed, 182 insertions(+) create mode 100644 security/keys/keyagent.c -- // SPDX-License-Identifier: GPL-2.0-only /* ka_simple.c: userspace keyagent example * * Copyright (C) 2022 Red Hat Inc. All Rights Reserved. * Written by Benjamin Coddington (bcodding@redhat.com) * * This programs registers a simple keyagent for user keys that will handle * requests from the kernel keyagent, and instantiate keys that have * callout_info == "test_callout_info". */ #include #include #include #include #include #include #include #include #include #include int ka_sig_fd = 0; key_serial_t ka_key_serial; __be16 ka_signal; /* Setup a signalfd masked to SIGRTMIN + 1 */ void ka_sig_setup() { int ret; sigset_t mask; /* Which realtime signal are we using? */ ka_signal = SIGRTMIN + 1; sigemptyset(&mask); sigaddset(&mask, ka_signal); ret = sigprocmask(SIG_BLOCK, &mask, NULL); if (ret != 0) err(ret, "rt_sigprocmask"); ka_sig_fd = signalfd(-1, &mask, 0); if (ka_sig_fd == -1) err(ret, "signalfd"); } /* Register this process as a keyagent for user keys to be notified by * signal number SIGRTMIN + 1 by creating a keyagent key with a description * of "user", and payload of SIGRTMIN + 1 */ void ka_register() { printf("Registering as keyagent for user keys with signal %d\n", ka_signal); /* The kernel will place authorization keys on our process keyring. * Make sure we have a process keyring: */ keyctl_get_keyring_ID(KEY_SPEC_PROCESS_KEYRING, 1); ka_key_serial = add_key("keyagent", "user", &ka_signal, sizeof(unsigned int), KEY_SPEC_SESSION_KEYRING); if (ka_key_serial == -1) err(errno, "add_key"); /* Permissions for the keyagent's key: */ keyctl_setperm(ka_key_serial, KEY_USR_ALL); } /* Handle kernel request_key(). The serial number of the key is the int * passed in the realtime signal */ int ka_request_key(key_serial_t key) { int ret, ntype, dpos, n; char *buf_type_desc, *key_type, *key_desc; void *callout; printf("ka_request_key %d\n", key); ret = keyctl_assume_authority(key); if (ret < 0) { warn("failed to assume authority over key %d (%m)\n", key); goto out; } ret = keyctl_describe_alloc(key, &buf_type_desc); if (ret < 0) { warn("key %d inaccessible (%m)\n", key); goto out; } printf("Key descriptor: \"%s\"\n", buf_type_desc); /* Shamelessly copied from libkeyutils/request_key.c: */ ntype = -1; dpos = -1; n = sscanf(buf_type_desc, "%*[^;]%n;%*d;%*d;%x;%n", &ntype, &n, &dpos); if (n != 1) printf("Failed to parse key description\n"); key_type = buf_type_desc; key_type[ntype] = 0; key_desc = buf_type_desc + dpos; ret = keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, &callout); if (ret < 0) { warn("failed to retrieve callout info (%m)\n"); goto out_free_type; } if (strcmp(buf_type_desc, "user") == 0 && strcmp(callout, "test_callout_info") == 0) { keyctl_instantiate(key, "keyagent_payload", sizeof("keyagent_payload"), KEY_SPEC_SESSION_KEYRING); printf("instantiated key %d with payload \"keyagent_payload\" on session keyring\n", key); } else { keyctl_reject(key, 10, EKEYREJECTED, KEY_SPEC_SESSION_KEYRING); printf("this keyagent only instantiates user keys with callout \"test_callout_info\"\n"); } /* De-assume the authority (for now) */ ret = keyctl_assume_authority(0); free(callout); out_free_type: free(buf_type_desc); out: return ret; } /* Handle signals from our signalfd, dispatch ka_request_key() */ int ka_process() { struct signalfd_siginfo fdsi; ssize_t size; for (;;) { size = read(ka_sig_fd, &fdsi, sizeof(struct signalfd_siginfo)); if (size != sizeof(struct signalfd_siginfo)) err(EINVAL, "reading signal_fd"); if (ka_request_key(fdsi.ssi_int)) break; } } int main(int argc, char **argv) { ka_sig_setup(); ka_register(); printf("Registered as keyagent with key %d\n", ka_key_serial); printf("Subscribe to this keyagent by linking it into your session keyring with:\n\tkeyctl link %d @s\n", ka_key_serial); printf("then, you can send a request to this agent with:\n\tkeyctl request2 user \"test_callout_info\"\n"); ka_process(); } -- 2.31.1