svcrpc: fix handling of garbage args
[pandora-kernel.git] / net / sunrpc / auth_gss / svcauth_gss.c
index d329a12..81ae3d6 100644 (file)
@@ -224,38 +224,34 @@ static int rsi_parse(struct cache_detail *cd,
 
        /* major/minor */
        len = qword_get(&mesg, buf, mlen);
-       if (len < 0)
+       if (len <= 0)
                goto out;
-       if (len == 0) {
+       rsii.major_status = simple_strtoul(buf, &ep, 10);
+       if (*ep)
+               goto out;
+       len = qword_get(&mesg, buf, mlen);
+       if (len <= 0)
+               goto out;
+       rsii.minor_status = simple_strtoul(buf, &ep, 10);
+       if (*ep)
                goto out;
-       } else {
-               rsii.major_status = simple_strtoul(buf, &ep, 10);
-               if (*ep)
-                       goto out;
-               len = qword_get(&mesg, buf, mlen);
-               if (len <= 0)
-                       goto out;
-               rsii.minor_status = simple_strtoul(buf, &ep, 10);
-               if (*ep)
-                       goto out;
 
-               /* out_handle */
-               len = qword_get(&mesg, buf, mlen);
-               if (len < 0)
-                       goto out;
-               status = -ENOMEM;
-               if (dup_to_netobj(&rsii.out_handle, buf, len))
-                       goto out;
+       /* out_handle */
+       len = qword_get(&mesg, buf, mlen);
+       if (len < 0)
+               goto out;
+       status = -ENOMEM;
+       if (dup_to_netobj(&rsii.out_handle, buf, len))
+               goto out;
 
-               /* out_token */
-               len = qword_get(&mesg, buf, mlen);
-               status = -EINVAL;
-               if (len < 0)
-                       goto out;
-               status = -ENOMEM;
-               if (dup_to_netobj(&rsii.out_token, buf, len))
-                       goto out;
-       }
+       /* out_token */
+       len = qword_get(&mesg, buf, mlen);
+       status = -EINVAL;
+       if (len < 0)
+               goto out;
+       status = -ENOMEM;
+       if (dup_to_netobj(&rsii.out_token, buf, len))
+               goto out;
        rsii.h.expiry_time = expiry;
        rsip = rsi_update(&rsii, rsip);
        status = 0;
@@ -975,6 +971,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
        struct kvec *resv = &rqstp->rq_res.head[0];
        struct xdr_netobj tmpobj;
        struct rsi *rsip, rsikey;
+       int ret;
 
        /* Read the verifier; should be NULL: */
        *authp = rpc_autherr_badverf;
@@ -1014,23 +1011,27 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
                /* No upcall result: */
                return SVC_DROP;
        case 0:
+               ret = SVC_DROP;
                /* Got an answer to the upcall; use it: */
                if (gss_write_init_verf(rqstp, rsip))
-                       return SVC_DROP;
+                       goto out;
                if (resv->iov_len + 4 > PAGE_SIZE)
-                       return SVC_DROP;
+                       goto out;
                svc_putnl(resv, RPC_SUCCESS);
                if (svc_safe_putnetobj(resv, &rsip->out_handle))
-                       return SVC_DROP;
+                       goto out;
                if (resv->iov_len + 3 * 4 > PAGE_SIZE)
-                       return SVC_DROP;
+                       goto out;
                svc_putnl(resv, rsip->major_status);
                svc_putnl(resv, rsip->minor_status);
                svc_putnl(resv, GSS_SEQ_WIN);
                if (svc_safe_putnetobj(resv, &rsip->out_token))
-                       return SVC_DROP;
+                       goto out;
        }
-       return SVC_COMPLETE;
+       ret = SVC_COMPLETE;
+out:
+       cache_put(&rsip->h, &rsi_cache);
+       return ret;
 }
 
 /*
@@ -1125,6 +1126,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        case RPC_GSS_PROC_DESTROY:
                if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
                        goto auth_err;
+               rsci->h.expiry_time = get_seconds();
                set_bit(CACHE_NEGATIVE, &rsci->h.flags);
                if (resv->iov_len + 4 > PAGE_SIZE)
                        goto drop;
@@ -1142,20 +1144,20 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
                case RPC_GSS_SVC_NONE:
                        break;
                case RPC_GSS_SVC_INTEGRITY:
-                       if (unwrap_integ_data(&rqstp->rq_arg,
-                                       gc->gc_seq, rsci->mechctx))
-                               goto auth_err;
                        /* placeholders for length and seq. number: */
                        svc_putnl(resv, 0);
                        svc_putnl(resv, 0);
+                       if (unwrap_integ_data(&rqstp->rq_arg,
+                                       gc->gc_seq, rsci->mechctx))
+                               goto garbage_args;
                        break;
                case RPC_GSS_SVC_PRIVACY:
-                       if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
-                                       gc->gc_seq, rsci->mechctx))
-                               goto auth_err;
                        /* placeholders for length and seq. number: */
                        svc_putnl(resv, 0);
                        svc_putnl(resv, 0);
+                       if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
+                                       gc->gc_seq, rsci->mechctx))
+                               goto garbage_args;
                        break;
                default:
                        goto auth_err;
@@ -1167,6 +1169,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
                ret = SVC_OK;
                goto out;
        }
+garbage_args:
+       ret = SVC_GARBAGE;
+       goto out;
 auth_err:
        /* Restore write pointer to its original value: */
        xdr_ressize_check(rqstp, reject_stat);
@@ -1386,10 +1391,19 @@ int
 gss_svc_init(void)
 {
        int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
-       if (rv == 0) {
-               cache_register(&rsc_cache);
-               cache_register(&rsi_cache);
-       }
+       if (rv)
+               return rv;
+       rv = cache_register(&rsc_cache);
+       if (rv)
+               goto out1;
+       rv = cache_register(&rsi_cache);
+       if (rv)
+               goto out2;
+       return 0;
+out2:
+       cache_unregister(&rsc_cache);
+out1:
+       svc_auth_unregister(RPC_AUTH_GSS);
        return rv;
 }