]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/sunrpc/auth_gss/auth_gss.c
sunrpc: fix RCU handling of gc_ctx field
[karo-tx-linux.git] / net / sunrpc / auth_gss / auth_gss.c
index b6e440baccc3733f7b8963ed7ab6fddc72fd0c4c..afb292cd797decf08561492925d87d34d09e485b 100644 (file)
@@ -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;
 }
@@ -262,9 +263,22 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
                p = ERR_PTR(ret);
                goto err;
        }
-       dprintk("RPC:       %s Success. gc_expiry %lu now %lu timeout %u\n",
-               __func__, ctx->gc_expiry, now, timeout);
-       return q;
+
+       /* is there any trailing data? */
+       if (q == end) {
+               p = q;
+               goto done;
+       }
+
+       /* pull in acceptor name (if there is one) */
+       p = simple_get_netobj(q, end, &ctx->gc_acceptor);
+       if (IS_ERR(p))
+               goto err;
+done:
+       dprintk("RPC:       %s Success. gc_expiry %lu now %lu timeout %u acceptor %.*s\n",
+               __func__, ctx->gc_expiry, now, timeout, ctx->gc_acceptor.len,
+               ctx->gc_acceptor.data);
+       return p;
 err:
        dprintk("RPC:       %s returns error %ld\n", __func__, -PTR_ERR(p));
        return p;
@@ -1194,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
@@ -1225,6 +1239,7 @@ gss_do_free_ctx(struct gss_cl_ctx *ctx)
 
        gss_delete_sec_context(&ctx->gc_gss_ctx);
        kfree(ctx->gc_wire_ctx.data);
+       kfree(ctx->gc_acceptor.data);
        kfree(ctx);
 }
 
@@ -1260,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);
@@ -1332,6 +1347,36 @@ gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
        return err;
 }
 
+static char *
+gss_stringify_acceptor(struct rpc_cred *cred)
+{
+       char *string = NULL;
+       struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
+       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)
+               goto out;
+
+       string = kmalloc(acceptor->len + 1, GFP_KERNEL);
+       if (!string)
+               goto out;
+
+       memcpy(string, acceptor->data, acceptor->len);
+       string[acceptor->len] = '\0';
+out:
+       rcu_read_unlock();
+       return string;
+}
+
 /*
  * Returns -EACCES if GSS context is NULL or will expire within the
  * timeout (miliseconds)
@@ -1340,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;
 }
@@ -1357,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:
@@ -1909,29 +1961,31 @@ static const struct rpc_authops authgss_ops = {
 };
 
 static const struct rpc_credops gss_credops = {
-       .cr_name        = "AUTH_GSS",
-       .crdestroy      = gss_destroy_cred,
-       .cr_init        = gss_cred_init,
-       .crbind         = rpcauth_generic_bind_cred,
-       .crmatch        = gss_match,
-       .crmarshal      = gss_marshal,
-       .crrefresh      = gss_refresh,
-       .crvalidate     = gss_validate,
-       .crwrap_req     = gss_wrap_req,
-       .crunwrap_resp  = gss_unwrap_resp,
-       .crkey_timeout  = gss_key_timeout,
+       .cr_name                = "AUTH_GSS",
+       .crdestroy              = gss_destroy_cred,
+       .cr_init                = gss_cred_init,
+       .crbind                 = rpcauth_generic_bind_cred,
+       .crmatch                = gss_match,
+       .crmarshal              = gss_marshal,
+       .crrefresh              = gss_refresh,
+       .crvalidate             = gss_validate,
+       .crwrap_req             = gss_wrap_req,
+       .crunwrap_resp          = gss_unwrap_resp,
+       .crkey_timeout          = gss_key_timeout,
+       .crstringify_acceptor   = gss_stringify_acceptor,
 };
 
 static const struct rpc_credops gss_nullops = {
-       .cr_name        = "AUTH_GSS",
-       .crdestroy      = gss_destroy_nullcred,
-       .crbind         = rpcauth_generic_bind_cred,
-       .crmatch        = gss_match,
-       .crmarshal      = gss_marshal,
-       .crrefresh      = gss_refresh_null,
-       .crvalidate     = gss_validate,
-       .crwrap_req     = gss_wrap_req,
-       .crunwrap_resp  = gss_unwrap_resp,
+       .cr_name                = "AUTH_GSS",
+       .crdestroy              = gss_destroy_nullcred,
+       .crbind                 = rpcauth_generic_bind_cred,
+       .crmatch                = gss_match,
+       .crmarshal              = gss_marshal,
+       .crrefresh              = gss_refresh_null,
+       .crvalidate             = gss_validate,
+       .crwrap_req             = gss_wrap_req,
+       .crunwrap_resp          = gss_unwrap_resp,
+       .crstringify_acceptor   = gss_stringify_acceptor,
 };
 
 static const struct rpc_pipe_ops gss_upcall_ops_v0 = {