* 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
#include "tests.h"
#include <errno.h>
+#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#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)
{
for (i = 0; i < nfd; ++i) {
if (i)
printf(", ");
-#ifndef VERBOSE_MSGHDR
+#if !VERBOSE
if (i >= DEFAULT_STRLEN) {
printf("...");
break;
(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)
{
cmsg_len++) {
test_scm_security(mh, msg_controllen,
page, text, cmsg_len,
- VAL_STR(SOL_SOCKET));
+ ARG_STR(SOL_SOCKET));
}
}
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);
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);
for (i = 0; i < data_len; ++i) {
if (i)
printf(", ");
-#ifndef VERBOSE_MSGHDR
+#if !VERBOSE
if (i >= DEFAULT_STRLEN) {
printf("...");
break;
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);
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
(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",