[syscalls] Add ZX_POL_NEW_PROCESS
Previously, we lacked a policy bit for controlling process creation.
We'll use this policy bit in the future to force clients through
fuchsia.process.Launcher.
Also, hide ZX_POL_MAX from userspace so we can add more policy bits in
the future.
TEST=spawn_launcher_test
Change-Id: Idcba7c7db595774bd10b227da41e4c7249bb83ea
diff --git a/docs/syscalls/job_set_policy.md b/docs/syscalls/job_set_policy.md
index d3f3d6b..3c6d720 100644
--- a/docs/syscalls/job_set_policy.md
+++ b/docs/syscalls/job_set_policy.md
@@ -67,6 +67,8 @@
a new fifo.
+ **ZX_POL_NEW_TIMER** a process under this job is attempting to create
a new timer.
++ **ZX_POL_NEW_PROCESS** a process under this job is attempting to create
+ a new process.
+ **ZX_POL_NEW_ANY** is a special *condition* that stands for all of
the above **ZX_NEW** condtions such as **ZX_POL_NEW_VMO**,
**ZX_POL_NEW_CHANNEL**, **ZX_POL_NEW_EVENT**, **ZX_POL_NEW_EVENTPAIR**,
diff --git a/kernel/object/policy_manager.cpp b/kernel/object/policy_manager.cpp
index a4e9007..db5682c 100644
--- a/kernel/object/policy_manager.cpp
+++ b/kernel/object/policy_manager.cpp
@@ -43,7 +43,8 @@
uint64_t new_socket : 4;
uint64_t new_fifo : 4;
uint64_t new_timer : 4;
- uint64_t unused_bits : 19;
+ uint64_t new_process : 4;
+ uint64_t unused_bits : 15;
uint64_t cookie_mode : 1; // see kPolicyInCookie.
};
@@ -62,7 +63,7 @@
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 == 12u, "please update PolicyManager AddPolicy and QueryBasicPolicy");
+static_assert(ZX_POL_MAX == 13u, "please update PolicyManager AddPolicy and QueryBasicPolicy");
PolicyManager* PolicyManager::Create(uint32_t default_action) {
fbl::AllocChecker ac;
@@ -151,6 +152,7 @@
case ZX_POL_NEW_SOCKET: return GetEffectiveAction(existing.new_socket);
case ZX_POL_NEW_FIFO: return GetEffectiveAction(existing.new_fifo);
case ZX_POL_NEW_TIMER: return GetEffectiveAction(existing.new_timer);
+ case ZX_POL_NEW_PROCESS: return GetEffectiveAction(existing.new_process);
case ZX_POL_VMAR_WX: return GetEffectiveAction(existing.vmar_wx);
default: return ZX_POL_ACTION_DENY;
}
@@ -219,6 +221,9 @@
case ZX_POL_NEW_TIMER:
POLMAN_SET_ENTRY(mode, existing.new_timer, policy, result.new_timer);
break;
+ case ZX_POL_NEW_PROCESS:
+ POLMAN_SET_ENTRY(mode, existing.new_process, policy, result.new_process);
+ break;
default:
return ZX_ERR_NOT_SUPPORTED;
}
diff --git a/kernel/syscalls/task.cpp b/kernel/syscalls/task.cpp
index 2bba39a..d7fcd45 100644
--- a/kernel/syscalls/task.cpp
+++ b/kernel/syscalls/task.cpp
@@ -329,21 +329,26 @@
if (options != 0)
return ZX_ERR_INVALID_ARGS;
+ auto up = ProcessDispatcher::GetCurrent();
+
+ // We check the policy against the process calling zx_process_create, which
+ // is the operative policy, rather than against |job_handle|. Access to
+ // |job_handle| is controlled by the rights associated with the handle.
+ zx_status_t result = up->QueryPolicy(ZX_POL_NEW_PROCESS);
+ if (result != ZX_OK)
+ return result;
+
// copy out the name
char buf[ZX_MAX_NAME_LEN];
fbl::StringPiece sp;
// Silently truncate the given name.
if (name_len > sizeof(buf))
name_len = sizeof(buf);
- zx_status_t result = copy_user_string(_name, name_len,
- buf, sizeof(buf), &sp);
+ result = copy_user_string(_name, name_len, buf, sizeof(buf), &sp);
if (result != ZX_OK)
return result;
LTRACEF("name %s\n", buf);
- // convert job handle to job dispatcher
- auto up = ProcessDispatcher::GetCurrent();
-
fbl::RefPtr<JobDispatcher> job;
// TODO(ZX-968): define process creation job rights.
auto status = up->GetDispatcherWithRights(job_handle, ZX_RIGHT_WRITE, &job);
@@ -354,11 +359,11 @@
fbl::RefPtr<Dispatcher> proc_dispatcher;
fbl::RefPtr<VmAddressRegionDispatcher> vmar_dispatcher;
zx_rights_t proc_rights, vmar_rights;
- zx_status_t res = ProcessDispatcher::Create(fbl::move(job), sp, options,
- &proc_dispatcher, &proc_rights,
- &vmar_dispatcher, &vmar_rights);
- if (res != ZX_OK)
- return res;
+ result = ProcessDispatcher::Create(fbl::move(job), sp, options,
+ &proc_dispatcher, &proc_rights,
+ &vmar_dispatcher, &vmar_rights);
+ if (result != ZX_OK)
+ return result;
uint32_t koid = (uint32_t)proc_dispatcher->get_koid();
ktrace(TAG_PROC_CREATE, koid, 0, 0, 0);
diff --git a/system/public/zircon/syscalls/policy.h b/system/public/zircon/syscalls/policy.h
index c89758a..f7061ce 100644
--- a/system/public/zircon/syscalls/policy.h
+++ b/system/public/zircon/syscalls/policy.h
@@ -39,7 +39,10 @@
#define ZX_POL_NEW_SOCKET 9u
#define ZX_POL_NEW_FIFO 10u
#define ZX_POL_NEW_TIMER 11u
-#define ZX_POL_MAX 12u
+#define ZX_POL_NEW_PROCESS 12u
+#ifdef _KERNEL
+#define ZX_POL_MAX 13u
+#endif
// Policy actions.
// ZX_POL_ACTION_ALLOW and ZX_POL_ACTION_DENY can be ORed with ZX_POL_ACTION_EXCEPTION.
diff --git a/system/utest/spawn/launcher.c b/system/utest/spawn/launcher.c
new file mode 100644
index 0000000..4c776ae
--- /dev/null
+++ b/system/utest/spawn/launcher.c
@@ -0,0 +1,32 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <launchpad/launchpad.h>
+#include <zircon/syscalls.h>
+#include <string.h>
+
+int main(int argc, const char* const* argv) {
+ launchpad_t* lp = NULL;
+ launchpad_create(ZX_HANDLE_INVALID, "launcher-child", &lp);
+ launchpad_load_from_file(lp, argv[1]);
+ launchpad_set_args(lp, argc - 1, argv + 1);
+ launchpad_clone(lp, LP_CLONE_ALL);
+
+ zx_handle_t process = ZX_HANDLE_INVALID;
+ zx_status_t status = launchpad_go(lp, &process, NULL);
+ if (status != ZX_OK)
+ return 401;
+
+ status = zx_object_wait_one(process, ZX_TASK_TERMINATED, ZX_TIME_INFINITE, NULL);
+ if (status != ZX_OK)
+ return status;
+
+ zx_info_process_t proc_info;
+ memset(&proc_info, 0, sizeof(proc_info));
+ status = zx_object_get_info(process, ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), NULL, NULL);
+ if (status != ZX_OK)
+ return status;
+
+ return proc_info.return_code;
+}
diff --git a/system/utest/spawn/rules.mk b/system/utest/spawn/rules.mk
index 4c9f3db..81c7341 100644
--- a/system/utest/spawn/rules.mk
+++ b/system/utest/spawn/rules.mk
@@ -21,9 +21,9 @@
system/ulib/zx \
MODULE_LIBS := \
- system/ulib/c \
system/ulib/fdio \
system/ulib/unittest \
+ system/ulib/c \
system/ulib/zircon \
include make/module.mk
@@ -43,8 +43,30 @@
$(LOCAL_DIR)/child.c \
MODULE_LIBS := \
- system/ulib/c \
system/ulib/fdio \
+ system/ulib/c \
+ system/ulib/zircon \
+
+include make/module.mk
+
+#
+# spawn-launcher
+#
+
+MODULE := $(LOCAL_DIR).launcher
+
+MODULE_TYPE := userapp
+MODULE_GROUP := test
+
+MODULE_NAME := spawn-launcher
+
+MODULE_SRCS := \
+ $(LOCAL_DIR)/launcher.c \
+
+MODULE_LIBS := \
+ system/ulib/launchpad \
+ system/ulib/fdio \
+ system/ulib/c \
system/ulib/zircon \
include make/module.mk
diff --git a/system/utest/spawn/spawn.cpp b/system/utest/spawn/spawn.cpp
index 6360964..f2a5558 100644
--- a/system/utest/spawn/spawn.cpp
+++ b/system/utest/spawn/spawn.cpp
@@ -16,8 +16,10 @@
#include <unistd.h>
#include <zircon/limits.h>
#include <zircon/processargs.h>
+#include <zircon/syscalls/policy.h>
static constexpr char kSpawnChild[] = "/boot/bin/spawn-child";
+static constexpr char kSpawnLauncher[] = "/boot/bin/spawn-launcher";
static bool has_fd(int fd) {
zx_handle_t handles[FDIO_MAX_HANDLES];
@@ -74,6 +76,47 @@
END_TEST;
}
+static bool spawn_launcher_test(void) {
+ BEGIN_TEST;
+
+ zx_status_t status;
+ zx::process process;
+ const char* argv[] = {kSpawnLauncher, kSpawnChild, nullptr};
+
+ // Check that we can spawn the lancher process in a job and that the
+ // launcher process can launch the child.
+ {
+ zx::job job;
+ ASSERT_EQ(ZX_OK, zx::job::create(zx_job_default(), 0, &job));
+
+ status = fdio_spawn(job.get(), FDIO_SPAWN_CLONE_ALL, kSpawnLauncher,
+ argv, process.reset_and_get_address());
+ ASSERT_EQ(ZX_OK, status);
+ EXPECT_EQ(43, join(process));
+ ASSERT_EQ(ZX_OK, job.kill());
+ }
+
+ // Check that setting |ZX_POL_NEW_PROCESS| to |ZX_POL_ACTION_DENY| prevents
+ // the launcher from launching the child.
+ {
+ zx::job job;
+ ASSERT_EQ(ZX_OK, zx::job::create(zx_job_default(), 0, &job));
+ zx_policy_basic_t policy = {
+ .condition = ZX_POL_NEW_PROCESS,
+ .policy = ZX_POL_ACTION_DENY,
+ };
+ ASSERT_EQ(ZX_OK, job.set_policy(ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1));
+
+ status = fdio_spawn(job.get(), FDIO_SPAWN_CLONE_ALL, kSpawnLauncher,
+ argv, process.reset_and_get_address());
+ ASSERT_EQ(ZX_OK, status);
+ EXPECT_EQ(401, join(process));
+ ASSERT_EQ(ZX_OK, job.kill());
+ }
+
+ END_TEST;
+}
+
static bool spawn_invalid_args_test(void) {
BEGIN_TEST;
@@ -550,6 +593,7 @@
BEGIN_TEST_CASE(spawn_tests)
RUN_TEST(spawn_control_test)
+RUN_TEST(spawn_launcher_test)
RUN_TEST(spawn_invalid_args_test)
RUN_TEST(spawn_flags_test)
RUN_TEST(spawn_environ_test)