Bug 104601
Summary: | Description of getname-related syscalls wrong | ||
---|---|---|---|
Product: | Documentation | Reporter: | mattator |
Component: | man-pages | Assignee: | documentation_man-pages (documentation_man-pages) |
Status: | RESOLVED INVALID | ||
Severity: | high | CC: | mtk.manpages |
Priority: | P1 | ||
Hardware: | All | ||
OS: | Linux | ||
Kernel Version: | Subsystem: | ||
Regression: | No | Bisected commit-id: |
Description
mattator
2015-09-15 15:28:35 UTC
In my tests, getsockname *does* do truncation if the length argument is smaller than the address size. Please post a *minimal* working example that demonstrates otherwise. My example is below. Here are two sample runs: $ ./a.out returned len = 16 0: <0x2> 1: <0x0> 2: <0x15> 3: <0xb3> 4: <0x0> 5: <0x0> 6: <0x0> 7: <0x0> 8: <0x0> 9: <0x0> 10: <0x0> 11: <0x0> 12: <0x0> 13: <0x0> 14: <0x0> 15: <0x0> 16: <0xff> 17: <0xff> 18: <0xff> 19: <0xff> $ ./a.out 8 returned len = 16 0: <0x2> 1: <0x0> 2: <0x15> 3: <0xb3> 4: <0x0> 5: <0x0> 6: <0x0> 7: <0x0> 8: <0xff> 9: <0xff> 10: <0xff> 11: <0xff> 12: <0xff> 13: <0xff> 14: <0xff> 15: <0xff> 16: <0xff> 17: <0xff> 18: <0xff> 19: <0xff> One can see that truncation has occurred in the second run, were a short length argument was supplied to getsockname(). #define _GNU_SOURCE #include <netdb.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) #define fatal(msg) do { fprintf(stderr, "%s\n", msg); \ exit(EXIT_FAILURE); } while (0) #define usageErr(msg, progName) \ do { fprintf(stderr, "Usage: "); \ fprintf(stderr, msg, progName); \ exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { int lfd, optval; struct addrinfo hints; struct addrinfo *result, *rp; /* Call getaddrinfo() to obtain a list of addresses that we can try binding to */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; /* Allows IPv4 or IPv6 */ hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wildcard IP address; service name is numeric */ if (getaddrinfo(NULL, "5555", &hints, &result) != 0) errExit("getaddrinfo"); /* Walk through returned list until we find an address structure that can be used to successfully create and bind a socket */ optval = 1; for (rp = result; rp != NULL; rp = rp->ai_next) { lfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (lfd == -1) continue; /* On error, try next address */ if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) errExit("setsockopt"); if (bind(lfd, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Success */ /* bind() failed: close this socket and try next address */ close(lfd); } if (rp == NULL) fatal("Could not bind socket to any address"); freeaddrinfo(result); struct sockaddr_storage saddr; socklen_t len; /* Preinitialize address structure with visually distinctive bytes */ memset(&saddr, 0xff, sizeof(saddr)); /* By default, we'll use the size of 'struct sockaddr' as the length argument for getsockname(). The user can override this by specifying a lengh value on the command line */ len = sizeof(saddr); if (argc > 1) len = atoi(argv[1]); if (getsockname(lfd, (struct sockaddr *) &saddr, &len) == -1) errExit("getsockname"); printf("returned len = %ld\n", (long) len); int j; unsigned char c; /* Inspect bytes in returned structure */ for (j = 0; j < 20; j++) { c = (((char *) &saddr) [j]); printf("%2d: <0x%x>\n", j, c); } } See also this code in net/socket.c static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, void __user *uaddr, int __user *ulen) { int err; int len; BUG_ON(klen > sizeof(struct sockaddr_storage)); err = get_user(len, ulen); if (err) return err; if (len > klen) len = klen; if (len < 0) return -EINVAL; if (len) { if (audit_sockaddr(klen, kaddr)) return -ENOMEM; if (copy_to_user(uaddr, kaddr, len)) return -EFAULT; } /* * "fromlen shall refer to the value before truncation.." * 1003.1g */ return __put_user(klen, ulen); } Closing as I believe this is not a bug. Please reopen if you can provide information to show otherwise. |