]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
socket-util: introduce CMSG_FIND_AND_COPY_DATA()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 13 Apr 2023 09:00:41 +0000 (18:00 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 16 Apr 2023 04:26:55 +0000 (13:26 +0900)
The cmd(3) man page says about CMSG_DATA():
> The pointer returned cannot be assumed to be suitably aligned for
> accessing arbitrary payload data types. Applications should not cast
> it to a pointer type matching the payload, but should instead use
> memcpy(3) to copy data to or from a suitably declared object.

Hence, if we want to use unaligned data in cmsg, we need to copy it
before use. That's typically important for reading timestamps in
RISCV32, as the time_t is 64bit and size_t is 32bit on the system.

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

index b35de4dad631687d1d9a3904659407a4fa6492b4..5b76948c0648712e2dba170ff6c02dc35093088f 100644 (file)
@@ -1171,6 +1171,24 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng
         return NULL;
 }
 
+void* cmsg_find_and_copy_data(struct msghdr *mh, int level, int type, void *buf, size_t buf_len) {
+        struct cmsghdr *cmsg;
+
+        assert(mh);
+        assert(buf);
+        assert(buf_len > 0);
+
+        /* This is similar to cmsg_find_data(), but copy the found data to buf. This should be typically used
+         * when reading possibly unaligned data such as timestamp, as time_t is 64bit and size_t is 32bit on
+         * RISCV32. See issue #27241. */
+
+        cmsg = cmsg_find(mh, level, type, CMSG_LEN(buf_len));
+        if (!cmsg)
+                return NULL;
+
+        return memcpy_safe(buf, CMSG_DATA(cmsg), buf_len);
+}
+
 int socket_ioctl_fd(void) {
         int fd;
 
index d6d63a4f339a0366620269ff4ecf781682d1aaa3..b323b1b99f57d02e5b5014ed34016ee0ca0f20e0 100644 (file)
@@ -189,11 +189,16 @@ int flush_accept(int fd);
         })
 
 struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
+void* cmsg_find_and_copy_data(struct msghdr *mh, int level, int type, void *buf, size_t buf_len);
 
 /* Type-safe, dereferencing version of cmsg_find() */
 #define CMSG_FIND_DATA(mh, level, type, ctype)                          \
         CMSG_TYPED_DATA(cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))), ctype)
 
+/* Type-safe version of cmsg_find_and_copy_data() */
+#define CMSG_FIND_AND_COPY_DATA(mh, level, type, ctype)             \
+        (ctype*) cmsg_find_and_copy_data(mh, level, type, &(ctype){}, sizeof(ctype))
+
 /* Resolves to a type that can carry cmsghdr structures. Make sure things are properly aligned, i.e. the type
  * itself is placed properly in memory and the size is also aligned to what's appropriate for "cmsghdr"
  * structures. */