}
}
+#ifndef UIO_MAXIOV
+# define UIO_MAXIOV 1024
+#endif
+
+static unsigned int
+get_optmem_max(void)
+{
+ static int optmem_max;
+
+ if (!optmem_max) {
+ if (read_int_from_file("/proc/sys/net/core/optmem_max",
+ &optmem_max) || optmem_max <= 0) {
+ optmem_max = sizeof(long long) * (2 * UIO_MAXIOV + 512);
+ } else {
+ optmem_max = (optmem_max + sizeof(long long) - 1)
+ & ~(sizeof(long long) - 1);
+ }
+ }
+
+ return optmem_max;
+}
+
static void
-decode_msg_control(struct tcb *tcp, unsigned long addr, const size_t control_len)
+decode_msg_control(struct tcb *tcp, unsigned long addr,
+ const size_t in_control_len)
{
- if (!control_len)
+ if (!in_control_len)
return;
tprints(", msg_control=");
#endif
sizeof(struct cmsghdr);
+ size_t control_len =
+ in_control_len > get_optmem_max()
+ ? get_optmem_max() : in_control_len;
size_t buf_len = control_len;
char *buf = buf_len < cmsg_size ? NULL : malloc(buf_len);
if (!buf || umoven(tcp, addr, buf_len, buf) < 0) {
if (buf_len) {
tprints(", ");
printaddr(addr + (control_len - buf_len));
+ } else if (control_len < in_control_len) {
+ tprints(", ...");
}
tprints("]");
free(buf);
# define SCM_SECURITY 3
#endif
+#ifndef UIO_MAXIOV
+# define UIO_MAXIOV 1024
+#endif
+
#define MIN_SIZE_OF(type, member) \
(offsetof(type, member) + sizeof(((type *) 0)->member))
(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 * UIO_MAXIOV + 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);
struct msghdr *mh = tail_alloc(sizeof(*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",
(int) tcp->u_arg[i]);
return RVAL_DECODED;
}
+
+#if defined _LARGEFILE64_SOURCE && defined HAVE_OPEN64
+# define open_file open64
+#else
+# define open_file open
+#endif
+
+int
+read_int_from_file(const char *const fname, int *const pvalue)
+{
+ const int fd = open_file(fname, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ long lval;
+ char buf[sizeof(lval) * 3];
+ int n = read(fd, buf, sizeof(buf) - 1);
+ int saved_errno = errno;
+ close(fd);
+
+ if (n < 0) {
+ errno = saved_errno;
+ return -1;
+ }
+
+ buf[n] = '\0';
+ char *endptr = 0;
+ errno = 0;
+ lval = strtol(buf, &endptr, 10);
+ if (!endptr || (*endptr && '\n' != *endptr)
+#if INT_MAX < LONG_MAX
+ || lval > INT_MAX || lval < INT_MIN
+#endif
+ || ERANGE == errno) {
+ if (!errno)
+ errno = EINVAL;
+ return -1;
+ }
+
+ *pvalue = (int) lval;
+ return 0;
+}