]> granicus.if.org Git - strace/blobdiff - tests/msg_control.c
tests: extend TEST_NETLINK_OBJECT macro
[strace] / tests / msg_control.c
index 8d2888345ab95b19c334689d3c704defe6372dcc..b63f2d04e13e572d7f3a35431f5945bf43d1b4d7 100644 (file)
@@ -2,6 +2,7 @@
  * Check decoding of struct msghdr ancillary data.
  *
  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
+ * Copyright (c) 2016-2017 The strace developers.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,6 +30,7 @@
 
 #include "tests.h"
 #include <errno.h>
+#include <limits.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
@@ -38,6 +40,9 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include "xlat.h"
+#include "xlat/scmvals.h"
+
 #ifndef SOL_IP
 # define SOL_IP 0
 #endif
 #define MIN_SIZE_OF(type, member) \
        (offsetof(type, member) + sizeof(((type *) 0)->member))
 
-#define VAL_STR(val) val, #val
-
 static struct cmsghdr *
 get_cmsghdr(void *const page, const size_t len)
 {
        return page - CMSG_ALIGN(len);
 }
 
-#define DEFAULT_STRLEN 32
-
 static void
 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
 {
@@ -76,7 +77,7 @@ print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
        for (i = 0; i < nfd; ++i) {
                if (i)
                        printf(", ");
-#ifndef VERBOSE_MSGHDR
+#if !VERBOSE
                if (i >= DEFAULT_STRLEN) {
                        printf("...");
                        break;
@@ -229,6 +230,152 @@ test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
               (unsigned long) len, rc, errno2name());
 }
 
+static void
+test_scm_timestamp(struct msghdr *const mh, void *const page)
+{
+       size_t len = CMSG_SPACE(sizeof(struct timeval));
+       struct cmsghdr *cmsg = get_cmsghdr(page, len);
+
+       cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_TIMESTAMP;
+       struct timeval *tv = (struct timeval *) CMSG_DATA(cmsg);
+       tv->tv_sec = 123456789;
+       tv->tv_usec = 987654;
+
+       mh->msg_control = cmsg;
+       mh->msg_controllen = len;
+
+       int rc = sendmsg(-1, mh, 0);
+       printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
+              ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
+              ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP"
+              ", cmsg_data={tv_sec=%lld, tv_usec=%llu}}]"
+              ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
+              (unsigned) cmsg->cmsg_len,
+              (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec),
+              (unsigned long) len, rc, errno2name());
+
+       len = CMSG_SPACE(sizeof(struct timeval) - sizeof(long));
+       cmsg = get_cmsghdr(page, len);
+
+       cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval) - sizeof(long));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_TIMESTAMP;
+
+       mh->msg_control = cmsg;
+       mh->msg_controllen = len;
+
+       rc = sendmsg(-1, mh, 0);
+       printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
+              ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
+              ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP, cmsg_data=?}]"
+              ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
+              (unsigned) cmsg->cmsg_len,
+              (unsigned long) len, rc, errno2name());
+}
+
+static void
+test_scm_timestampns(struct msghdr *const mh, void *const page)
+{
+       size_t len = CMSG_SPACE(sizeof(struct timespec));
+       struct cmsghdr *cmsg = get_cmsghdr(page, len);
+
+       cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_TIMESTAMPNS;
+       struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg);
+       ts->tv_sec = 123456789;
+       ts->tv_nsec = 987654321;
+
+       mh->msg_control = cmsg;
+       mh->msg_controllen = len;
+
+       int rc = sendmsg(-1, mh, 0);
+       printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
+              ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
+              ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS"
+              ", cmsg_data={tv_sec=%lld, tv_nsec=%llu}}]"
+              ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
+              (unsigned) cmsg->cmsg_len,
+              (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec),
+              (unsigned long) len, rc, errno2name());
+
+       len = CMSG_SPACE(sizeof(struct timespec) - sizeof(long));
+       cmsg = get_cmsghdr(page, len);
+
+       cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec) - sizeof(long));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_TIMESTAMPNS;
+
+       mh->msg_control = cmsg;
+       mh->msg_controllen = len;
+
+       rc = sendmsg(-1, mh, 0);
+       printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
+              ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
+              ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS"
+              ", cmsg_data=?}]"
+              ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
+              (unsigned) cmsg->cmsg_len,
+              (unsigned long) len, rc, errno2name());
+}
+
+static void
+test_scm_timestamping(struct msghdr *const mh, void *const page)
+{
+       size_t len = CMSG_SPACE(3 * sizeof(struct timespec));
+       struct cmsghdr *cmsg = get_cmsghdr(page, len);
+
+       cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_TIMESTAMPING;
+       struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg);
+       ts[0].tv_sec = 123456789;
+       ts[0].tv_nsec = 987654321;
+       ts[1].tv_sec = 123456790;
+       ts[1].tv_nsec = 987654320;
+       ts[2].tv_sec = 123456791;
+       ts[2].tv_nsec = 987654319;
+
+       mh->msg_control = cmsg;
+       mh->msg_controllen = len;
+
+       int rc = sendmsg(-1, mh, 0);
+       printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
+              ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
+              ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING"
+              ", cmsg_data=[{tv_sec=%lld, tv_nsec=%llu}"
+              ", {tv_sec=%lld, tv_nsec=%llu}, {tv_sec=%lld, tv_nsec=%llu}]}]"
+              ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
+              (unsigned) cmsg->cmsg_len, (long long) ts[0].tv_sec,
+              zero_extend_signed_to_ull(ts[0].tv_nsec),
+              (long long) ts[1].tv_sec,
+              zero_extend_signed_to_ull(ts[1].tv_nsec),
+              (long long) ts[2].tv_sec,
+              zero_extend_signed_to_ull(ts[2].tv_nsec),
+              (unsigned long) len, rc, errno2name());
+
+       len = CMSG_SPACE(3 * sizeof(struct timespec) - sizeof(long));
+       cmsg = get_cmsghdr(page, len);
+
+       cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec) - sizeof(long));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_TIMESTAMPING;
+
+       mh->msg_control = cmsg;
+       mh->msg_controllen = len;
+
+       rc = sendmsg(-1, mh, 0);
+       printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
+              ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
+              ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING"
+              ", cmsg_data=?}]"
+              ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
+              (unsigned) cmsg->cmsg_len,
+              (unsigned long) len, rc, errno2name());
+}
+
 static void
 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
 {
@@ -370,7 +517,7 @@ test_sol_socket(struct msghdr *const mh, void *const page)
                     cmsg_len++) {
                        test_scm_security(mh, msg_controllen,
                                          page, text, cmsg_len,
-                                         VAL_STR(SOL_SOCKET));
+                                         ARG_STR(SOL_SOCKET));
                }
        }
 
