forked from mirrors/linux
		
	net/smc: take sock lock in smc_ioctl()
SMC ioctl processing requires the sock lock to work properly in all thinkable scenarios. Problem has been found with RaceFuzzer and fixes: KASAN: null-ptr-deref Read in smc_ioctl Reported-by: Byoungyoung Lee <lifeasageek@gmail.com> Reported-by: syzbot+35b2c5aa76fd398b9fd4@syzkaller.appspotmail.com Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Reviewed-by: Stefano Brivio <sbrivio@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									bd598d2050
								
							
						
					
					
						commit
						1992d99882
					
				
					 1 changed files with 15 additions and 4 deletions
				
			
		| 
						 | 
					@ -1524,10 +1524,13 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd,
 | 
				
			||||||
			return -EBADF;
 | 
								return -EBADF;
 | 
				
			||||||
		return smc->clcsock->ops->ioctl(smc->clcsock, cmd, arg);
 | 
							return smc->clcsock->ops->ioctl(smc->clcsock, cmd, arg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						lock_sock(&smc->sk);
 | 
				
			||||||
	switch (cmd) {
 | 
						switch (cmd) {
 | 
				
			||||||
	case SIOCINQ: /* same as FIONREAD */
 | 
						case SIOCINQ: /* same as FIONREAD */
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_LISTEN)
 | 
							if (smc->sk.sk_state == SMC_LISTEN) {
 | 
				
			||||||
 | 
								release_sock(&smc->sk);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_INIT ||
 | 
							if (smc->sk.sk_state == SMC_INIT ||
 | 
				
			||||||
		    smc->sk.sk_state == SMC_CLOSED)
 | 
							    smc->sk.sk_state == SMC_CLOSED)
 | 
				
			||||||
			answ = 0;
 | 
								answ = 0;
 | 
				
			||||||
| 
						 | 
					@ -1536,8 +1539,10 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SIOCOUTQ:
 | 
						case SIOCOUTQ:
 | 
				
			||||||
		/* output queue size (not send + not acked) */
 | 
							/* output queue size (not send + not acked) */
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_LISTEN)
 | 
							if (smc->sk.sk_state == SMC_LISTEN) {
 | 
				
			||||||
 | 
								release_sock(&smc->sk);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_INIT ||
 | 
							if (smc->sk.sk_state == SMC_INIT ||
 | 
				
			||||||
		    smc->sk.sk_state == SMC_CLOSED)
 | 
							    smc->sk.sk_state == SMC_CLOSED)
 | 
				
			||||||
			answ = 0;
 | 
								answ = 0;
 | 
				
			||||||
| 
						 | 
					@ -1547,8 +1552,10 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SIOCOUTQNSD:
 | 
						case SIOCOUTQNSD:
 | 
				
			||||||
		/* output queue size (not send only) */
 | 
							/* output queue size (not send only) */
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_LISTEN)
 | 
							if (smc->sk.sk_state == SMC_LISTEN) {
 | 
				
			||||||
 | 
								release_sock(&smc->sk);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_INIT ||
 | 
							if (smc->sk.sk_state == SMC_INIT ||
 | 
				
			||||||
		    smc->sk.sk_state == SMC_CLOSED)
 | 
							    smc->sk.sk_state == SMC_CLOSED)
 | 
				
			||||||
			answ = 0;
 | 
								answ = 0;
 | 
				
			||||||
| 
						 | 
					@ -1556,8 +1563,10 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd,
 | 
				
			||||||
			answ = smc_tx_prepared_sends(&smc->conn);
 | 
								answ = smc_tx_prepared_sends(&smc->conn);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SIOCATMARK:
 | 
						case SIOCATMARK:
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_LISTEN)
 | 
							if (smc->sk.sk_state == SMC_LISTEN) {
 | 
				
			||||||
 | 
								release_sock(&smc->sk);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (smc->sk.sk_state == SMC_INIT ||
 | 
							if (smc->sk.sk_state == SMC_INIT ||
 | 
				
			||||||
		    smc->sk.sk_state == SMC_CLOSED) {
 | 
							    smc->sk.sk_state == SMC_CLOSED) {
 | 
				
			||||||
			answ = 0;
 | 
								answ = 0;
 | 
				
			||||||
| 
						 | 
					@ -1573,8 +1582,10 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
 | 
							release_sock(&smc->sk);
 | 
				
			||||||
		return -ENOIOCTLCMD;
 | 
							return -ENOIOCTLCMD;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						release_sock(&smc->sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return put_user(answ, (int __user *)arg);
 | 
						return put_user(answ, (int __user *)arg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue