SUNRPC: Always match an upcall message in gss_pipe_downcall()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 7 Jun 2007 14:14:15 +0000 (10:14 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 11 Jul 2007 03:40:31 +0000 (23:40 -0400)
It used to be possible for an rpc.gssd daemon to stuff the RPC credential
cache for any rpc client simply by creating RPCSEC_GSS contexts and then
doing downcalls. In practice, no daemons ever made use of this feature.

Remove this feature now, since it will be impossible to figure out which
mechanism a given context actually matches if we enable more
than one gss mechanism to use the same upcall pipe.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
net/sunrpc/auth_gss/auth_gss.c

index 653d712..e407a35 100644 (file)
@@ -306,8 +306,6 @@ gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg)
 static void
 __gss_unhash_msg(struct gss_upcall_msg *gss_msg)
 {
-       if (list_empty(&gss_msg->list))
-               return;
        list_del_init(&gss_msg->list);
        rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
        wake_up_all(&gss_msg->waitqueue);
@@ -320,8 +318,11 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg)
        struct gss_auth *gss_auth = gss_msg->auth;
        struct inode *inode = gss_auth->dentry->d_inode;
 
+       if (list_empty(&gss_msg->list))
+               return;
        spin_lock(&inode->i_lock);
-       __gss_unhash_msg(gss_msg);
+       if (!list_empty(&gss_msg->list))
+               __gss_unhash_msg(gss_msg);
        spin_unlock(&inode->i_lock);
 }
 
@@ -493,12 +494,11 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        void *buf;
        struct rpc_clnt *clnt;
        struct gss_auth *gss_auth;
-       struct rpc_cred *cred;
        struct gss_upcall_msg *gss_msg;
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct gss_cl_ctx *ctx;
        uid_t uid;
-       int err = -EFBIG;
+       ssize_t err = -EFBIG;
 
        if (mlen > MSG_BUF_MAXSIZE)
                goto out;
@@ -523,43 +523,39 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        ctx = gss_alloc_context();
        if (ctx == NULL)
                goto err;
-       err = 0;
+
+       err = -ENOENT;
+       /* Find a matching upcall */
        gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth);
+       spin_lock(&inode->i_lock);
+       gss_msg = __gss_find_upcall(gss_auth, uid);
+       if (gss_msg == NULL) {
+               spin_unlock(&inode->i_lock);
+               goto err_put_ctx;
+       }
+       list_del_init(&gss_msg->list);
+       spin_unlock(&inode->i_lock);
+
        p = gss_fill_context(p, end, ctx, gss_auth->mech);
        if (IS_ERR(p)) {
                err = PTR_ERR(p);
-               if (err != -EACCES)
-                       goto err_put_ctx;
+               gss_msg->msg.errno = (err == -EACCES) ? -EACCES : -EAGAIN;
+               goto err_release_msg;
        }
+       gss_msg->ctx = gss_get_ctx(ctx);
+       err = mlen;
+
+err_release_msg:
        spin_lock(&inode->i_lock);
-       gss_msg = __gss_find_upcall(gss_auth, uid);
-       if (gss_msg) {
-               if (err == 0 && gss_msg->ctx == NULL)
-                       gss_msg->ctx = gss_get_ctx(ctx);
-               gss_msg->msg.errno = err;
-               __gss_unhash_msg(gss_msg);
-               spin_unlock(&inode->i_lock);
-               gss_release_msg(gss_msg);
-       } else {
-               struct auth_cred acred = { .uid = uid };
-               spin_unlock(&inode->i_lock);
-               cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW);
-               if (IS_ERR(cred)) {
-                       err = PTR_ERR(cred);
-                       goto err_put_ctx;
-               }
-               gss_cred_set_ctx(cred, gss_get_ctx(ctx));
-       }
-       gss_put_ctx(ctx);
-       kfree(buf);
-       dprintk("RPC:       gss_pipe_downcall returning length %Zu\n", mlen);
-       return mlen;
+       __gss_unhash_msg(gss_msg);
+       spin_unlock(&inode->i_lock);
+       gss_release_msg(gss_msg);
 err_put_ctx:
        gss_put_ctx(ctx);
 err:
        kfree(buf);
 out:
-       dprintk("RPC:       gss_pipe_downcall returning %d\n", err);
+       dprintk("RPC:       gss_pipe_downcall returning %Zd\n", err);
        return err;
 }