From: Lennart Poettering Date: Mon, 15 Oct 2018 16:02:30 +0000 (+0200) Subject: socket-util: add sockaddr_un_set_path() helper X-Git-Tag: v240~538^2~10 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5cf91ea9c858fca03983c96932c886497953603e;p=thirdparty%2Fsystemd.git socket-util: add sockaddr_un_set_path() helper Properly initializing sun_path from foreign data is not easy, given the size constraints, and NUL confusion. Let's add a helper function for this. --- diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index aa636ffd61e..6b3c6592a52 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1262,3 +1262,47 @@ int sockaddr_un_unlink(const struct sockaddr_un *sa) { return 1; } + +int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { + size_t l; + + assert(ret); + assert(path); + + /* Initialize ret->sun_path from the specified argument. This will interpret paths starting with '@' as + * abstract namespace sockets, and those starting with '/' as regular filesystem sockets. It won't accept + * anything else (i.e. no relative paths), to avoid ambiguities. Note that this function cannot be used to + * reference paths in the abstract namespace that include NUL bytes in the name. */ + + l = strlen(path); + if (l == 0) + return -EINVAL; + if (!IN_SET(path[0], '/', '@')) + return -EINVAL; + if (path[1] == 0) + return -EINVAL; + + /* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than + * the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket + * addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that + * do not expect non-NUL terminated file system path*/ + if (l+1 > sizeof(ret->sun_path)) + return -EINVAL; + + *ret = (struct sockaddr_un) { + .sun_family = AF_UNIX, + }; + + if (path[0] == '@') { + /* Abstract namespace socket */ + memcpy(ret->sun_path + 1, path + 1, l); /* copy *with* trailing NUL byte */ + return (int) (offsetof(struct sockaddr_un, sun_path) + l); /* 🔥 *don't* 🔥 include trailing NUL in size */ + + } else { + assert(path[0] == '/'); + + /* File system socket */ + memcpy(ret->sun_path, path, l + 1); /* copy *with* trailing NUL byte */ + return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */ + } +} diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 0a7d79885fd..29bd85f1e05 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -188,3 +188,5 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng }) int socket_ioctl_fd(void); + +int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path);