unexport sock_map_fd(), switch to sock_alloc_file()
Both modular callers of sock_map_fd() had been buggy; sctp one leaks descriptor and file if copy_to_user() fails, 9p one shouldn't be exposing file in the descriptor table at all. Switch both to sock_alloc_file(), export it, unexport sock_map_fd() and make it static. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
2840763051
commit
56b31d1c9f
|
@ -65,6 +65,7 @@ typedef enum {
|
|||
struct poll_table_struct;
|
||||
struct pipe_inode_info;
|
||||
struct inode;
|
||||
struct file;
|
||||
struct net;
|
||||
|
||||
#define SOCK_ASYNC_NOSPACE 0
|
||||
|
@ -246,7 +247,7 @@ extern int sock_sendmsg(struct socket *sock, struct msghdr *msg,
|
|||
size_t len);
|
||||
extern int sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||
size_t size, int flags);
|
||||
extern int sock_map_fd(struct socket *sock, int flags);
|
||||
extern struct file *sock_alloc_file(struct socket *sock, int flags);
|
||||
extern struct socket *sockfd_lookup(int fd, int *err);
|
||||
extern struct socket *sock_from_file(struct file *file, int *err);
|
||||
#define sockfd_put(sock) fput(sock->file)
|
||||
|
|
|
@ -793,30 +793,28 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
|
|||
static int p9_socket_open(struct p9_client *client, struct socket *csocket)
|
||||
{
|
||||
struct p9_trans_fd *p;
|
||||
int ret, fd;
|
||||
struct file *file;
|
||||
int ret;
|
||||
|
||||
p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
csocket->sk->sk_allocation = GFP_NOIO;
|
||||
fd = sock_map_fd(csocket, 0);
|
||||
if (fd < 0) {
|
||||
file = sock_alloc_file(csocket, 0);
|
||||
if (IS_ERR(file)) {
|
||||
pr_err("%s (%d): failed to map fd\n",
|
||||
__func__, task_pid_nr(current));
|
||||
sock_release(csocket);
|
||||
kfree(p);
|
||||
return fd;
|
||||
return PTR_ERR(file);
|
||||
}
|
||||
|
||||
get_file(csocket->file);
|
||||
get_file(csocket->file);
|
||||
p->wr = p->rd = csocket->file;
|
||||
get_file(file);
|
||||
p->wr = p->rd = file;
|
||||
client->trans = p;
|
||||
client->status = Connected;
|
||||
|
||||
sys_close(fd); /* still racy */
|
||||
|
||||
p->rd->f_flags |= O_NONBLOCK;
|
||||
|
||||
p->conn = p9_conn_create(client);
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
#include <net/icmp.h>
|
||||
|
@ -4276,6 +4277,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
|
|||
{
|
||||
sctp_peeloff_arg_t peeloff;
|
||||
struct socket *newsock;
|
||||
struct file *newfile;
|
||||
int retval = 0;
|
||||
|
||||
if (len < sizeof(sctp_peeloff_arg_t))
|
||||
|
@ -4289,22 +4291,35 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
|
|||
goto out;
|
||||
|
||||
/* Map the socket to an unused fd that can be returned to the user. */
|
||||
retval = sock_map_fd(newsock, 0);
|
||||
retval = get_unused_fd();
|
||||
if (retval < 0) {
|
||||
sock_release(newsock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
newfile = sock_alloc_file(newsock, 0);
|
||||
if (unlikely(IS_ERR(newfile))) {
|
||||
put_unused_fd(retval);
|
||||
sock_release(newsock);
|
||||
return PTR_ERR(newfile);
|
||||
}
|
||||
|
||||
SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",
|
||||
__func__, sk, newsock->sk, retval);
|
||||
|
||||
/* Return the fd mapped to the new socket. */
|
||||
peeloff.sd = retval;
|
||||
if (put_user(len, optlen))
|
||||
if (put_user(len, optlen)) {
|
||||
fput(newfile);
|
||||
put_unused_fd(retval);
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval, &peeloff, len))
|
||||
retval = -EFAULT;
|
||||
|
||||
}
|
||||
peeloff.sd = retval;
|
||||
if (copy_to_user(optval, &peeloff, len)) {
|
||||
fput(newfile);
|
||||
put_unused_fd(retval);
|
||||
return -EFAULT;
|
||||
}
|
||||
fd_install(retval, newfile);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -346,7 +346,7 @@ static struct file_system_type sock_fs_type = {
|
|||
* but we take care of internal coherence yet.
|
||||
*/
|
||||
|
||||
static struct file *sock_alloc_file(struct socket *sock, int flags)
|
||||
struct file *sock_alloc_file(struct socket *sock, int flags)
|
||||
{
|
||||
struct qstr name = { .name = "" };
|
||||
struct path path;
|
||||
|
@ -375,8 +375,9 @@ static struct file *sock_alloc_file(struct socket *sock, int flags)
|
|||
file->private_data = sock;
|
||||
return file;
|
||||
}
|
||||
EXPORT_SYMBOL(sock_alloc_file);
|
||||
|
||||
int sock_map_fd(struct socket *sock, int flags)
|
||||
static int sock_map_fd(struct socket *sock, int flags)
|
||||
{
|
||||
struct file *newfile;
|
||||
int fd = get_unused_fd_flags(flags);
|
||||
|
@ -392,7 +393,6 @@ int sock_map_fd(struct socket *sock, int flags)
|
|||
put_unused_fd(fd);
|
||||
return PTR_ERR(newfile);
|
||||
}
|
||||
EXPORT_SYMBOL(sock_map_fd);
|
||||
|
||||
struct socket *sock_from_file(struct file *file, int *err)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue