Block TIMER_SIGNAL in sigprocmask(SIG_SETMASK, ...).

Previously, we were zeroing out the reserved signals, when we actually
wanted to have TIMER_SIGNAL always be blocked, and the other signals
always be unblocked. This resulted in process termination when a
SIGEV_THREAD timer callback calls sigprocmask(SIG_SETMASK, ...) with
any signal mask value, and then subsequently fails to complete its
callback and reach the sigtimedwait in bionic before the next timer
iteration triggers.

Add a how argument to filter_reserved_signals to appropriately
block/unblock our reserved signals.

Bug: http://b/116783733
Test: bionic-unit-tests32/64
Change-Id: Ie5339682cdeb914711cd4089cd26ee395704d0df
diff --git a/libc/bionic/sigprocmask.cpp b/libc/bionic/sigprocmask.cpp
index 36866f3..5f70f32 100644
--- a/libc/bionic/sigprocmask.cpp
+++ b/libc/bionic/sigprocmask.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 #include "private/sigrtmin.h"
@@ -65,10 +66,16 @@
 int sigprocmask64(int how,
                   const sigset64_t* new_set,
                   sigset64_t* old_set) __attribute__((__noinline__)) {
+  // how is only checked for validity if new_set is provided.
+  if (new_set && how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) {
+    errno = EINVAL;
+    return -1;
+  }
+
   sigset64_t mutable_new_set;
   sigset64_t* mutable_new_set_ptr = nullptr;
   if (new_set) {
-    mutable_new_set = filter_reserved_signals(*new_set);
+    mutable_new_set = filter_reserved_signals(*new_set, how);
     mutable_new_set_ptr = &mutable_new_set;
   }
   return __rt_sigprocmask(how, mutable_new_set_ptr, old_set, sizeof(*new_set));