forked from mirrors/linux
		
	lockd: Add helper to sanity check incoming NOTIFY requests
lockd accepts SM_NOTIFY calls only from a privileged process on the local system. If lockd uses an AF_INET6 listener, the sender's address (ie the local rpc.statd) will be the IPv6 loopback address, not the IPv4 loopback address. Make sure the privilege test in nlmsvc_proc_sm_notify() and nlm4svc_proc_sm_notify() works for both AF_INET and AF_INET6 family addresses by refactoring the test into a helper and adding support for IPv6 addresses. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
This commit is contained in:
		
							parent
							
								
									dcff09f124
								
							
						
					
					
						commit
						b85e467634
					
				
					 3 changed files with 45 additions and 8 deletions
				
			
		|  | @ -421,11 +421,9 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, | ||||||
| { | { | ||||||
| 	struct sockaddr_in	saddr; | 	struct sockaddr_in	saddr; | ||||||
| 
 | 
 | ||||||
| 	memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr)); |  | ||||||
| 
 |  | ||||||
| 	dprintk("lockd: SM_NOTIFY     called\n"); | 	dprintk("lockd: SM_NOTIFY     called\n"); | ||||||
| 	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) | 
 | ||||||
| 	 || ntohs(saddr.sin_port) >= 1024) { | 	if (!nlm_privileged_requester(rqstp)) { | ||||||
| 		char buf[RPC_MAX_ADDRBUFLEN]; | 		char buf[RPC_MAX_ADDRBUFLEN]; | ||||||
| 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", | 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", | ||||||
| 				svc_print_addr(rqstp, buf, sizeof(buf))); | 				svc_print_addr(rqstp, buf, sizeof(buf))); | ||||||
|  |  | ||||||
|  | @ -453,11 +453,9 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, | ||||||
| { | { | ||||||
| 	struct sockaddr_in	saddr; | 	struct sockaddr_in	saddr; | ||||||
| 
 | 
 | ||||||
| 	memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr)); |  | ||||||
| 
 |  | ||||||
| 	dprintk("lockd: SM_NOTIFY     called\n"); | 	dprintk("lockd: SM_NOTIFY     called\n"); | ||||||
| 	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) | 
 | ||||||
| 	 || ntohs(saddr.sin_port) >= 1024) { | 	if (!nlm_privileged_requester(rqstp)) { | ||||||
| 		char buf[RPC_MAX_ADDRBUFLEN]; | 		char buf[RPC_MAX_ADDRBUFLEN]; | ||||||
| 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", | 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", | ||||||
| 				svc_print_addr(rqstp, buf, sizeof(buf))); | 				svc_print_addr(rqstp, buf, sizeof(buf))); | ||||||
|  |  | ||||||
|  | @ -277,6 +277,47 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) | ||||||
| 	return file->f_file->f_path.dentry->d_inode; | 	return file->f_file->f_path.dentry->d_inode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline int __nlm_privileged_request4(const struct sockaddr *sap) | ||||||
|  | { | ||||||
|  | 	const struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||||||
|  | 	return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) && | ||||||
|  | 			(ntohs(sin->sin_port) < 1024); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||||||
|  | static inline int __nlm_privileged_request6(const struct sockaddr *sap) | ||||||
|  | { | ||||||
|  | 	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||||||
|  | 	return (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK) && | ||||||
|  | 			(ntohs(sin6->sin6_port) < 1024); | ||||||
|  | } | ||||||
|  | #else	/* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | ||||||
|  | static inline int __nlm_privileged_request6(const struct sockaddr *sap) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | #endif	/* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Ensure incoming requests are from local privileged callers. | ||||||
|  |  * | ||||||
|  |  * Return TRUE if sender is local and is connecting via a privileged port; | ||||||
|  |  * otherwise return FALSE. | ||||||
|  |  */ | ||||||
|  | static inline int nlm_privileged_requester(const struct svc_rqst *rqstp) | ||||||
|  | { | ||||||
|  | 	const struct sockaddr *sap = svc_addr(rqstp); | ||||||
|  | 
 | ||||||
|  | 	switch (sap->sa_family) { | ||||||
|  | 	case AF_INET: | ||||||
|  | 		return __nlm_privileged_request4(sap); | ||||||
|  | 	case AF_INET6: | ||||||
|  | 		return __nlm_privileged_request6(sap); | ||||||
|  | 	default: | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline int __nlm_cmp_addr4(const struct sockaddr *sap1, | static inline int __nlm_cmp_addr4(const struct sockaddr *sap1, | ||||||
| 				  const struct sockaddr *sap2) | 				  const struct sockaddr *sap2) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Chuck Lever
						Chuck Lever