[RFC PATCH 0/5] net: socket bind to file descriptor introduced

STALE5112d

8 messages, 2 authors, 2012-08-15 · open the first message on its own page

[RFC PATCH 0/5] net: socket bind to file descriptor introduced

From: Stanislav Kinsbursky <hidden>
Date: 2012-08-15 16:24:48

This patch set introduces new socket operation and new system call:
sys_fbind(), which allows to bind socket to opened file.
File to bind to can be created by sys_mknod(S_IFSOCK) and opened by
open(O_PATH).

This system call is especially required for UNIX sockets, which has name
lenght limitation.

The following series implements...

---

Stanislav Kinsbursky (5):
      net: cleanup unix_bind() a little
      net: split unix_bind()
      net: new protocol operation fbind() introduced
      net: fbind() for unix sockets protocol operations introduced
      syscall: sys_fbind() introduced


 arch/x86/syscalls/syscall_32.tbl |    1 
 arch/x86/syscalls/syscall_64.tbl |    1 
 include/linux/net.h              |    2 +
 include/linux/syscalls.h         |    1 
 kernel/sys_ni.c                  |    3 +
 net/socket.c                     |   25 +++++++
 net/unix/af_unix.c               |  136 ++++++++++++++++++++++++++++++--------
 7 files changed, 140 insertions(+), 29 deletions(-)

[RFC PATCH 2/5] net: split unix_bind()

From: Stanislav Kinsbursky <hidden>
Date: 2012-08-15 16:24:49

This patch moves UNIX socket insert into separated function, because this code
will be used for unix_fbind() too.

Signed-off-by: Stanislav Kinsbursky <redacted>
---
 net/unix/af_unix.c |   52 +++++++++++++++++++++++++++++-----------------------
 1 files changed, 29 insertions(+), 23 deletions(-)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index bc90ddb..b26200d 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -814,11 +814,38 @@ fail:
 	return NULL;
 }
 
+static int __unix_add_sock(struct path *path, struct sock *sk,
+			 struct unix_address *addr, int hash)
+{
+	struct net *net = sock_net(sk);
+	struct unix_sock *u = unix_sk(sk);
+	struct sockaddr_un *sunaddr = addr->name;
+	char *sun_path = sunaddr->sun_path;
+	struct hlist_head *list;
+
+	if (!sun_path[0]) {
+		if (__unix_find_socket_byname(net, sunaddr, addr->len,
+					      sk->sk_type, hash)) {
+			unix_release_addr(addr);
+			return -EADDRINUSE;
+		}
+
+		list = &unix_socket_table[addr->hash];
+	} else {
+		list = &unix_socket_table[path->dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
+		u->path = *path;
+	}
+
+	__unix_remove_socket(sk);
+	u->addr = addr;
+	__unix_insert_socket(list, sk);
+	return 0;
+
+}
 
 static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sock *sk = sock->sk;
-	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk);
 	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
 	char *sun_path = sunaddr->sun_path;
@@ -827,7 +854,6 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	int err;
 	unsigned int hash;
 	struct unix_address *addr;
-	struct hlist_head *list;
 
 	err = -EINVAL;
 	if (sunaddr->sun_family != AF_UNIX)
@@ -893,27 +919,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	}
 
 	spin_lock(&unix_table_lock);