@@ -378,12 +525,16 @@ test_sol_socket(struct msghdr *const mh, void *const page)
        test_scm_rights3(mh, page, DEFAULT_STRLEN);
        test_scm_rights3(mh, page, DEFAULT_STRLEN + 1);
 
-       test_unknown_type(mh, page, VAL_STR(SOL_SOCKET), "SCM_???");
+       test_scm_timestamp(mh, page);
+       test_scm_timestampns(mh, page);
+       test_scm_timestamping(mh, page);
+
+       test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???");
 }
 
 static void
 test_ip_pktinfo(struct msghdr *const mh, void *const page,
-               const int cmsg_type, const char *const cmsg_type_str)
+               const int cmsg_type, const char *const cmsg_type_str)
 {
        const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
        struct cmsghdr *const cmsg = get_cmsghdr(page, len);
@@ -448,7 +599,7 @@ test_ip_uint(struct msghdr *const mh, void *const page,
 
 static void
 test_ip_uint8_t(struct msghdr *const mh, void *const page,
-               const int cmsg_type, const char *const cmsg_type_str)
+               const int cmsg_type, const char *const cmsg_type_str)
 {
        const unsigned int len = CMSG_SPACE(1);
        struct cmsghdr *const cmsg = get_cmsghdr(page, len);
@@ -478,7 +629,7 @@ print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
        for (i = 0; i < data_len; ++i) {
                if (i)
                        printf(", ");
-#ifndef VERBOSE_MSGHDR
+#if !VERBOSE
                if (i >= DEFAULT_STRLEN) {
                        printf("...");
                        break;
@@ -530,7 +681,7 @@ struct sock_ee {
 
 static void
 test_ip_recverr(struct msghdr *const mh, void *const page,
-               const int cmsg_type, const char *const cmsg_type_str)
+               const int cmsg_type, const char *const cmsg_type_str)
 {
        const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
        struct cmsghdr *const cmsg = get_cmsghdr(page, len);
@@ -603,32 +754,32 @@ test_ip_origdstaddr(struct msghdr *const mh, void *const page,
 static void
 test_sol_ip(struct msghdr *const mh, void *const page)
 {
-       test_ip_pktinfo(mh, page, VAL_STR(IP_PKTINFO));
-       test_ip_uint(mh, page, VAL_STR(IP_TTL));
-       test_ip_uint8_t(mh, page, VAL_STR(IP_TOS));
-       test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 1);
-       test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 2);
-       test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 3);
-       test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 4);
-       test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 5);
-       test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 6);
-       test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 7);
-       test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 8);
-       test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), DEFAULT_STRLEN - 1);
-       test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), DEFAULT_STRLEN);
-       test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), DEFAULT_STRLEN + 1);
+       test_ip_pktinfo(mh, page, ARG_STR(IP_PKTINFO));
+       test_ip_uint(mh, page, ARG_STR(IP_TTL));
+       test_ip_uint8_t(mh, page, ARG_STR(IP_TOS));
+       test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 1);
+       test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 2);
+       test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 3);
+       test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 4);
+       test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 5);
+       test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 6);
+       test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 7);
+       test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 8);
+       test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN - 1);
+       test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN);
+       test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN + 1);
 #ifdef IP_CHECKSUM
