diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/socket.c | 83 |
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 | ||
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 | 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) | |||
389 | int sock_map_fd(struct socket *sock, int flags) | 398 | int 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) | ||
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 | * 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); |