SUNRPC: Fix races in rpcauth_create
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 9 Jun 2007 20:15:46 +0000 (16:15 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 11 Jul 2007 03:40:34 +0000 (23:40 -0400)
See the FIXME: auth_flavors[] really needs a lock and module refcounting.

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

index f6b6c81..584f243 100644 (file)
@@ -18,6 +18,7 @@
 # define RPCDBG_FACILITY       RPCDBG_AUTH
 #endif
 
+static DEFINE_SPINLOCK(rpc_authflavor_lock);
 static struct rpc_authops *    auth_flavors[RPC_AUTH_MAXFLAVOR] = {
        &authnull_ops,          /* AUTH_NULL */
        &authunix_ops,          /* AUTH_UNIX */
@@ -35,26 +36,34 @@ int
 rpcauth_register(struct rpc_authops *ops)
 {
        rpc_authflavor_t flavor;
+       int ret = -EPERM;
 
        if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
                return -EINVAL;
-       if (auth_flavors[flavor] != NULL)
-               return -EPERM;          /* what else? */
-       auth_flavors[flavor] = ops;
-       return 0;
+       spin_lock(&rpc_authflavor_lock);
+       if (auth_flavors[flavor] == NULL) {
+               auth_flavors[flavor] = ops;
+               ret = 0;
+       }
+       spin_unlock(&rpc_authflavor_lock);
+       return ret;
 }
 
 int
 rpcauth_unregister(struct rpc_authops *ops)
 {
        rpc_authflavor_t flavor;
+       int ret = -EPERM;
 
        if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
                return -EINVAL;
-       if (auth_flavors[flavor] != ops)
-               return -EPERM;          /* what else? */
-       auth_flavors[flavor] = NULL;
-       return 0;
+       spin_lock(&rpc_authflavor_lock);
+       if (auth_flavors[flavor] == ops) {
+               auth_flavors[flavor] = NULL;
+               ret = 0;
+       }
+       spin_unlock(&rpc_authflavor_lock);
+       return ret;
 }
 
 struct rpc_auth *
@@ -68,15 +77,19 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
        if (flavor >= RPC_AUTH_MAXFLAVOR)
                goto out;
 
-       /* FIXME - auth_flavors[] really needs an rw lock,
-        * and module refcounting. */
 #ifdef CONFIG_KMOD
        if ((ops = auth_flavors[flavor]) == NULL)
                request_module("rpc-auth-%u", flavor);
 #endif
-       if ((ops = auth_flavors[flavor]) == NULL)
+       spin_lock(&rpc_authflavor_lock);
+       ops = auth_flavors[flavor];
+       if (ops == NULL || !try_module_get(ops->owner)) {
+               spin_unlock(&rpc_authflavor_lock);
                goto out;
+       }
+       spin_unlock(&rpc_authflavor_lock);
        auth = ops->create(clnt, pseudoflavor);
+       module_put(ops->owner);
        if (IS_ERR(auth))
                return auth;
        if (clnt->cl_auth)