]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
socket-util: change sockaddr_un_set_path() to return recognizable error on 108ch...
authorLennart Poettering <lennart@poettering.net>
Tue, 10 May 2022 14:15:26 +0000 (16:15 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 13 May 2022 12:47:58 +0000 (21:47 +0900)
This way we can implement nice fallbacks later on.

While we are at it, provide a test for this (one that is a bit over the
top, but then again, we can never have enough tests).

src/basic/socket-util.c
src/test/test-socket-util.c

index 8d0494ece55564f8170570d62f485f9465e3795a..0dfe2a7dbca0e9c791835d59c04e7049a2412d88 100644 (file)
@@ -1236,7 +1236,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
          * 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;
+                return path[0] == '@' ? -EINVAL : -ENAMETOOLONG; /* return a recognizable error if this is
+                                                                  * too long to fit into a sockaddr_un, but
+                                                                  * is a file system path, and thus might be
+                                                                  * connectible via O_PATH indirection. */
 
         *ret = (struct sockaddr_un) {
                 .sun_family = AF_UNIX,
index 3245516f9a7800ef593fd06ec62d0df9a6f92b59..cd1e374ec82bb06bdb4414655e4fca32e4a158f1 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <fcntl.h>
 #include <grp.h>
+#include <net/if_arp.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include "escape.h"
 #include "exit-status.h"
 #include "fd-util.h"
+#include "fs-util.h"
 #include "in-addr-util.h"
 #include "io-util.h"
 #include "log.h"
 #include "macro.h"
+#include "path-util.h"
 #include "process-util.h"
+#include "random-util.h"
+#include "rm-rf.h"
 #include "socket-util.h"
 #include "string-util.h"
 #include "tests.h"
@@ -478,4 +483,46 @@ TEST(ipv6_enabled) {
         log_info("IPv6 enabled: %s", yes_no(socket_ipv6_is_enabled()));
 }
 
+TEST(sockaddr_un_set_path) {
+        _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+        _cleanup_(unlink_and_freep) char *sh = NULL;
+        _cleanup_free_ char *j = NULL;
+        union sockaddr_union sa;
+        _cleanup_close_ int fd1 = -1, fd2 = -1, fd3 = -1;
+
+        assert_se(mkdtemp_malloc("/tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaXXXXXX", &t) >= 0);
+        assert_se(strlen(t) > SUN_PATH_LEN);
+
+        assert_se(j = path_join(t, "sock"));
+        assert_se(sockaddr_un_set_path(&sa.un, j) == -ENAMETOOLONG); /* too long for AF_UNIX socket */
+
+        assert_se(asprintf(&sh, "/tmp/%" PRIx64, random_u64()) >= 0);
+        assert_se(symlink(t, sh) >= 0); /* create temporary symlink, to access it anyway */
+
+        free(j);
+        assert_se(j = path_join(sh, "sock"));
+        assert_se(sockaddr_un_set_path(&sa.un, j) >= 0);
+
+        fd1 = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+        assert_se(fd1 >= 0);
+        assert_se(bind(fd1, &sa.sa, SOCKADDR_LEN(sa)) >= 0);
+        assert_se(listen(fd1, 1) >= 0);
+
+        sh = unlink_and_free(sh); /* remove temporary symlink */
+
+        fd2 = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+        assert_se(fd2 >= 0);
+        assert_se(connect(fd2, &sa.sa, SOCKADDR_LEN(sa)) < 0);
+        assert_se(errno == ENOENT); /* we removed the symlink, must fail */
+
+        free(j);
+        assert_se(j = path_join(t, "sock"));
+
+        fd3 = open(j, O_CLOEXEC|O_PATH|O_NOFOLLOW);
+        assert_se(fd3 > 0);
+        assert_se(sockaddr_un_set_path(&sa.un, FORMAT_PROC_FD_PATH(fd3)) >= 0); /* connect via O_PATH instead, circumventing 108ch limit */
+
+        assert_se(connect(fd2, &sa.sa, SOCKADDR_LEN(sa)) >= 0);
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);