From patchwork Wed Nov 19 12:22:49 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 5336901 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B386E9F2ED for ; Wed, 19 Nov 2014 12:23:27 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C8F962017E for ; Wed, 19 Nov 2014 12:23:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C394820179 for ; Wed, 19 Nov 2014 12:23:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754368AbaKSMXD (ORCPT ); Wed, 19 Nov 2014 07:23:03 -0500 Received: from mx1.redhat.com ([209.132.183.28]:48938 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754327AbaKSMW7 (ORCPT ); Wed, 19 Nov 2014 07:22:59 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sAJCMraC023736 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 19 Nov 2014 07:22:53 -0500 Received: from warthog.procyon.org.uk ([10.3.112.3]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sAJCMnts023555; Wed, 19 Nov 2014 07:22:50 -0500 Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 2/2] KEYS: request_key() should reget expired keys rather than give EKEYEXPIRED From: David Howells To: cth@carlh.net, chuck.lever@oracle.com Cc: neilb@suse.de, dhowells@redhat.com, linux-nfs@vger.kernel.org, keyrings@linux-nfs.org, linux-kernel@vger.kernel.org Date: Wed, 19 Nov 2014 12:22:49 +0000 Message-ID: <20141119122249.26494.25661.stgit@warthog.procyon.org.uk> In-Reply-To: <20141119122238.26494.23666.stgit@warthog.procyon.org.uk> References: <20141119122238.26494.23666.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.17-dirty MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Since the keyring facility can be viewed as a cache (at least in some applications), the local expiration time on the key should probably be viewed as a 'needs updating after this time' property rather than an absolute 'anyone now wanting to use this object is out of luck' property. Since request_key() is the main interface for the usage of keys, this should update or replace an expired key rather than issuing EKEYEXPIRED if the local expiration has been reached (ie. it should refresh the cache). For absolute conditions where refreshing the cache probably doesn't help, the key can be negatively instantiated using KEYCTL_REJECT_KEY with EKEYEXPIRED given as the error to issue. This will still cause request_key() to return EKEYEXPIRED as that was explicitly set. In the future, if the key type has an update op available, we might want to upcall with the expired key and allow the upcall to update it. We would pass a different operation name (the first column in /etc/request-key.conf) to the request-key program. request_key() returning EKEYEXPIRED is causing an NFS problem which Chuck Lever describes thusly: After about 10 minutes, my NFSv4 functional tests fail because the ownership of the test files goes to "-2". Looking at /proc/keys shows that the id_resolv keys that map to my test user ID have expired. The ownership problem persists until the expired keys are purged from the keyring, and fresh keys are obtained. I bisected the problem to 3.13 commit b2a4df200d57 ("KEYS: Expand the capacity of a keyring"). This commit inadvertantly changes the API contract of the internal function keyring_search_aux(). The root cause appears to be that b2a4df200d57 made "no state check" the default behavior. "No state check" means the keyring search iterator function skips checking the key's expiry timeout, and returns expired keys. request_key_and_link() depends on getting an -EAGAIN result code to know when to perform an upcall to refresh an expired key. This patch can be tested directly by: keyctl request2 user debug:fred a @s keyctl timeout %user:debug:fred 3 sleep 4 keyctl request2 user debug:fred a @s Without the patch, the last command gives error EKEYEXPIRED, but with the command it gives a new key. Reported-by: Carl Hetherington Reported-by: Chuck Lever Signed-off-by: David Howells Tested-by: Chuck Lever --- security/keys/internal.h | 1 + security/keys/keyring.c | 3 ++- security/keys/request_key.c | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/security/keys/internal.h b/security/keys/internal.h index b8960c4959a5..200e37867336 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -117,6 +117,7 @@ struct keyring_search_context { #define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */ #define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */ #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */ +#define KEYRING_SEARCH_SKIP_EXPIRED 0x0020 /* Ignore expired keys (intention to replace) */ int (*iterator)(const void *object, void *iterator_data); diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 238aa172f25b..e72548b5897e 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -546,7 +546,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data) } if (key->expiry && ctx->now.tv_sec >= key->expiry) { - ctx->result = ERR_PTR(-EKEYEXPIRED); + if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED)) + ctx->result = ERR_PTR(-EKEYEXPIRED); kleave(" = %d [expire]", ctx->skipped_ret); goto skipped; } diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 0bb23f98e4ca..0c7aea4dea54 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -516,7 +516,8 @@ struct key *request_key_and_link(struct key_type *type, .match_data.cmp = key_default_cmp, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .flags = KEYRING_SEARCH_DO_STATE_CHECK, + .flags = (KEYRING_SEARCH_DO_STATE_CHECK | + KEYRING_SEARCH_SKIP_EXPIRED), }; struct key *key; key_ref_t key_ref;