-
-	err = -EADDRINUSE;
-	if (!sun_path[0]) {
-		if (__unix_find_socket_byname(net, sunaddr, addr->len,
-					      sk->sk_type, hash)) {
-			unix_release_addr(addr);
-			goto out_unlock;
-		}
-
-		list = &unix_socket_table[addr->hash];
-	} else {
-		list = &unix_socket_table[path.dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
-		u->path = path;
-	}
-
-	err = 0;
-	__unix_remove_socket(sk);
-	u->addr = addr;
-	__unix_insert_socket(list, sk);
-
-out_unlock:
+	err = __unix_add_sock(&path, sk, addr, hash);
 	spin_unlock(&unix_table_lock);
 out_up:
 	mutex_unlock(&u->readlock);

[RFC PATCH 1/5] net: cleanup unix_bind() a little

From: Stanislav Kinsbursky <hidden>
Date: 2012-08-15 16:24:50

This will simplify further changes for unix_fbind().
---
 net/unix/af_unix.c |   12 +++++-------
 1 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 641f2e4..bc90ddb 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -880,10 +880,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 		if (err)
 			goto out_mknod_dput;
 		err = security_path_mknod(&path, dentry, mode, 0);
-		if (err)
-			goto out_mknod_drop_write;
-		err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
-out_mknod_drop_write:
+		if (!err)
+			err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
 		mnt_drop_write(path.mnt);
 		if (err)
 			goto out_mknod_dput;
@@ -896,9 +894,9 @@ out_mknod_drop_write:
 
 	spin_lock(&unix_table_lock);
 
+	err = -EADDRINUSE;
 	if (!sun_path[0]) {
-		err = -EADDRINUSE;
-		if (__unix_find_socket_byname(net, sunaddr, addr_len,
+		if (__unix_find_socket_byname(net, sunaddr, addr->len,
 					      sk->sk_type, hash)) {
 			unix_release_addr(addr);
 			goto out_unlock;
@@ -906,7 +904,7 @@ out_mknod_drop_write:
 
 		list = &unix_socket_table[addr->hash];
 	} else {
-		list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
+		list = &unix_socket_table[path.dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
 		u->path = path;
 	}
 

[RFC PATCH 3/5] net: new protocol operation fbind() introduced

From: Stanislav Kinsbursky <hidden>
Date: 2012-08-15 16:24:53

This operation is used to bind socket to specified file.

Signed-off-by: Stanislav Kinsbursky <redacted>
---
 include/linux/net.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/linux/net.h b/include/linux/net.h
index e9ac2df..843cb75 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -157,6 +157,7 @@ struct kiocb;
 struct sockaddr;
 struct msghdr;
 struct module;
+struct path;
 
 struct proto_ops {
 	int		family;
@@ -165,6 +166,7 @@ struct proto_ops {
 	int		(*bind)	     (struct socket *sock,
 				      struct sockaddr *myaddr,
 				      int sockaddr_len);
+	int		(*fbind)     (struct file *file, struct socket *sock);
 	int		(*connect)   (struct socket *sock,
 				      struct sockaddr *vaddr,
 				      int sockaddr_len, int flags);

[RFC PATCH 4/5] net: fbind() for unix sockets protocol operations introduced

From: Stanislav Kinsbursky <hidden>
Date: 2012-08-15 16:24:57

Path for unix_address is taken from passed file.
File inode have to be socket.
Since no sunaddr is present, addr->name is constructed at the place. It
obviously means, then path name can be truncated is it's longer then
UNIX_MAX_PATH.

Signed-off-by: Stanislav Kinsbursky <redacted>
---
 net/unix/af_unix.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 76 insertions(+), 2 deletions(-)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index b26200d..2f34c9d 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -286,12 +286,11 @@ static inline struct sock *unix_find_socket_byname(struct net *net,
 	return s;
 }
 
-static struct sock *unix_find_socket_byinode(struct inode *i)
+static struct sock *__unix_find_socket_byinode(struct inode *i)
 {
 	struct sock *s;
 	struct hlist_node *node;
 
-	spin_lock(&unix_table_lock);
 	sk_for_each(s, node,
 		    &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
 		struct dentry *dentry = unix_sk(s)->path.dentry;
@@ -303,6 +302,15 @@ static struct sock *unix_find_socket_byinode(struct inode *i)
 	}
 	s = NULL;
 found:
+	return s;
+}
+
+static struct sock *unix_find_socket_byinode(struct inode *i)
+{
+	struct sock *s;
+
+	spin_lock(&unix_table_lock);
+	s = __unix_find_socket_byinode(i);
 	spin_unlock(&unix_table_lock);
 	return s;
 }
@@ -502,6 +510,7 @@ out:
 
 static int unix_release(struct socket *);
 static int unix_bind(struct socket *, struct sockaddr *, int);
+static int unix_fbind(struct file *file, struct socket *sock);
 static int unix_stream_connect(struct socket *, struct sockaddr *,
 			       int addr_len, int flags);
 static int unix_socketpair(struct socket *, struct socket *);
@@ -542,6 +551,7 @@ static const struct proto_ops unix_stream_ops = {
 	.owner =	THIS_MODULE,
 	.release =	unix_release,
 	.bind =		unix_bind,
+	.fbind =	unix_fbind,
 	.connect =	unix_stream_connect,
 	.socketpair =	unix_socketpair,
 	.accept =	unix_accept,
@@ -564,6 +574,7 @@ static const struct proto_ops unix_dgram_ops = {
 	.owner =	THIS_MODULE,
 	.release =	unix_release,
 	.bind =		unix_bind,
+	.fbind =	unix_fbind,
 	.connect =	unix_dgram_connect,
 	.socketpair =	unix_socketpair,
 	.accept =	sock_no_accept,
@@ -586,6 +597,7 @@ static const struct proto_ops unix_seqpacket_ops = {
 	.owner =	THIS_MODULE,
 	.release =	unix_release,
 	.bind =		unix_bind,
+	.fbind =	unix_fbind,
 	.connect =	unix_stream_connect,
 	.socketpair =	unix_socketpair,
 	.accept =	unix_accept,
@@ -843,6 +855,68 @@ static int __unix_add_sock(struct path *path, struct sock *sk,
 
 }
 
+static int unix_fbind(struct file *f, struct socket *sock)
+{
+	struct sock *sk = sock->sk, *tmp;
+	struct unix_sock *u = unix_sk(sk);
+	struct unix_address *addr;
+	struct path *path = &f->f_path;
+	struct inode *inode = path->dentry->d_inode;
+	char *buf, *name;
+	int err;
+
+	err = -ENOTSOCK;
+	if (!S_ISSOCK(inode->i_mode))
+		goto out;
+
+	mutex_lock(&u->readlock);
+
+	err = -EINVAL;
+	if (u->addr)
+		goto out_up;
+
+	err = -ENOMEM;
+	buf = (char*)__get_free_page(GFP_KERNEL);
+	if (!buf)
+		goto out_up;
+
+	err = -EFAULT;
+	name = d_path(path, buf, PAGE_SIZE);
+	if (IS_ERR(name))
+		goto out_up_page;
+
+	addr = kmalloc(sizeof(*addr) + sizeof(struct sockaddr_un), GFP_KERNEL);
+	if (!addr)
+		goto out_up_page;
+
+	addr->name->sun_family = AF_UNIX;
+	addr->len = min(strlen(name), (size_t)UNIX_PATH_MAX);
+	memcpy(addr->name->sun_path, name, addr->len);
+	atomic_set(&addr->refcnt, 1);
+
+	spin_lock(&unix_table_lock);
+
+	err = -EADDRINUSE;
+	tmp = __unix_find_socket_byinode(inode);
+	if (tmp) {
+		sock_put(tmp);
+		unix_release_addr(addr);
+		goto out_unlock;
+	}
+
+	err = __unix_add_sock(path, sk, addr, 0);
+	path_get(path);
+
+out_unlock:
+	spin_unlock(&unix_table_lock);
+out_up_page:
+	free_page((unsigned long)buf);
+out_up:
+	mutex_unlock(&u->readlock);
+out:
+	return err;
+}
+
 static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sock *sk = sock->sk;

[RFC PATCH 5/5] syscall: sys_fbind() introduced

From: Stanislav Kinsbursky <hidden>
Date: 2012-08-15 16:25:08

This syscall allows to bind socket to specified file descriptor.
Descriptor can be gained by simple open with O_PATH flag.
Socket node can be created by sys_mknod().

Signed-off-by: Stanislav Kinsbursky <redacted>
---
 arch/x86/syscalls/syscall_32.tbl |    1 +
 arch/x86/syscalls/syscall_64.tbl |    1 +
 include/linux/syscalls.h         |    1 +
 kernel/sys_ni.c                  |    3 +++
 net/socket.c                     |   25 +++++++++++++++++++++++++
 5 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 7a35a6e..9594b82 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -356,3 +356,4 @@
 347	i386	process_vm_readv	sys_process_vm_readv		compat_sys_process_vm_readv
 348	i386	process_vm_writev	sys_process_vm_writev		compat_sys_process_vm_writev
 349	i386	kcmp			sys_kcmp
+350	i386	fbind			sys_fbind
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index 51171ae..f964df8 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -319,6 +319,7 @@
 310	64	process_vm_readv	sys_process_vm_readv
 311	64	process_vm_writev	sys_process_vm_writev
 312	64	kcmp			sys_kcmp
+313	common	fbind			sys_fbind
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 19439c7..9e78fa4 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -602,6 +602,7 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname,
 asmlinkage long sys_getsockopt(int fd, int level, int optname,
 				char __user *optval, int __user *optlen);
 asmlinkage long sys_bind(int, struct sockaddr __user *, int);
+asmlinkage long sys_fbind(int, int);
 asmlinkage long sys_connect(int, struct sockaddr __user *, int);
 asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *);
 asmlinkage long sys_accept4(int, struct sockaddr __user *, int __user *, int);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index dbff751..30c393a 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -206,3 +206,6 @@ cond_syscall(compat_sys_open_by_handle_at);
 
 /* compare kernel pointers */
 cond_syscall(sys_kcmp);
+
+cond_syscall(sys_fbind);
+
diff --git a/net/socket.c b/net/socket.c
index 6e0ccc0..67d9795 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1432,6 +1432,31 @@ out:
 	return err;
 }
 
+SYSCALL_DEFINE2(fbind, int, fd, int, sk_fd)
+{
+	struct socket *sock;
+	int err, fput_sk, fput_fd;
+	struct file *file;
+
+	sock = sockfd_lookup_light(sk_fd, &err, &fput_sk);
+	if (!sock)
+		return err;
+
+	err = -EBADF;
+	file = fget_raw_light(fd, &fput_fd);
+	if (!file)
+		goto out_put_sk;
+
+	err = -EINVAL;
+	if (sock->ops->fbind)
+		err = sock->ops->fbind(file, sock);
+
+	fput_light(file, fput_fd);
+out_put_sk:
+	fput_light(sock->file, fput_sk);
+	return err;
+}
+
 /*
  *	Bind a name to a socket. Nothing much to do here since it's
  *	the protocol's responsibility to handle the local address.

Re: [RFC PATCH 5/5] syscall: sys_fbind() introduced

From: "H. Peter Anvin" <hpa@zytor.com>
Date: 2012-08-15 16:31:05

On 08/15/2012 09:22 AM, Stanislav Kinsbursky wrote:
quoted hunk
This syscall allows to bind socket to specified file descriptor.
Descriptor can be gained by simple open with O_PATH flag.
Socket node can be created by sys_mknod().

Signed-off-by: Stanislav Kinsbursky <redacted>
---
  arch/x86/syscalls/syscall_32.tbl |    1 +
  arch/x86/syscalls/syscall_64.tbl |    1 +
  include/linux/syscalls.h         |    1 +
  kernel/sys_ni.c                  |    3 +++
  net/socket.c                     |   25 +++++++++++++++++++++++++
  5 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 7a35a6e..9594b82 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -356,3 +356,4 @@
  347	i386	process_vm_readv	sys_process_vm_readv		compat_sys_process_vm_readv
  348	i386	process_vm_writev	sys_process_vm_writev		compat_sys_process_vm_writev
  349	i386	kcmp			sys_kcmp
+350	i386	fbind			sys_fbind
i386 uses socketcalls... perhaps it shouldn't (socketcalls are pretty 
much an abomination), but for socketcall-based architectures this really 
should be a socketcall.

Don't you also need fconnect()?  Or is that simply handled by allowing 
open() without O_PATH?

	-hpa

-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.

Re: [RFC PATCH 5/5] syscall: sys_fbind() introduced

From: Stanislav Kinsbursky <hidden>
Date: 2012-08-15 16:44:33

15.08.2012 20:30, H. Peter Anvin пишет:
On 08/15/2012 09:22 AM, Stanislav Kinsbursky wrote:
quoted
This syscall allows to bind socket to specified file descriptor.
Descriptor can be gained by simple open with O_PATH flag.
Socket node can be created by sys_mknod().

Signed-off-by: Stanislav Kinsbursky <redacted>
---
   arch/x86/syscalls/syscall_32.tbl |    1 +
   arch/x86/syscalls/syscall_64.tbl |    1 +
   include/linux/syscalls.h         |    1 +
   kernel/sys_ni.c                  |    3 +++
   net/socket.c                     |   25 +++++++++++++++++++++++++
   5 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 7a35a6e..9594b82 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -356,3 +356,4 @@
   347	i386	process_vm_readv	sys_process_vm_readv		compat_sys_process_vm_readv
   348	i386	process_vm_writev	sys_process_vm_writev		compat_sys_process_vm_writev
   349	i386	kcmp			sys_kcmp
+350	i386	fbind			sys_fbind
i386 uses socketcalls... perhaps it shouldn't (socketcalls are pretty
much an abomination), but for socketcall-based architectures this really
should be a socketcall.
Thanks, Peter. I'll rework this.
Don't you also need fconnect()?  Or is that simply handled by allowing
open() without O_PATH?
Yes, I need it.
If this approach will be accepted, then I'll send one more patch set for fconnect.
	-hpa

-- 
Best regards,
Stanislav Kinsbursky
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help