aboutsummaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
authorMasatake YAMATO <yamato@redhat.com>2012-08-29 06:44:29 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-04 15:52:13 -0400
commit600e177920df936d03b807780ca92c662af98990 (patch)
tree76c4cb39ce71d2e0b63074e1170c60792fb7913c /net/socket.c
parentcefd81cfeca14ec4c63cc748441634f1d4c0eb3f (diff)
net: Providing protocol type via system.sockprotoname xattr of /proc/PID/fd entries
lsof reports some of socket descriptors as "can't identify protocol" like: [yamato@localhost]/tmp% sudo lsof | grep dbus | grep iden dbus-daem 652 dbus 6u sock ... 17812 can't identify protocol dbus-daem 652 dbus 34u sock ... 24689 can't identify protocol dbus-daem 652 dbus 42u sock ... 24739 can't identify protocol dbus-daem 652 dbus 48u sock ... 22329 can't identify protocol ... lsof cannot resolve the protocol used in a socket because procfs doesn't provide the map between inode number on sockfs and protocol type of the socket. For improving the situation this patch adds an extended attribute named 'system.sockprotoname' in which the protocol name for /proc/PID/fd/SOCKET is stored. So lsof can know the protocol for a given /proc/PID/fd/SOCKET with getxattr system call. A few weeks ago I submitted a patch for the same purpose. The patch was introduced /proc/net/sockfs which enumerates inodes and protocols of all sockets alive on a system. However, it was rejected because (1) a global lock was needed, and (2) the layout of struct socket was changed with the patch. This patch doesn't use any global lock; and doesn't change the layout of any structs. In this patch, a protocol name is stored to dentry->d_name of sockfs when new socket is associated with a file descriptor. Before this patch dentry->d_name was not used; it was just filled with empty string. lsof may use an extended attribute named 'system.sockprotoname' to retrieve the value of dentry->d_name. It is nice if we can see the protocol name with ls -l /proc/PID/fd. However, "socket:[#INODE]", the name format returned from sockfs_dname() was already defined. To keep the compatibility between kernel and user land, the extended attribute is used to prepare the value of dentry->d_name. Signed-off-by: Masatake YAMATO <yamato@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c83
1 files changed, 78 insertions, 5 deletions
diff --git a/net/socket.c b/net/socket.c
index a5471f804d99..977c0f48c8d6 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -88,6 +88,7 @@
88#include <linux/nsproxy.h> 88#include <linux/nsproxy.h>
89#include <linux/magic.h> 89#include <linux/magic.h>
90#include <linux/slab.h> 90#include <linux/slab.h>
91#include <linux/xattr.h>
91 92
92#include <asm/uaccess.h> 93#include <asm/uaccess.h>
93#include <asm/unistd.h> 94#include <asm/unistd.h>
@@ -346,7 +347,8 @@ static struct file_system_type sock_fs_type = {
346 * but we take care of internal coherence yet. 347 * but we take care of internal coherence yet.
347 */ 348 */
348 349
349static int sock_alloc_file(struct socket *sock, struct file **f, int flags) 350static int sock_alloc_file(struct socket *sock, struct file **f, int flags,
351 const char *dname)
350{ 352{
351 struct qstr name = { .name = "" }; 353 struct qstr name = { .name = "" };
352 struct path path; 354 struct path path;
@@ -357,6 +359,13 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
357 if (unlikely(fd < 0)) 359 if (unlikely(fd < 0))
358 return fd; 360 return fd;
359 361
362 if (dname) {
363 name.name = dname;
364 name.len = strlen(name.name);
365 } else if (sock->sk) {
366 name.name = sock->sk->sk_prot_creator->name;
367 name.len = strlen(name.name);
368 }
360 path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); 369 path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
361 if (unlikely(!path.dentry)) { 370 if (unlikely(!path.dentry)) {
362 put_unused_fd(fd); 371 put_unused_fd(fd);
@@ -389,7 +398,7 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
389int sock_map_fd(struct socket *sock, int flags) 398int sock_map_fd(struct socket *sock, int flags)
390{ 399{
391 struct file *newfile; 400 struct file *newfile;
392 int fd = sock_alloc_file(sock, &newfile, flags); 401 int fd = sock_alloc_file(sock, &newfile, flags, NULL);
393 402
394 if (likely(fd >= 0)) 403 if (likely(fd >= 0))
395 fd_install(fd, newfile); 404 fd_install(fd, newfile);
@@ -455,6 +464,68 @@ static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
455 return NULL; 464 return NULL;
456} 465}
457 466
467#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
468#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
469#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
470static ssize_t sockfs_getxattr(struct dentry *dentry,
471 const char *name, void *value, size_t size)
472{
473 const char *proto_name;
474 size_t proto_size;
475 int error;
476
477 error = -ENODATA;
478 if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) {
479 proto_name = dentry->d_name.name;
480 proto_size = strlen(proto_name);
481
482 if (value) {
483 error = -ERANGE;
484 if (proto_size + 1 > size)
485 goto out;
486
487 strncpy(value, proto_name, proto_size + 1);
488 }
489 error = proto_size + 1;
490 }
491
492out:
493 return error;
494}
495
496static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
497 size_t size)
498{
499 ssize_t len;
500 ssize_t used = 0;
501
502 len = security_inode_listsecurity(dentry->d_inode, buffer, size);
503 if (len < 0)
504 return len;
505 used += len;
506 if (buffer) {
507 if (size < used)
508 return -ERANGE;
509 buffer += len;
510 }
511
512 len = (XATTR_NAME_SOCKPROTONAME_LEN + 1);
513 used += len;
514 if (buffer) {
515 if (size < used)
516 return -ERANGE;
517 memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len);
518 buffer += len;
519 }
520
521 return used;
522}
523
524static const struct inode_operations sockfs_inode_ops = {
525 .getxattr = sockfs_getxattr,
526 .listxattr = sockfs_listxattr,
527};
528
458/** 529/**
459 * sock_alloc - allocate a socket 530 * sock_alloc - allocate a socket
460 * 531 *
@@ -479,6 +550,7 @@ static struct socket *sock_alloc(void)
479 inode->i_mode = S_IFSOCK | S_IRWXUGO; 550 inode->i_mode = S_IFSOCK | S_IRWXUGO;
480 inode->i_uid = current_fsuid(); 551 inode->i_uid = current_fsuid();
481 inode->i_gid = current_fsgid(); 552 inode->i_gid = current_fsgid();
553 inode->i_op = &sockfs_inode_ops;
482 554
483 this_cpu_add(sockets_in_use, 1); 555 this_cpu_add(sockets_in_use, 1);
484 return sock; 556 return sock;
@@ -1394,13 +1466,13 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
1394 if (err < 0) 1466 if (err < 0)
1395 goto out_release_both; 1467 goto out_release_both;
1396 1468
1397 fd1 = sock_alloc_file(sock1, &newfile1, flags); 1469 fd1 = sock_alloc_file(sock1, &newfile1, flags, NULL);
1398 if (unlikely(fd1 < 0)) { 1470 if (unlikely(fd1 < 0)) {
1399 err = fd1; 1471 err = fd1;
1400 goto out_release_both; 1472 goto out_release_both;
1401 } 1473 }
1402 1474
1403 fd2 = sock_alloc_file(sock2, &newfile2, flags); 1475 fd2 = sock_alloc_file(sock2, &newfile2, flags, NULL);
1404 if (unlikely(fd2 < 0)) { 1476 if (unlikely(fd2 < 0)) {
1405 err = fd2; 1477 err = fd2;
1406 fput(newfile1); 1478 fput(newfile1);
@@ -1536,7 +1608,8 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
1536 */ 1608 */
1537 __module_get(newsock->ops->owner); 1609 __module_get(newsock->ops->owner);
1538 1610
1539 newfd = sock_alloc_file(newsock, &newfile, flags); 1611 newfd = sock_alloc_file(newsock, &newfile, flags,
1612 sock->sk->sk_prot_creator->name);
1540 if (unlikely(newfd < 0)) { 1613 if (unlikely(newfd < 0)) {
1541 err = newfd; 1614 err = newfd;
1542 sock_release(newsock); 1615 sock_release(newsock);