Commit 600e177920df936d03b807780ca92c662af98990

Authored by Masatake YAMATO
Committed by David S. Miller
1 parent cefd81cfec

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>

Showing 1 changed file with 78 additions and 5 deletions Side-by-side Diff

... ... @@ -88,6 +88,7 @@
88 88 #include <linux/nsproxy.h>
89 89 #include <linux/magic.h>
90 90 #include <linux/slab.h>
  91 +#include <linux/xattr.h>
91 92  
92 93 #include <asm/uaccess.h>
93 94 #include <asm/unistd.h>
... ... @@ -346,7 +347,8 @@
346 347 * but we take care of internal coherence yet.
347 348 */
348 349  
349   -static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
  350 +static int sock_alloc_file(struct socket *sock, struct file **f, int flags,
  351 + const char *dname)
350 352 {
351 353 struct qstr name = { .name = "" };
352 354 struct path path;
... ... @@ -357,6 +359,13 @@
357 359 if (unlikely(fd < 0))
358 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 369 path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
361 370 if (unlikely(!path.dentry)) {
362 371 put_unused_fd(fd);
... ... @@ -389,7 +398,7 @@
389 398 int sock_map_fd(struct socket *sock, int flags)
390 399 {
391 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 403 if (likely(fd >= 0))
395 404 fd_install(fd, newfile);
... ... @@ -455,6 +464,68 @@
455 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)
  470 +static 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 +
  492 +out:
  493 + return error;
  494 +}
  495 +
  496 +static 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 +
  524 +static const struct inode_operations sockfs_inode_ops = {
  525 + .getxattr = sockfs_getxattr,
  526 + .listxattr = sockfs_listxattr,
  527 +};
  528 +
458 529 /**
459 530 * sock_alloc - allocate a socket
460 531 *
... ... @@ -479,6 +550,7 @@
479 550 inode->i_mode = S_IFSOCK | S_IRWXUGO;
480 551 inode->i_uid = current_fsuid();
481 552 inode->i_gid = current_fsgid();
  553 + inode->i_op = &sockfs_inode_ops;
482 554  
483 555 this_cpu_add(sockets_in_use, 1);
484 556 return sock;
485 557  
... ... @@ -1394,13 +1466,13 @@
1394 1466 if (err < 0)
1395 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 1470 if (unlikely(fd1 < 0)) {
1399 1471 err = fd1;
1400 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 1476 if (unlikely(fd2 < 0)) {
1405 1477 err = fd2;
1406 1478 fput(newfile1);
... ... @@ -1536,7 +1608,8 @@
1536 1608 */
1537 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 1613 if (unlikely(newfd < 0)) {
1541 1614 err = newfd;
1542 1615 sock_release(newsock);