[object][job] Fix bug where process creation bypasses ZX_POL_NEW_ANY

This change fixes a bug where process creation would succeed even when
the job policy prohibited it via ZX_POL_NEW_ANY.  See ZX-3364 for
details.

Add test and static_asserts to reduce the likelihood of regression.

Bug: ZX-3364 #done
Test: "k ut job_policy"
Change-Id: Ifcb22d3c341d1ebc1c8e37c264e5833305dacf59
diff --git a/kernel/object/job_policy.cpp b/kernel/object/job_policy.cpp
index cc9d393..0c81d45 100644
--- a/kernel/object/job_policy.cpp
+++ b/kernel/object/job_policy.cpp
@@ -6,6 +6,7 @@
 
 #include <assert.h>
 #include <err.h>
+#include <fbl/algorithm.h>
 #include <kernel/deadline.h>
 #include <zircon/syscalls/policy.h>
 
@@ -63,8 +64,22 @@
 // space of a single uint64_t so the 'union' trick works.
 static_assert(sizeof(Encoding) == sizeof(pol_cookie_t), "bitfield issue");
 
-// Make sure that adding new policies forces updating this file.
-static_assert(ZX_POL_MAX == 13u, "please update PolicyManager AddPolicy and QueryBasicPolicy");
+// It is critical that this array contain all "new object" policies because it's used to implement
+// ZX_NEW_ANY.
+const uint32_t kNewObjectPolicies[]{
+    ZX_POL_NEW_VMO,
+    ZX_POL_NEW_CHANNEL,
+    ZX_POL_NEW_EVENT,
+    ZX_POL_NEW_EVENTPAIR,
+    ZX_POL_NEW_PORT,
+    ZX_POL_NEW_SOCKET,
+    ZX_POL_NEW_FIFO,
+    ZX_POL_NEW_TIMER,
+    ZX_POL_NEW_PROCESS,
+};
+static_assert(
+    fbl::count_of(kNewObjectPolicies) + 4 == ZX_POL_MAX,
+    "please update JobPolicy::AddPartial, JobPolicy::QueryBasicPolicy, and kNewObjectPolicies");
 
 bool CanSetEntry(uint64_t existing, uint32_t new_action) {
     if (Encoding::is_default(existing))
@@ -184,8 +199,8 @@
 
         if (in.condition == ZX_POL_NEW_ANY) {
             // loop over all ZX_POL_NEW_xxxx conditions.
-            for (uint32_t it = ZX_POL_NEW_VMO; it <= ZX_POL_NEW_TIMER; ++it) {
-                if ((res = AddPartial(mode, new_cookie, it, in.policy, &partials[it])) < 0) {
+            for (auto pol : kNewObjectPolicies) {
+                if ((res = AddPartial(mode, new_cookie, pol, in.policy, &partials[pol])) < 0) {
                     return res;
                 }
             }
diff --git a/kernel/object/job_policy_tests.cpp b/kernel/object/job_policy_tests.cpp
index f2adfd7..896240e 100644
--- a/kernel/object/job_policy_tests.cpp
+++ b/kernel/object/job_policy_tests.cpp
@@ -85,6 +85,25 @@
     END_TEST;
 }
 
+static bool add_basic_policy_deny_any() {
+    BEGIN_TEST;
+
+    JobPolicy p;
+    zx_policy_basic_t policy{ZX_POL_NEW_ANY, ZX_POL_ACTION_DENY};
+    ASSERT_EQ(ZX_OK, p.AddBasicPolicy(ZX_JOB_POL_ABSOLUTE, &policy, 1), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_VMO), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_CHANNEL), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_EVENT), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_EVENTPAIR), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_PORT), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_SOCKET), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_FIFO), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_TIMER), "");
+    ASSERT_EQ(ZX_POL_ACTION_DENY, p.QueryBasicPolicy(ZX_POL_NEW_PROCESS), "");
+
+    END_TEST;
+}
+
 static bool set_get_timer_slack() {
     BEGIN_TEST;
 
@@ -103,5 +122,6 @@
 UNITTEST("add_basic_policy_absolute", add_basic_policy_absolute)
 UNITTEST("add_basic_policy_relative", add_basic_policy_relative)
 UNITTEST("add_basic_policy_unmodified_on_error", add_basic_policy_unmodified_on_error)
+UNITTEST("add_basic_policy_deny_any", add_basic_policy_deny_any)
 UNITTEST("set_get_timer_slack", set_get_timer_slack)
 UNITTEST_END_TESTCASE(job_policy_tests, "job_policy", "JobPolicy tests");