shill: RTNL: fixup bounds checking in decoding

The fuzzing framework noticed two heap overruns in RTNL parsing.

For NLMSG_ERROR, we validate that the header fits in our buffer, but we
don't validate that the 'nlmsgerr' does. Fix that.

For DeocdeNdUserOption(), our bounds check isn't big enough; beyond the
first element, we're trusting that the headers contain correct length
values, and we only bounds check against them. Extend the initial bounds
checking to account for all the bits we're expecting to be packed into
this message.

BUG=chromium:856866
TEST=build for x86 with USE="asan fuzzer", then run
     /usr/libexec/fuzzers/rtnl_handler_fuzzer
TEST=network_Ipv6SimpleNegotiation

Change-Id: I0bb289208f08d971355be10033389877fc600716
Signed-off-by: Brian Norris <briannorris@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1116254
Reviewed-by: Kirtika Ruchandani <kirtika@chromium.org>
diff --git a/net/rtnl_handler.cc b/net/rtnl_handler.cc
index 3189b2f..f2cf827 100644
--- a/net/rtnl_handler.cc
+++ b/net/rtnl_handler.cc
@@ -284,6 +284,11 @@
           break;
         case NLMSG_ERROR:
           {
+            if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+              SLOG(this, 5) << "invalid error message header: length "
+                            << hdr->nlmsg_len;
+              break;
+            }
             struct nlmsgerr* err =
                 reinterpret_cast<nlmsgerr*>(NLMSG_DATA(hdr));
             int error_number = -err->error;
diff --git a/net/rtnl_message.cc b/net/rtnl_message.cc
index 9f265c0..f744044 100644
--- a/net/rtnl_message.cc
+++ b/net/rtnl_message.cc
@@ -259,7 +259,9 @@
                                      Mode mode,
                                      rtattr** attr_data,
                                      int* attr_length) {
-  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->nd_user_opt))) {
+  if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->nd_user_opt) +
+                                        sizeof(struct nduseroptmsg) +
+                                        sizeof(NDUserOptionHeader))) {
     return false;
   }