Skip to content

Commit c034203

Browse files
Dan Carpenterchucklever
authored andcommitted
nfsd: fix double fget() bug in __write_ports_addfd()
The bug here is that you cannot rely on getting the same socket from multiple calls to fget() because userspace can influence that. This is a kind of double fetch bug. The fix is to delete the svc_alien_sock() function and instead do the checking inside the svc_addsock() function. Fixes: 3064639 ("nfsd: check passed socket's net matches NFSd superblock's one") Signed-off-by: Dan Carpenter <[email protected]> Reviewed-by: NeilBrown <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent d53d700 commit c034203

File tree

3 files changed

+10
-28
lines changed

3 files changed

+10
-28
lines changed

fs/nfsd/nfsctl.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -690,16 +690,11 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred
690690
if (err != 0 || fd < 0)
691691
return -EINVAL;
692692

693-
if (svc_alien_sock(net, fd)) {
694-
printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__);
695-
return -EINVAL;
696-
}
697-
698693
err = nfsd_create_serv(net);
699694
if (err != 0)
700695
return err;
701696

702-
err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
697+
err = svc_addsock(nn->nfsd_serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
703698

704699
if (err >= 0 &&
705700
!nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1))

include/linux/sunrpc/svcsock.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,9 @@ int svc_recv(struct svc_rqst *, long);
6161
void svc_send(struct svc_rqst *rqstp);
6262
void svc_drop(struct svc_rqst *);
6363
void svc_sock_update_bufs(struct svc_serv *serv);
64-
bool svc_alien_sock(struct net *net, int fd);
65-
int svc_addsock(struct svc_serv *serv, const int fd,
66-
char *name_return, const size_t len,
67-
const struct cred *cred);
64+
int svc_addsock(struct svc_serv *serv, struct net *net,
65+
const int fd, char *name_return, const size_t len,
66+
const struct cred *cred);
6867
void svc_init_xprt_sock(void);
6968
void svc_cleanup_xprt_sock(void);
7069
struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot);

net/sunrpc/svcsock.c

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,25 +1480,10 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
14801480
return svsk;
14811481
}
14821482

1483-
bool svc_alien_sock(struct net *net, int fd)
1484-
{
1485-
int err;
1486-
struct socket *sock = sockfd_lookup(fd, &err);
1487-
bool ret = false;
1488-
1489-
if (!sock)
1490-
goto out;
1491-
if (sock_net(sock->sk) != net)
1492-
ret = true;
1493-
sockfd_put(sock);
1494-
out:
1495-
return ret;
1496-
}
1497-
EXPORT_SYMBOL_GPL(svc_alien_sock);
1498-
14991483
/**
15001484
* svc_addsock - add a listener socket to an RPC service
15011485
* @serv: pointer to RPC service to which to add a new listener
1486+
* @net: caller's network namespace
15021487
* @fd: file descriptor of the new listener
15031488
* @name_return: pointer to buffer to fill in with name of listener
15041489
* @len: size of the buffer
@@ -1508,8 +1493,8 @@ EXPORT_SYMBOL_GPL(svc_alien_sock);
15081493
* Name is terminated with '\n'. On error, returns a negative errno
15091494
* value.
15101495
*/
1511-
int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
1512-
const size_t len, const struct cred *cred)
1496+
int svc_addsock(struct svc_serv *serv, struct net *net, const int fd,
1497+
char *name_return, const size_t len, const struct cred *cred)
15131498
{
15141499
int err = 0;
15151500
struct socket *so = sockfd_lookup(fd, &err);
@@ -1520,6 +1505,9 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
15201505

15211506
if (!so)
15221507
return err;
1508+
err = -EINVAL;
1509+
if (sock_net(so->sk) != net)
1510+
goto out;
15231511
err = -EAFNOSUPPORT;
15241512
if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
15251513
goto out;

0 commit comments

Comments
 (0)