On 1/19/2017 06:20, J. Bruce Fields wrote: > On Mon, Jan 16, 2017 at 08:23:37AM +0800, Kinglong Mee wrote: >> Commit 4d712ef1db05 "svcauth_gss: Close connection when >> dropping an incoming message" will close connection, >> but forget authorizing the svc when meeting SVC_CLOSE. >> >> That, there will be an module reference to sunrpc, >> and some memory leak. >> >> When mounting an nfs filesystem, the reference leak increase one. > > Thanks, applying for 4.10. > > (I'm not too happy with this function--e.g. it'd be easier to avoid this > sort of bug if we had a single unavoidable common exit that always > called svc_authenticate. > > But I'm not sure of the best cleanup on a quick look. And this is a > simple bugfix. Maybe we could add some cleanup on top for 4.11.) Hi Bruce, I don't see this patch in the latest linux kernel (4.11.0-rc1+), what's your plan about it? Ps, for the cleanup, I have a draft for it, but it's a good one. thanks, Kinglong Mee ----------------------------------------------------------------------------- diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 44e7d49..a390842 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1086,6 +1086,30 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} #endif +#define FMT_ERR_ENCODE(rpc_stat) do { \ + svc_printk(rqstp, "svc: decode error ##rpc_stat (%s:%d)\n", \ + __FILE__, __LINE__); \ + serv->sv_stats->rpcbadfmt++; \ + svc_putnl(resv, (rpc_stat)); \ +} while (0) + +#define VERS_ERR_ENCODE(lovers, hivers) do { \ + FMT_ERR_ENCODE(RPC_PROG_MISMATCH); \ + svc_putnl(resv, (lovers)); \ + svc_putnl(resv, (hivers)); \ +} while (0) + +#define AUTH_ERR_ENCODE(auth_stat) do { \ + svc_printk(rqstp, "svc: authentication error %d (%s:%d)\n", \ + ntohl(auth_stat), __FILE__, __LINE__); \ + serv->sv_stats->rpcbadauth++; \ + /* Restore write pointer to location of accept status: */ \ + xdr_ressize_check(rqstp, reply_statp); \ + svc_putnl(resv, 1); /* REJECT */ \ + svc_putnl(resv, 1); /* AUTH_ERROR */ \ + svc_putnl(resv, ntohl(auth_stat)); /* status */ \ +} while (0) + /* * Common routine for processing the RPC request. */ @@ -1099,14 +1123,15 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) kxdrproc_t xdr; __be32 *statp; u32 prog, vers, proc; - __be32 auth_stat, rpc_stat; + __be32 auth_stat; int auth_res; __be32 *reply_statp; - rpc_stat = rpc_success; - - if (argv->iov_len < 6*4) - goto err_short_len; + if (argv->iov_len < 6*4) { + svc_printk(rqstp, "short len %zd, dropping request\n", + argv->iov_len); + goto close; + } /* Will be turned off only in gss privacy case: */ set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); @@ -1124,8 +1149,14 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) /* First words of reply: */ svc_putnl(resv, 1); /* REPLY */ - if (vers != 2) /* RPC version number */ - goto err_bad_rpc; + if (vers != 2) { /* RPC version number */ + serv->sv_stats->rpcbadfmt++; + svc_putnl(resv, 1); /* REJECT */ + svc_putnl(resv, 0); /* RPC_MISMATCH */ + svc_putnl(resv, 2); /* Only RPCv2 supported */ + svc_putnl(resv, 2); + goto sendit; + } /* Save position in case we later decide to reject: */ reply_statp = resv->iov_base + resv->iov_len; @@ -1155,12 +1186,14 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) case SVC_OK: break; case SVC_GARBAGE: - goto err_garbage; + FMT_ERR_ENCODE(RPC_GARBAGE_ARGS); + goto sendit; case SVC_SYSERR: - rpc_stat = rpc_system_err; - goto err_bad; + FMT_ERR_ENCODE(RPC_SYSTEM_ERR); + goto sendit; case SVC_DENIED: - goto err_bad_auth; + AUTH_ERR_ENCODE(auth_stat); + goto sendit; case SVC_CLOSE: /* * Makesure authorise svc if progp->pg_authenticate fail, @@ -1174,12 +1207,19 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) goto sendit; } - if (progp == NULL) - goto err_bad_prog; + if (progp == NULL) { + FMT_ERR_ENCODE(RPC_PROG_UNAVAIL); + svc_printk(rqstp, "svc: unknown program %d\n", prog); + goto sendit; + } if (vers >= progp->pg_nvers || - !(versp = progp->pg_vers[vers])) - goto err_bad_vers; + !(versp = progp->pg_vers[vers])) { + VERS_ERR_ENCODE(progp->pg_lovers, progp->pg_hivers); + svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", + vers, prog, progp->pg_name); + goto sendit; + } /* * Some protocol versions (namely NFSv4) require some form of @@ -1193,12 +1233,20 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) * fit. */ if (versp->vs_need_cong_ctrl && - !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags)) - goto err_bad_vers; + !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags)) { + VERS_ERR_ENCODE(progp->pg_lovers, progp->pg_hivers); + svc_printk(rqstp, "congestion control (%d for prog %d, %s)\n", + vers, prog, progp->pg_name); + goto sendit; + } procp = versp->vs_proc + proc; - if (proc >= versp->vs_nproc || !procp->pc_func) - goto err_bad_proc; + if (proc >= versp->vs_nproc || !procp->pc_func) { + FMT_ERR_ENCODE(RPC_PROC_UNAVAIL); + svc_printk(rqstp, "unknown procedure (%d)\n", proc); + goto sendit; + } + rqstp->rq_procinfo = procp; /* Syntactic check complete */ @@ -1225,8 +1273,10 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) if (!versp->vs_dispatch) { /* Decode arguments */ xdr = procp->pc_decode; - if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) - goto err_garbage; + if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) { + FMT_ERR_ENCODE(RPC_GARBAGE_ARGS); + goto sendit; + } *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); @@ -1240,12 +1290,14 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) if (*statp == rpc_autherr_badcred) { if (procp->pc_release) procp->pc_release(rqstp, NULL, rqstp->rq_resp); - goto err_bad_auth; + + AUTH_ERR_ENCODE(auth_stat); + goto sendit; } if (*statp == rpc_success && (xdr = procp->pc_encode) && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { - dprintk("svc: failed to encode reply\n"); + svc_printk(rqstp, "svc: failed to encode reply\n"); /* serv->sv_stats->rpcsystemerr++; */ *statp = rpc_system_err; } @@ -1269,77 +1321,18 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) if (procp->pc_encode == NULL) goto dropit; - - sendit: - if (svc_authorise(rqstp)) - goto close; - return 1; /* Caller can now send it */ - - dropit: - svc_authorise(rqstp); /* doesn't hurt to call this twice */ - dprintk("svc: svc_process dropit\n"); - return 0; - - close: +sendit: + if (!svc_authorise(rqstp)) + return 1; /* Caller can now send it */ +close: if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) svc_close_xprt(rqstp->rq_xprt); dprintk("svc: svc_process close\n"); return 0; - -err_short_len: - svc_printk(rqstp, "short len %zd, dropping request\n", - argv->iov_len); - goto close; - -err_bad_rpc: - serv->sv_stats->rpcbadfmt++; - svc_putnl(resv, 1); /* REJECT */ - svc_putnl(resv, 0); /* RPC_MISMATCH */ - svc_putnl(resv, 2); /* Only RPCv2 supported */ - svc_putnl(resv, 2); - goto sendit; - -err_bad_auth: - dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); - serv->sv_stats->rpcbadauth++; - /* Restore write pointer to location of accept status: */ - xdr_ressize_check(rqstp, reply_statp); - svc_putnl(resv, 1); /* REJECT */ - svc_putnl(resv, 1); /* AUTH_ERROR */ - svc_putnl(resv, ntohl(auth_stat)); /* status */ - goto sendit; - -err_bad_prog: - dprintk("svc: unknown program %d\n", prog); - serv->sv_stats->rpcbadfmt++; - svc_putnl(resv, RPC_PROG_UNAVAIL); - goto sendit; - -err_bad_vers: - svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", - vers, prog, progp->pg_name); - - serv->sv_stats->rpcbadfmt++; - svc_putnl(resv, RPC_PROG_MISMATCH); - svc_putnl(resv, progp->pg_lovers); - svc_putnl(resv, progp->pg_hivers); - goto sendit; - -err_bad_proc: - svc_printk(rqstp, "unknown procedure (%d)\n", proc); - - serv->sv_stats->rpcbadfmt++; - svc_putnl(resv, RPC_PROC_UNAVAIL); - goto sendit; - -err_garbage: - svc_printk(rqstp, "failed to decode args\n"); - - rpc_stat = rpc_garbage_args; -err_bad: - serv->sv_stats->rpcbadfmt++; - svc_putnl(resv, ntohl(rpc_stat)); - goto sendit; +dropit: + svc_authorise(rqstp); /* doesn't hurt to call this twice */ + dprintk("svc: svc_process dropit\n"); + return 0; } /* -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html