summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2011-12-16 02:10:37 +0000
committerJo-Philipp Wich <jow@openwrt.org>2011-12-16 02:10:37 +0000
commitca7bc48ebc0b1f655088eaae89bd358556dc8824 (patch)
treecad031002a5c06e2372a9e920c3aa6baff3210a2
parent5c1ef9a0a60240a949be9ce1839c049471d7c5a1 (diff)
[PATCH] Abstract address UNIX sockets not binding properly (by capnbry@gmail.com, #366)
In #274, I stated abstract namespace and autobound abstract namespace datagram UNIX domain sockets work perfectly with nixio. However, I may have jumped the gun on that conclusion. Turns out they work perfectly for only one concurrent connection. The problem is that when binding to an abstract address socket, which begins with a NULL byte, nixio strncpy's the name into the sockaddr_un structure, which effectively copies nothing. It then binds to an address of 180 NULLs, which is completely legal, but obviously you run into problems when a second client tries to bind to the same address. The rules are as follows ( http://linux.die.net/man/7/unix) for the names: * If the name is blank, bind() should pass that the addrlen of sizeof(sa_family_t) and Linux will autobind a name that begins with null and is followed by 5 digits. * If the first character of the name is non-null, the name is a pathname and is null-terminated. addrlen should be sizeof(sockaddr_un), but the length can also be the pathname len + sizeof(sa_family_t) as the value will be null-terminated by the kernel unix socket driver * If the first character is null, the address is abstract and the value should not be null-terminated and addrlen is pathname + sizeof(sa_family_t) The attached patch fixes bind/connect/sendto by shortening the addrlen passed to be pathname len + sizeof(sa_family_t), which generates the correct socket names for all 3 cases above. It also fixes the address returned by recvfrom, which currently returns a blank string for any abstract address socket (as they begin with a null).
-rw-r--r--libs/nixio/src/bind.c10
-rw-r--r--libs/nixio/src/io.c12
2 files changed, 13 insertions, 9 deletions
diff --git a/libs/nixio/src/bind.c b/libs/nixio/src/bind.c
index 711205955..68e1df8a8 100644
--- a/libs/nixio/src/bind.c
+++ b/libs/nixio/src/bind.c
@@ -193,15 +193,15 @@ static int nixio_sock__bind_connect(lua_State *L, int do_bind) {
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
- luaL_argcheck(L, pathlen < sizeof(addr.sun_path), 2, "out of range");
- strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+ luaL_argcheck(L, pathlen <= sizeof(addr.sun_path), 2, "out of range");
+ memcpy(addr.sun_path, path, pathlen);
+ socklen_t alen = sizeof(sa_family_t) + pathlen;
if (do_bind) {
- status = bind(sock->fd, (struct sockaddr*)&addr, sizeof(addr));
+ status = bind(sock->fd, (struct sockaddr*)&addr, alen);
} else {
do {
- status = connect(sock->fd, (struct sockaddr*)&addr,
- sizeof(addr));
+ status = connect(sock->fd, (struct sockaddr*)&addr, alen);
} while (status == -1 && errno == EINTR);
}
#endif
diff --git a/libs/nixio/src/io.c b/libs/nixio/src/io.c
index 1d8f4484c..12d5c7df4 100644
--- a/libs/nixio/src/io.c
+++ b/libs/nixio/src/io.c
@@ -61,11 +61,11 @@ static int nixio_sock__sendto(lua_State *L, int to) {
const char *path = luaL_checklstring(L, 3, &pathlen);
addr_un.sun_family = AF_UNIX;
- luaL_argcheck(L, pathlen < sizeof(addr_un.sun_path), 3, "out of range");
- strncpy(addr_un.sun_path, path, sizeof(addr_un.sun_path));
+ luaL_argcheck(L, pathlen <= sizeof(addr_un.sun_path), 3, "out of range");
+ memcpy(addr_un.sun_path, path, pathlen);
addr = (struct sockaddr*)&addr_un;
- alen = sizeof(addr_un);
+ alen = sizeof(sa_family_t) + pathlen;
}
#endif
}
@@ -180,7 +180,11 @@ static int nixio_sock__recvfrom(lua_State *L, int from) {
}
#ifndef __WINNT__
else if (sock->domain == AF_UNIX && alen > sizeof(sa_family_t)) {
- lua_pushstring(L, addr_un.sun_path);
+ /* if first char is non-null then the path is not in the
+ abstract namespace and alen includes the trailing null */
+ if (addr_un.sun_path[0])
+ --alen;
+ lua_pushlstring(L, addr_un.sun_path, alen - sizeof(sa_family_t));
return 2;
}
#endif