For instance, if I look at the getsockname man page on ubuntu 15.04: === getsockname() returns the current address to which the socket sockfd is bound, in the buffer pointed to by addr. The addrlen argument should be initialized to indicate the amount of space (in bytes) pointed to by addr. On return it contains the actual size of the socket address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call. === I've looked at some getname function for different protocols in the 4.3 and 3.14 kernels and the addrlen parameter was never considered as an input or the returned sockaddr* truncated. This was the cause of a stack smashing in a userspace application I use and possibly many others so I ranked it high. More details here: http://stackoverflow.com/questions/32522031/mismatch-between-manpage-and-kernel-behavior-about-getsockname
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.