Re: [PATCH] SUNRPC: Make sure authorize svc when meeting SVC_CLOSE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 3/10/2017 09:37, Kinglong Mee wrote:
> 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.

Sorry, it's not 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



[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux