]> granicus.if.org Git - strace/commitdiff
msghdr.c: limit output when printing excessively large messages
authorDmitry V. Levin <ldv@altlinux.org>
Sun, 3 Jul 2016 22:15:45 +0000 (22:15 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 3 Jul 2016 22:15:45 +0000 (22:15 +0000)
Limit output of struct msghdr.msg_control when
struct msghdr.msg_controllen is greater than the maximum ancillary
buffer size specified in /proc/sys/net/core/optmem_max file.

* configure.ac (AC_CHECK_FUNCS): Add open64.
* defs.h (read_int_from_file): New prototype.
* util.c (read_int_from_file): New function.
* msghdr.c (get_optmem_max): New function based on read_int_from_file.
(decode_msg_control): Use it to check control_len argument.
* tests/msg_control.c (test_big_len): New function.
(main): Use it to test printing of excessively large messages.

configure.ac
defs.h
msghdr.c
tests/msg_control.c
util.c

index 74288d830077a7595805691a1992cc8e0d496144..97b75be7564bf853feb2569f37f6a16485a6a002 100644 (file)
@@ -290,6 +290,7 @@ AC_CHECK_FUNCS(m4_normalize([
        ftruncate
        futimens
        if_indextoname
+       open64
        pipe2
        prctl
        preadv
diff --git a/defs.h b/defs.h
index 114b98e5768a0da74fa16088404486fa02d1356f..bda74a3406102bc9aff23f67aa256004230f8137 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -511,6 +511,8 @@ int strace_vfprintf(FILE *fp, const char *fmt, va_list args);
 # define strace_vfprintf vfprintf
 #endif
 
+extern int read_int_from_file(const char *, int *);
+
 extern void set_sortby(const char *);
 extern void set_overhead(int);
 extern void qualify(const char *);
index dd203260cbc252c7d9272c04683c2e2dbd4854cc..3db95fa7803dd5b048cfd5a80991da041d09b32a 100644 (file)
--- a/msghdr.c
+++ b/msghdr.c
@@ -229,10 +229,33 @@ print_cmsg_type_data(struct tcb *tcp, const int cmsg_level, const int cmsg_type,
        }
 }
 
+#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=");
 
@@ -242,6 +265,9 @@ decode_msg_control(struct tcb *tcp, unsigned long addr, const size_t control_len
 #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) {
@@ -299,6 +325,8 @@ decode_msg_control(struct tcb *tcp, unsigned long addr, const size_t control_len
        if (buf_len) {
                tprints(", ");
                printaddr(addr + (control_len - buf_len));
+       } else if (control_len < in_control_len) {
+               tprints(", ...");
        }
        tprints("]");
        free(buf);
index 8d2888345ab95b19c334689d3c704defe6372dcc..d5ed278deb9ba73483070de1f31ac52317dedebf 100644 (file)
 # 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))
 
@@ -652,6 +656,39 @@ 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 * 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);
@@ -659,6 +696,7 @@ int main(int ac, const char **av)
 
        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",
diff --git a/util.c b/util.c
index 3122755414d889770ee781dddb1e08790ae34f76..c99136d295c449a33e37342f9bb4b53620526979 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1436,3 +1436,45 @@ printargs_d(struct tcb *tcp)
                        (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;
+}