diff options
-rw-r--r-- | net/unix/af_unix.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index bbacf4c60fe3..78585217f61a 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -289,17 +289,29 @@ static int unix_validate_addr(struct sockaddr_un *sunaddr, int addr_len) return 0; } -static void unix_mkname_bsd(struct sockaddr_un *sunaddr, int addr_len) +static int unix_mkname_bsd(struct sockaddr_un *sunaddr, int addr_len) { + struct sockaddr_storage *addr = (struct sockaddr_storage *)sunaddr; + short offset = offsetof(struct sockaddr_storage, __data); + + BUILD_BUG_ON(offset != offsetof(struct sockaddr_un, sun_path)); + /* This may look like an off by one error but it is a bit more * subtle. 108 is the longest valid AF_UNIX path for a binding. * sun_path[108] doesn't as such exist. However in kernel space * we are guaranteed that it is a valid memory location in our * kernel address buffer because syscall functions always pass * a pointer of struct sockaddr_storage which has a bigger buffer - * than 108. + * than 108. Also, we must terminate sun_path for strlen() in + * getname_kernel(). + */ + addr->__data[addr_len - offset] = 0; + + /* Don't pass sunaddr->sun_path to strlen(). Otherwise, 108 will + * cause panic if CONFIG_FORTIFY_SOURCE=y. Let __fortify_strlen() + * know the actual buffer. */ - ((char *)sunaddr)[addr_len] = 0; + return strlen(addr->__data) + offset + 1; } static void __unix_remove_socket(struct sock *sk) @@ -1208,8 +1220,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr, struct path parent; int err; - addr_len = strnlen(sunaddr->sun_path, sizeof(sunaddr->sun_path)) - + offsetof(struct sockaddr_un, sun_path) + 1; + addr_len = unix_mkname_bsd(sunaddr, addr_len); addr = unix_create_addr(sunaddr, addr_len); if (!addr) return -ENOMEM; |