|
@@ -88,6 +88,7 @@
|
|
|
#include <linux/nsproxy.h>
|
|
|
#include <linux/magic.h>
|
|
|
#include <linux/slab.h>
|
|
|
+#include <linux/xattr.h>
|
|
|
|
|
|
#include <asm/uaccess.h>
|
|
|
#include <asm/unistd.h>
|
|
@@ -346,7 +347,8 @@ static struct file_system_type sock_fs_type = {
|
|
|
* but we take care of internal coherence yet.
|
|
|
*/
|
|
|
|
|
|
-static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
|
|
|
+static int sock_alloc_file(struct socket *sock, struct file **f, int flags,
|
|
|
+ const char *dname)
|
|
|
{
|
|
|
struct qstr name = { .name = "" };
|
|
|
struct path path;
|
|
@@ -357,6 +359,13 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
|
|
|
if (unlikely(fd < 0))
|
|
|
return fd;
|
|
|
|
|
|
+ if (dname) {
|
|
|
+ name.name = dname;
|
|
|
+ name.len = strlen(name.name);
|
|
|
+ } else if (sock->sk) {
|
|
|
+ name.name = sock->sk->sk_prot_creator->name;
|
|
|
+ name.len = strlen(name.name);
|
|
|
+ }
|
|
|
path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
|
|
|
if (unlikely(!path.dentry)) {
|
|
|
put_unused_fd(fd);
|
|
@@ -389,7 +398,7 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
|
|
|
int sock_map_fd(struct socket *sock, int flags)
|
|
|
{
|
|
|
struct file *newfile;
|
|
|
- int fd = sock_alloc_file(sock, &newfile, flags);
|
|
|
+ int fd = sock_alloc_file(sock, &newfile, flags, NULL);
|
|
|
|
|
|
if (likely(fd >= 0))
|
|
|
fd_install(fd, newfile);
|
|
@@ -455,6 +464,68 @@ static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
|
|
|
+#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
|
|
|
+#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
|
|
|
+static ssize_t sockfs_getxattr(struct dentry *dentry,
|
|
|
+ const char *name, void *value, size_t size)
|
|
|
+{
|
|
|
+ const char *proto_name;
|
|
|
+ size_t proto_size;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ error = -ENODATA;
|
|
|
+ if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) {
|
|
|
+ proto_name = dentry->d_name.name;
|
|
|
+ proto_size = strlen(proto_name);
|
|
|
+
|
|
|
+ if (value) {
|
|
|
+ error = -ERANGE;
|
|
|
+ if (proto_size + 1 > size)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ strncpy(value, proto_name, proto_size + 1);
|
|
|
+ }
|
|
|
+ error = proto_size + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
|
|
|
+ size_t size)
|
|
|
+{
|
|
|
+ ssize_t len;
|
|
|
+ ssize_t used = 0;
|
|
|
+
|
|
|
+ len = security_inode_listsecurity(dentry->d_inode, buffer, size);
|
|
|
+ if (len < 0)
|
|
|
+ return len;
|
|
|
+ used += len;
|
|
|
+ if (buffer) {
|
|
|
+ if (size < used)
|
|
|
+ return -ERANGE;
|
|
|
+ buffer += len;
|
|
|
+ }
|
|
|
+
|
|
|
+ len = (XATTR_NAME_SOCKPROTONAME_LEN + 1);
|
|
|
+ used += len;
|
|
|
+ if (buffer) {
|
|
|
+ if (size < used)
|
|
|
+ return -ERANGE;
|
|
|
+ memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len);
|
|
|
+ buffer += len;
|
|
|
+ }
|
|
|
+
|
|
|
+ return used;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct inode_operations sockfs_inode_ops = {
|
|
|
+ .getxattr = sockfs_getxattr,
|
|
|
+ .listxattr = sockfs_listxattr,
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* sock_alloc - allocate a socket
|
|
|
*
|
|
@@ -479,6 +550,7 @@ static struct socket *sock_alloc(void)
|
|
|
inode->i_mode = S_IFSOCK | S_IRWXUGO;
|
|
|
inode->i_uid = current_fsuid();
|
|
|
inode->i_gid = current_fsgid();
|
|
|
+ inode->i_op = &sockfs_inode_ops;
|
|
|
|
|
|
this_cpu_add(sockets_in_use, 1);
|
|
|
return sock;
|
|
@@ -1394,13 +1466,13 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
|
|
|
if (err < 0)
|
|
|
goto out_release_both;
|
|
|
|
|
|
- fd1 = sock_alloc_file(sock1, &newfile1, flags);
|
|
|
+ fd1 = sock_alloc_file(sock1, &newfile1, flags, NULL);
|
|
|
if (unlikely(fd1 < 0)) {
|
|
|
err = fd1;
|
|
|
goto out_release_both;
|
|
|
}
|
|
|
|
|
|
- fd2 = sock_alloc_file(sock2, &newfile2, flags);
|
|
|
+ fd2 = sock_alloc_file(sock2, &newfile2, flags, NULL);
|
|
|
if (unlikely(fd2 < 0)) {
|
|
|
err = fd2;
|
|
|
fput(newfile1);
|
|
@@ -1536,7 +1608,8 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
|
|
|
*/
|
|
|
__module_get(newsock->ops->owner);
|
|
|
|
|
|
- newfd = sock_alloc_file(newsock, &newfile, flags);
|
|
|
+ newfd = sock_alloc_file(newsock, &newfile, flags,
|
|
|
+ sock->sk->sk_prot_creator->name);
|
|
|
if (unlikely(newfd < 0)) {
|
|
|
err = newfd;
|
|
|
sock_release(newsock);
|