-       test_ip_recverr(mh, page, VAL_STR(IP_RECVERR));
+       test_ip_recverr(mh, page, ARG_STR(IP_RECVERR));
 #endif
 #ifdef IP_ORIGDSTADDR
-       test_ip_origdstaddr(mh, page, VAL_STR(IP_ORIGDSTADDR));
+       test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR));
 #endif
 #ifdef IP_CHECKSUM
-       test_ip_uint(mh, page, VAL_STR(IP_CHECKSUM));
+       test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM));
 #endif
        test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
-                         VAL_STR(SOL_IP));
-       test_unknown_type(mh, page, VAL_STR(SOL_IP), "IP_???");
+                         ARG_STR(SOL_IP));
+       test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???");
 }
 
 static void
@@ -652,13 +803,47 @@ test_unknown_level(struct msghdr *const mh, void *const page)
               (unsigned) mh->msg_controllen, rc, errno2name());
 }
 
+static void
+test_big_len(struct msghdr *const mh)
+{
+       int optmem_max;
+
+       if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max)
+           || optmem_max <= 0 || optmem_max > 0x100000)
+               optmem_max = sizeof(long long) * (2 * IOV_MAX + 512);
+       optmem_max = (optmem_max + sizeof(long long) - 1)
+                    & ~(sizeof(long long) - 1);
+
+       const size_t len = optmem_max * 2;
+       struct cmsghdr *const cmsg = tail_alloc(len);
+       cmsg->cmsg_len = len;
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+
+       mh->msg_control = cmsg;
+       mh->msg_controllen = len;
+
+       int rc = sendmsg(-1, mh, 0);
+       if (EBADF != errno)
+               perror_msg_and_skip("sendmsg");
+
+       printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
+              ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
+              ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
+              (unsigned) cmsg->cmsg_len);
+       print_fds(cmsg, optmem_max);
+       printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
+              (unsigned long) len, rc, errno2name());
+}
+
 int main(int ac, const char **av)
 {
        int rc = sendmsg(-1, 0, 0);
        printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
 
-       struct msghdr *mh = tail_alloc(sizeof(*mh));
+       TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, mh);
        memset(mh, 0, sizeof(*mh));
+       test_big_len(mh);
 
        rc = sendmsg(-1, mh + 1, 0);
        printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",