From patchwork Mon Jul 14 01:57:39 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 4542231 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9DF5AC0515 for ; Mon, 14 Jul 2014 01:58:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 98B1620145 for ; Mon, 14 Jul 2014 01:58:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9B2D92014A for ; Mon, 14 Jul 2014 01:57:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752504AbaGNB54 (ORCPT ); Sun, 13 Jul 2014 21:57:56 -0400 Received: from mail-qa0-f49.google.com ([209.85.216.49]:64968 "EHLO mail-qa0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751943AbaGNB54 (ORCPT ); Sun, 13 Jul 2014 21:57:56 -0400 Received: by mail-qa0-f49.google.com with SMTP id dc16so2718543qab.36 for ; Sun, 13 Jul 2014 18:57:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=Y3v9SVuqWZIcEZymnrbFsX9kg8h1WKOyfwXtz3q44SU=; b=ibjgZdpGMfNSJHFpr1Y+zpIJ44g3o0gsnAMAQffKOGFM4414nRO01SGB+Y+wrtB5/p mPUw+GP6bnCu5Wf/xZ43rGgH1+bbB1LMOQKitiM4PE5uouFK5hwHxuDrgosOJCTPuzl1 zewabnkQ6r103fV4tnZqgcH01zWZU0AH3b4jIcVuc3Ww/ApFR1YhNnhaFvNalKg9i1ie px6YWN55eMcfmNjzIZ+7LEDFU/83WXyIB+H0QbPKXODX8Gg0PVjz9cky4kMzgYvDMOHH cNC7a8bhJ/3kE10aqKXr/IVte0P59iaPHqsUTEBLm85Eq5O0l9P7Ixy+x6RIMvtbbvDG QO9w== X-Gm-Message-State: ALoCoQkc4Jj3H0rMTV+m/N/bI3NUxgpOizvAxrIkdbiuYYnR8jMxw0Pvib0JFNV0BgnJLuwFrgMu X-Received: by 10.224.169.20 with SMTP id w20mr17437756qay.2.1405303075241; Sun, 13 Jul 2014 18:57:55 -0700 (PDT) Received: from tlielax.poochiereds.net ([2001:470:8:d63:3a60:77ff:fe93:a95d]) by mx.google.com with ESMTPSA id d69sm5176312qge.35.2014.07.13.18.57.53 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 13 Jul 2014 18:57:54 -0700 (PDT) From: Jeff Layton To: trond.myklebust@primarydata.com Cc: bfields@fieldses.org, linux-nfs@vger.kernel.org, Arnd Bergmann , Paul McKenney Subject: [PATCH 2/7] sunrpc: fix RCU handling of gc_ctx field Date: Sun, 13 Jul 2014 21:57:39 -0400 Message-Id: <1405303064-9102-3-git-send-email-jlayton@primarydata.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1405303064-9102-1-git-send-email-jlayton@primarydata.com> References: <1405303064-9102-1-git-send-email-jlayton@primarydata.com> 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, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 The handling of the gc_ctx pointer only seems to be partially RCU-safe. The assignment and freeing are done using RCU, but many places in the code seem to dereference that pointer without proper RCU safeguards. Fix them to use rcu_dereference and to rcu_read_lock/unlock, and to properly handle the case where the pointer is NULL. Cc: Arnd Bergmann Cc: Paul McKenney Signed-off-by: Jeff Layton --- net/sunrpc/auth_gss/auth_gss.c | 52 ++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 73854314fb85..afb292cd797d 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -183,8 +183,9 @@ gss_cred_get_ctx(struct rpc_cred *cred) struct gss_cl_ctx *ctx = NULL; rcu_read_lock(); - if (gss_cred->gc_ctx) - ctx = gss_get_ctx(gss_cred->gc_ctx); + ctx = rcu_dereference(gss_cred->gc_ctx); + if (ctx) + gss_get_ctx(ctx); rcu_read_unlock(); return ctx; } @@ -1207,13 +1208,13 @@ gss_destroying_context(struct rpc_cred *cred) { struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); + struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1); struct rpc_task *task; - if (gss_cred->gc_ctx == NULL || - test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) + if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) return 0; - gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; + ctx->gc_proc = RPC_GSS_PROC_DESTROY; cred->cr_ops = &gss_nullops; /* Take a reference to ensure the cred will be destroyed either @@ -1274,7 +1275,7 @@ gss_destroy_nullcred(struct rpc_cred *cred) { struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); - struct gss_cl_ctx *ctx = gss_cred->gc_ctx; + struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1); RCU_INIT_POINTER(gss_cred->gc_ctx, NULL); call_rcu(&cred->cr_rcu, gss_free_cred_callback); @@ -1349,20 +1350,30 @@ gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred) static char * gss_stringify_acceptor(struct rpc_cred *cred) { - char *string; + char *string = NULL; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); - struct xdr_netobj *acceptor = &gss_cred->gc_ctx->gc_acceptor; + struct gss_cl_ctx *ctx; + struct xdr_netobj *acceptor; + + rcu_read_lock(); + ctx = rcu_dereference(gss_cred->gc_ctx); + if (!ctx) + goto out; + + acceptor = &ctx->gc_acceptor; /* no point if there's no string */ if (!acceptor->len) - return NULL; + goto out; string = kmalloc(acceptor->len + 1, GFP_KERNEL); if (!string) - return string; + goto out; memcpy(string, acceptor->data, acceptor->len); string[acceptor->len] = '\0'; +out: + rcu_read_unlock(); return string; } @@ -1374,15 +1385,16 @@ static int gss_key_timeout(struct rpc_cred *rc) { struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); + struct gss_cl_ctx *ctx; unsigned long now = jiffies; unsigned long expire; - if (gss_cred->gc_ctx == NULL) - return -EACCES; - - expire = gss_cred->gc_ctx->gc_expiry - (gss_key_expire_timeo * HZ); - - if (time_after(now, expire)) + rcu_read_lock(); + ctx = rcu_dereference(gss_cred->gc_ctx); + if (ctx) + expire = ctx->gc_expiry - (gss_key_expire_timeo * HZ); + rcu_read_unlock(); + if (!ctx || time_after(now, expire)) return -EACCES; return 0; } @@ -1391,13 +1403,19 @@ static int gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) { struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); + struct gss_cl_ctx *ctx; int ret; if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) goto out; /* Don't match with creds that have expired. */ - if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) + rcu_read_lock(); + ctx = rcu_dereference(gss_cred->gc_ctx); + if (!ctx || time_after(jiffies, ctx->gc_expiry)) { + rcu_read_unlock(); return 0; + } + rcu_read_unlock(); if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags)) return 0; out: