liblog: log reader validate headers

Ensure len and hdr_size fields are valid and match the return value.
Truncate or zero content as necessary, but do not drop the message.

Bug: 28610769
Change-Id: I10785fa5b03aa3da7d07b368188e3f7c36a84b4f
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index 0d6ba08..d04a8c1 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -341,6 +341,43 @@
     return logger_list;
 }
 
+/* Validate log_msg packet, read function has already been null checked */
+static int android_transport_read(struct android_log_logger_list *logger_list,
+                                  struct android_log_transport_context *transp,
+                                  struct log_msg *log_msg)
+{
+    int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+
+    if (ret > (int)sizeof(*log_msg)) {
+        ret = sizeof(*log_msg);
+    }
+
+    transp->ret = ret;
+
+    /* propagate errors, or make sure len & hdr_size members visible */
+    if (ret < (int)(sizeof(log_msg->entry.len) +
+                    sizeof(log_msg->entry.hdr_size))) {
+        if (ret >= (int)sizeof(log_msg->entry.len)) {
+            log_msg->entry.len = 0;
+        }
+        return ret;
+    }
+
+    /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
+    if (log_msg->entry_v2.hdr_size == 0) {
+        log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
+    }
+
+    /* len validation */
+    if (ret <= log_msg->entry_v2.hdr_size) {
+        log_msg->entry.len = 0;
+    } else {
+        log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
+    }
+
+    return ret;
+}
+
 /* Read from the selected logs */
 LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
                                                struct log_msg *log_msg)
@@ -378,7 +415,7 @@
                     } else if ((logger_list_internal->mode &
                                 ANDROID_LOG_NONBLOCK) ||
                             !transp->transport->poll) {
-                        retval = transp->ret = (*transp->transport->read)(
+                        retval = android_transport_read(
                                 logger_list_internal,
                                 transp,
                                 &transp->logMsg);
@@ -397,7 +434,7 @@
                             }
                             retval = transp->ret = pollval;
                         } else if (pollval > 0) {
-                            retval = transp->ret = (*transp->transport->read)(
+                            retval = android_transport_read(
                                     logger_list_internal,
                                     transp,
                                     &transp->logMsg);
@@ -434,16 +471,22 @@
         if (!oldest) {
             return ret;
         }
-        memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
-                    (oldest->logMsg.entry.hdr_size ?
-                        oldest->logMsg.entry.hdr_size :
-                        sizeof(struct logger_entry)));
+        // ret is a positive value less than sizeof(struct log_msg)
+        ret = oldest->ret;
+        if (ret < oldest->logMsg.entry.hdr_size) {
+            // zero truncated header fields.
+            memset(log_msg, 0,
+                   (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
+                       sizeof(oldest->logMsg) :
+                       oldest->logMsg.entry.hdr_size));
+        }
+        memcpy(log_msg, &oldest->logMsg, ret);
         oldest->logMsg.entry.len = 0; /* Mark it as copied */
-        return oldest->ret;
+        return ret;
     }
 
     /* if only one, no need to copy into transport_context and merge-sort */
-    return (transp->transport->read)(logger_list_internal, transp, log_msg);
+    return android_transport_read(logger_list_internal, transp, log_msg);
 }
 
 /* Close all the logs */