net-test: work around UML crashes during shutdown

Sometimes the tests all pass, but UML crashes during the shutdown process itself:
As such we can't actually rely on the /proc/exitcode returned value.

Before this change (rarely):
    ##### 0 failed tests.
    reboot: System halted
    ../kernel/tests/net/test/run_net_test.sh: line 431: 61682 Aborted                 (core dumped)
    $KERNEL_BINARY umid=net_test mem=512M $blockdevice=$ROOTFS $netconfig $consolemode $cmdline 1>&2
    stty: standard input: Inappropriate ioctl for device
    Returning exit code 134.

With this change and an extra 'echo 134 > /proc/exitcode' at end of net_test.sh
(to simulate a UML crash):
  ##### 0 failed tests.
  epollctl add err fd 3, Operation not permitted
  epollctl add err fd 19, Operation not permitted
  reboot: System halted

  Warning: UML appears to have crashed after successfully executing the tests.
  Info: retrieved exit code 0.
  Returning exit code 0.

Normally:
  ##### 0 failed tests.
  epollctl add err fd 3, Operation not permitted
  epollctl add err fd 19, Operation not permitted
  reboot: System halted

  Info: retrieved exit code 0.
  Returning exit code 0.

(I don't know why the epollctl add errors show up - but they don't appear to hurt.)

Some useful docs about UML kernel command line options at:
  http://user-mode-linux.sourceforge.net/old/input.html
  https://www.kernel.org/doc/html/latest/virt/uml/user_mode_linux_howto_v2.html

Tested: see above
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I37a67f140b5fa022f3dde97fbe45373df1a9a20d
Merged-In: I37a67f140b5fa022f3dde97fbe45373df1a9a20d
(cherrypicked from 0c89e40ce29b1908c546619e30e04fe5a6e6c6d2)
diff --git a/net/test/net_test.sh b/net/test/net_test.sh
index 72c67a9..f4ca29f 100755
--- a/net/test/net_test.sh
+++ b/net/test/net_test.sh
@@ -152,7 +152,13 @@
 
 echo -e "Running $net_test $net_test_args\n"
 $net_test $net_test_args
+rv="$?"
 
 # Write exit code of net_test to a file so that the builder can use it
 # to signal failure if any tests fail.
-echo $? >$net_test_exitcode
+echo "${rv}" > "${net_test_exitcode}"
+
+# Additionally on UML make it the exit code of UML kernel binary itself.
+if [[ -e '/proc/exitcode' ]]; then
+  echo "${rv}" > /proc/exitcode
+fi
diff --git a/net/test/run_net_test.sh b/net/test/run_net_test.sh
index deed5cd..5648a06 100755
--- a/net/test/run_net_test.sh
+++ b/net/test/run_net_test.sh
@@ -282,8 +282,10 @@
   # Get the absolute path to the test file that's being run.
   cmdline="$cmdline net_test=/host$SCRIPT_DIR/$test"
 
-  # Use UML's /proc/exitcode feature to communicate errors on test failure
-  cmdline="$cmdline net_test_exitcode=/proc/exitcode"
+  # We'd use UML's /proc/exitcode feature to communicate errors on test failure,
+  # if not for UML having a tendency to crash during shutdown,
+  # so instead use an extra serial line we'll redirect to an open fd...
+  cmdline="$cmdline net_test_exitcode=/dev/ttyS3"
 
   # Experience shows that we need at least 128 bits of entropy for the
   # kernel's crng init to complete (before it fully initializes stuff behaves
@@ -307,11 +309,30 @@
     blockdevice=ubdar
   fi
 
+  # Create a temp file for 'serial line 3' for return code.
+  SSL3="$(mktemp)"
+
   exitcode=0
-  $KERNEL_BINARY >&2 umid=net_test mem=512M \
-    $blockdevice=$SCRIPT_DIR/$ROOTFS $netconfig $consolemode $cmdline \
+  $KERNEL_BINARY >&2 3>"${SSL3}" umid=net_test mem=512M \
+    $blockdevice=$SCRIPT_DIR/$ROOTFS $netconfig $consolemode ssl3=null,fd:3 $cmdline \
   || exitcode=$?
 
+  if [[ "${exitcode}" == 134 && -s "${SSL3}" && "$(tr -d '\r' < "${SSL3}")" == 0 ]]; then
+    # Sometimes the tests all pass, but UML crashes during the shutdown process itself.
+    # As such we can't actually rely on the /proc/exitcode returned value.
+    echo "Warning: UML appears to have crashed after successfully executing the tests." 1>&2
+  elif [[ "${exitcode}" != 0 ]]; then
+    echo "Warning: UML exited with ${exitcode} instead of zero." 1>&2
+  fi
+
+  if [[ -s "${SSL3}" ]]; then
+    exitcode="$(tr -d '\r' < "${SSL3}")"
+    echo "Info: retrieved exit code ${exitcode}." 1>&2
+  fi
+
+  rm -f "${SSL3}"
+  unset SSL3
+
   # UML is kind of crazy in how guest syscalls work.  It requires host kernel
   # to not be in vsyscall=none mode.
   if [[ "${exitcode}" != '0' ]]; then