[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[hurd] 16/28: boot: Allow unprivileged users to boot Subhurds.
From: |
Samuel Thibault |
Subject: |
[hurd] 16/28: boot: Allow unprivileged users to boot Subhurds. |
Date: |
Wed, 16 Nov 2016 08:30:27 +0000 |
This is an automated email from the git hooks/post-receive script.
sthibault pushed a commit to branch upstream
in repository hurd.
commit 8c0e65b6b2db9946153ed736e66d4e613875deb6
Author: Justus Winter <address@hidden>
Date: Sun Oct 23 11:48:06 2016 +0200
boot: Allow unprivileged users to boot Subhurds.
Previously, boot handed privileged kernel ports to Subhurds. This
made boot unusable for unprivileged users, and allowed Subhurds to
wreak havoc on the whole system. Fix this by handing out pseudo ports
instead of the privileged ports.
* NEWS: Update.
* boot/Makefile (MIGSTUBS): Build stubs for the new kernel interfaces.
(MIGSFLAGS): Include mutation file.
(HURDLIBS): Link against libihash.
* boot/boot.c (privileged, want_privileged): New variables.
(pseudo_privileged_host_port): New variable.
(pseudo_pset, pseudo_kernel): Likewise.
(task_notification_port): Likewise.
(dead_task_notification_port): Likewise.
(boot_demuxer): Handle new protocols.
(OPT_PRIVILEGED): New macro.
(options): Add flag '--privileged' to enable the old mode.
(parse_opt): Handle new flag.
(allocate_pseudo_ports): New function.
(main): Handle new flag. If not running privileged, allocate more
pseudo ports to hand out in place of privileged kernel ports, create a
task namespace, and a task that the Subhurd can frob instead of the
real kernel task.
(do_mach_notify_dead_name): Handle dying tasks.
(S_vm_set_default_memory_manager): New function.
(S_host_reboot): Likewise.
(S_host_processor_set_priv): Likewise.
(S_register_new_task_notification): Likewise.
(task_ihash_cleanup): Likewise.
(task_ihash): New variable.
(task_died): New function.
(S_mach_notify_new_task): Likewise.
(S_processor_set_tasks): Likewise.
* boot/mig-decls.h: New file.
* boot/mig-mutate.h: Likewise.
---
NEWS | 5 +
boot/Makefile | 10 +-
boot/boot.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
boot/mig-decls.h | 27 ++++++
boot/mig-mutate.h | 25 +++++
5 files changed, 337 insertions(+), 12 deletions(-)
diff --git a/NEWS b/NEWS
index e9c4cb5..486cb2d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Version 0.9 (2016-11-XX)
+
+The 'boot' program can now be run as unprivileged user, allowing any
+user to create unprivileged Subhurds.
+
Version 0.8 (2016-05-18)
The netfs library is using the lockless reference-counting primitives
diff --git a/boot/Makefile b/boot/Makefile
index 38a8c69..ac40044 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -23,12 +23,12 @@ SRCS = mach-crt0.c boot.c ux.c sigvec.S syscall.S \
COMMON-OBJS = notifyServer.o deviceServer.o \
ioServer.o io_replyUser.o device_replyUser.o \
termServer.o boot_script.o userland-boot.o
-OBJS = boot.o $(COMMON-OBJS)
+MIGSTUBS = machServer.o mach_hostServer.o gnumachServer.o task_notifyServer.o
+OBJS = boot.o $(COMMON-OBJS) $(MIGSTUBS)
target = boot
-io-MIGSFLAGS=-DREPLY_PORTS
-HURDLIBS = store shouldbeinlibc
+MIGSFLAGS=-imacros $(srcdir)/mig-mutate.h -DHURD_DEFAULT_PAYLOAD_TO_PORT=1
+io-MIGSFLAGS=-DREPLY_PORTS -DHURD_DEFAULT_PAYLOAD_TO_PORT=1
+HURDLIBS = store shouldbeinlibc ihash
LDLIBS += -lpthread
include ../Makeconf
-
-MIGSFLAGS = -DHURD_DEFAULT_PAYLOAD_TO_PORT=1
diff --git a/boot/boot.c b/boot/boot.c
index ab9c164..1cc94bc 100644
--- a/boot/boot.c
+++ b/boot/boot.c
@@ -1,6 +1,6 @@
/* Load a task using the single server, and then run it
as if we were the kernel.
- Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,2006
+ Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,2006,14,16
Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -26,6 +26,7 @@
#include <device/device.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
+#include <mach/task_notify.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -35,6 +36,8 @@
#include <mach/default_pager.h>
#include <argp.h>
#include <hurd/store.h>
+#include <hurd/ihash.h>
+#include <sys/reboot.h>
#include <sys/mman.h>
#include <version.h>
@@ -46,6 +49,10 @@
#include "term_S.h"
#include "bootstrap_S.h"
/* #include "tioctl_S.h" */
+#include "mach_S.h"
+#include "mach_host_S.h"
+#include "gnumach_S.h"
+#include "task_notify_S.h"
#include "boot_script.h"
@@ -61,6 +68,14 @@
#include <hurd.h>
#include <assert.h>
+/* We support two modes of operation. Traditionally, Subhurds were
+ privileged, i.e. they had the privileged kernel ports. This has a
+ few drawbacks. Privileged subhurds can manipulate all tasks on the
+ system and halt the system. Nowadays we allow an unprivileged
+ mode. */
+static int privileged;
+static int want_privileged;
+
static struct termios orig_tty_state;
static int isig;
static char *kernel_command_line;
@@ -99,9 +114,14 @@ host_exit (int status)
}
mach_port_t privileged_host_port, master_device_port;
+mach_port_t pseudo_privileged_host_port;
mach_port_t pseudo_master_device_port;
mach_port_t receive_set;
mach_port_t pseudo_console, pseudo_root, pseudo_time;
+mach_port_t pseudo_pset;
+task_t pseudo_kernel;
+mach_port_t task_notification_port;
+mach_port_t dead_task_notification_port;
auth_t authserver;
struct store *root_store;
@@ -177,7 +197,11 @@ boot_demuxer (mach_msg_header_t *inp,
if ((routine = io_server_routine (inp)) ||
(routine = device_server_routine (inp)) ||
(routine = notify_server_routine (inp)) ||
- (routine = term_server_routine (inp))
+ (routine = term_server_routine (inp)) ||
+ (routine = mach_server_routine (inp)) ||
+ (routine = mach_host_server_routine (inp)) ||
+ (routine = gnumach_server_routine (inp)) ||
+ (routine = task_notify_server_routine (inp))
/* (routine = tioctl_server_routine (inp)) */)
{
(*routine) (inp, outp);
@@ -192,6 +216,8 @@ void * msg_thread (void *);
const char *argp_program_version = STANDARD_HURD_VERSION (boot);
+#define OPT_PRIVILEGED -1
+
static struct argp_option options[] =
{
{ "boot-root", 'D', "DIR", 0,
@@ -206,6 +232,8 @@ static struct argp_option options[] =
"Do not disable terminal signals, so you can suspend and interrupt boot."},
{ "device", 'f', "device_name=device_file", 0,
"Specify a device file used by subhurd and its virtual name."},
+ { "privileged", OPT_PRIVILEGED, NULL, 0,
+ "Allow the subhurd to access privileged kernel ports"},
{ 0 }
};
static char args_doc[] = "BOOT-SCRIPT";
@@ -277,6 +305,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
add_dev_map (arg, dev_file+1);
break;
+ case OPT_PRIVILEGED:
+ want_privileged = 1;
+ break;
+
case ARGP_KEY_ARG:
if (state->arg_num == 0)
bootscript = arg;
@@ -293,6 +325,55 @@ parse_opt (int key, char *arg, struct argp_state *state)
return 0;
}
+static error_t
+allocate_pseudo_ports (void)
+{
+ mach_port_t old;
+
+ /* Allocate a port that we hand out as the privileged host port. */
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &pseudo_privileged_host_port);
+ mach_port_insert_right (mach_task_self (),
+ pseudo_privileged_host_port,
+ pseudo_privileged_host_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ mach_port_move_member (mach_task_self (), pseudo_privileged_host_port,
+ receive_set);
+ mach_port_request_notification (mach_task_self (),
+ pseudo_privileged_host_port,
+ MACH_NOTIFY_NO_SENDERS, 1,
+ pseudo_privileged_host_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+ assert (old == MACH_PORT_NULL);
+
+ /* Allocate a port that we hand out as the privileged processor set
+ port. */
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &pseudo_pset);
+ mach_port_move_member (mach_task_self (), pseudo_pset,
+ receive_set);
+ /* Make one send right that we copy when handing it out. */
+ mach_port_insert_right (mach_task_self (),
+ pseudo_pset,
+ pseudo_pset,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+ /* We will receive new task notifications on this port. */
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &task_notification_port);
+ mach_port_move_member (mach_task_self (), task_notification_port,
+ receive_set);
+
+ /* And information about dying tasks here. */
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &dead_task_notification_port);
+ mach_port_move_member (mach_task_self (), dead_task_notification_port,
+ receive_set);
+
+ return 0;
+}
+
+
int
main (int argc, char **argv, char **envp)
{
@@ -315,16 +396,26 @@ main (int argc, char **argv, char **envp)
if (err)
error (4, err, "%s", root_store_name);
- get_privileged_ports (&privileged_host_port, &master_device_port);
+ if (want_privileged)
+ {
+ get_privileged_ports (&privileged_host_port, &master_device_port);
+ privileged = MACH_PORT_VALID (master_device_port);
+
+ if (! privileged)
+ error (1, 0, "Must be run as root for privileged subhurds");
+ }
- strcat (bootstrap_args, "f");
+ if (privileged)
+ strcat (bootstrap_args, "f");
mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
&receive_set);
if (root_store->class == &store_device_class && root_store->name
&& (root_store->flags & STORE_ENFORCED)
- && root_store->num_runs == 1 && root_store->runs[0].start == 0)
+ && root_store->num_runs == 1
+ && root_store->runs[0].start == 0
+ && privileged)
/* Let known device nodes pass through directly. */
bootdevice = root_store->name;
else
@@ -369,13 +460,33 @@ main (int argc, char **argv, char **envp)
if (foo != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self (), foo);
+ if (! privileged)
+ {
+ err = allocate_pseudo_ports ();
+ if (err)
+ error (1, err, "Allocating pseudo ports");
+
+ /* Create a new task namespace for us. */
+ err = proc_make_task_namespace (getproc (), task_notification_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (err)
+ error (1, err, "proc_make_task_namespace");
+
+ /* Create an empty task that the subhurds can freely frobnicate. */
+ err = task_create (mach_task_self (), 0, &pseudo_kernel);
+ if (err)
+ error (1, err, "task_create");
+ }
+
if (kernel_command_line == 0)
asprintf (&kernel_command_line, "%s %s root=%s",
argv[0], bootstrap_args, bootdevice);
/* Initialize boot script variables. */
if (boot_script_set_variable ("host-port", VAL_PORT,
- (int) privileged_host_port)
+ privileged
+ ? (int) privileged_host_port
+ : (int) pseudo_privileged_host_port)
|| boot_script_set_variable ("device-port", VAL_PORT,
(integer_t) pseudo_master_device_port)
|| boot_script_set_variable ("kernel-command-line", VAL_STR,
@@ -1115,6 +1226,8 @@ do_mach_notify_send_once (mach_port_t notify)
return EOPNOTSUPP;
}
+static void task_died (mach_port_t name);
+
kern_return_t
do_mach_notify_dead_name (mach_port_t notify,
mach_port_t name)
@@ -1123,7 +1236,11 @@ do_mach_notify_dead_name (mach_port_t notify,
if (name == child_task && notify == bootport)
host_exit (0);
#endif
- return EOPNOTSUPP;
+ if (notify != dead_task_notification_port)
+ return EOPNOTSUPP;
+ task_died (name);
+ mach_port_deallocate (mach_task_self (), name);
+ return 0;
}
@@ -1389,6 +1506,8 @@ S_io_reauthenticate (mach_port_t object,
size_t gulen = 0, aulen = 0, gglen = 0, aglen = 0;
error_t err;
+ /* XXX: This cannot possibly work, authserver is 0. */
+
err = mach_port_insert_right (mach_task_self (), object, object,
MACH_MSG_TYPE_MAKE_SEND);
assert_perror (err);
@@ -1681,3 +1800,152 @@ kern_return_t S_term_on_pty
io_t *ptymaster
)
{ return EOPNOTSUPP; }
+
+/* Mach host emulation. */
+
+kern_return_t
+S_vm_set_default_memory_manager (mach_port_t host_priv,
+ mach_port_t *default_manager)
+{
+ if (host_priv != pseudo_privileged_host_port)
+ return KERN_INVALID_HOST;
+
+ if (*default_manager != MACH_PORT_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ *default_manager = MACH_PORT_NULL;
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+S_host_reboot (mach_port_t host_priv,
+ int flags)
+{
+ fprintf (stderr, "Would %s the system. Bye.\n",
+ flags & RB_HALT? "halt": "reboot");
+ host_exit (0);
+}
+
+
+kern_return_t
+S_host_processor_set_priv (mach_port_t host_priv,
+ mach_port_t set_name,
+ mach_port_t *set)
+{
+ if (host_priv != pseudo_privileged_host_port)
+ return KERN_INVALID_HOST;
+
+ *set = pseudo_pset;
+ return KERN_SUCCESS;
+}
+
+mach_port_t new_task_notification;
+
+kern_return_t
+S_register_new_task_notification (mach_port_t host_priv,
+ mach_port_t notification)
+{
+ if (host_priv != pseudo_privileged_host_port)
+ return KERN_INVALID_HOST;
+
+ if (! MACH_PORT_VALID (notification))
+ return KERN_INVALID_ARGUMENT;
+
+ if (MACH_PORT_VALID (new_task_notification))
+ return KERN_NO_ACCESS;
+
+ new_task_notification = notification;
+ return KERN_SUCCESS;
+}
+
+
+/* Managing tasks. */
+
+static void
+task_ihash_cleanup (hurd_ihash_value_t value, void *cookie)
+{
+ (void) cookie;
+ mach_port_deallocate (mach_task_self (), (mach_port_t) value);
+}
+
+static struct hurd_ihash task_ihash =
+ HURD_IHASH_INITIALIZER_GKI (HURD_IHASH_NO_LOCP, task_ihash_cleanup, NULL,
+ NULL, NULL);
+
+static void
+task_died (mach_port_t name)
+{
+ hurd_ihash_remove (&task_ihash, (hurd_ihash_key_t) name);
+}
+
+/* Handle new task notifications from proc. */
+error_t
+S_mach_notify_new_task (mach_port_t notify,
+ mach_port_t task,
+ mach_port_t parent)
+{
+ error_t err;
+ mach_port_t previous;
+
+ if (notify != task_notification_port)
+ return EOPNOTSUPP;
+
+ err = mach_port_request_notification (mach_task_self (), task,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ dead_task_notification_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &previous);
+ if (err)
+ goto fail;
+ assert (! MACH_PORT_VALID (previous));
+
+ err = hurd_ihash_add (&task_ihash,
+ (hurd_ihash_key_t) task, (hurd_ihash_value_t) task);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ goto fail;
+ }
+
+ if (MACH_PORT_VALID (new_task_notification))
+ /* Relay the notification. */
+ mach_notify_new_task (new_task_notification, task, parent);
+
+ mach_port_deallocate (mach_task_self (), parent);
+ return 0;
+
+ fail:
+ task_terminate (task);
+ return err;
+}
+
+kern_return_t
+S_processor_set_tasks(mach_port_t processor_set,
+ task_array_t *task_list,
+ mach_msg_type_number_t *task_listCnt)
+{
+ error_t err;
+ size_t i;
+
+ err = vm_allocate (mach_task_self (), (vm_address_t *) task_list,
+ task_ihash.nr_items * sizeof **task_list, 1);
+ if (err)
+ return err;
+
+ /* The first task has to be the kernel. */
+ (*task_list)[0] = pseudo_kernel;
+
+ i = 1;
+ HURD_IHASH_ITERATE (&task_ihash, value)
+ {
+ task_t task = (task_t) value;
+ if (task == pseudo_kernel)
+ continue;
+
+ (*task_list)[i] = task;
+ i += 1;
+ }
+
+ *task_listCnt = task_ihash.nr_items;
+ return 0;
+}
diff --git a/boot/mig-decls.h b/boot/mig-decls.h
new file mode 100644
index 0000000..d539659
--- /dev/null
+++ b/boot/mig-decls.h
@@ -0,0 +1,27 @@
+/*
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Written by Justus Winter.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __BOOT_MIG_DECLS_H__
+#define __BOOT_MIG_DECLS_H__
+
+#include <hurd.h>
+
+#define MIG_EOPNOTSUPP EOPNOTSUPP
+
+#endif /* __BOOT_MIG_DECLS_H__ */
diff --git a/boot/mig-mutate.h b/boot/mig-mutate.h
new file mode 100644
index 0000000..ef90b73
--- /dev/null
+++ b/boot/mig-mutate.h
@@ -0,0 +1,25 @@
+/*
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Written by Justus Winter.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#define MACH_IMPORTS \
+ import "mig-decls.h";
+#define MACH_HOST_IMPORTS \
+ import "mig-decls.h";
+#define GNUMACH_IMPORTS \
+ import "mig-decls.h";
--
Alioth's /usr/local/bin/git-commit-notice on
/srv/git.debian.org/git/pkg-hurd/hurd.git
- [hurd] 11/28: startup: Dump processes if we cannot find the kernel., (continued)
- [hurd] 11/28: startup: Dump processes if we cannot find the kernel., Samuel Thibault, 2016/11/16
- [hurd] 03/28: Fix typo, Samuel Thibault, 2016/11/16
- [hurd] 12/28: boot: Use the smallest possible name when inserting rights., Samuel Thibault, 2016/11/16
- [hurd] 15/28: boot: restore terminal state on exit, Samuel Thibault, 2016/11/16
- [hurd] 18/28: boot: Tidy up the argument parser., Samuel Thibault, 2016/11/16
- [hurd] 24/28: eth-multiplexer: Avoid local definitions., Samuel Thibault, 2016/11/16
- [hurd] 28/28: libpager: fix returning error on data_unlock, Samuel Thibault, 2016/11/16
- [hurd] 08/28: proc: Fix new task notifications., Samuel Thibault, 2016/11/16
- [hurd] 19/28: Adjust to the fixed new task notifications., Samuel Thibault, 2016/11/16
- [hurd] 22/28: eth-multiplexer: Fix packet delivery., Samuel Thibault, 2016/11/16
- [hurd] 16/28: boot: Allow unprivileged users to boot Subhurds.,
Samuel Thibault <=
- [hurd] 17/28: boot: Add a default boot script., Samuel Thibault, 2016/11/16
- [hurd] 10/28: Add missing spinlock initializers, Samuel Thibault, 2016/11/16
- [hurd] 23/28: eth-multiplexer: Fix retrieving status of virtual interfaces., Samuel Thibault, 2016/11/16
- [hurd] 26/28: boot: Improve device pass-through., Samuel Thibault, 2016/11/16
- [hurd] 25/28: eth-multiplexer: Generate stable ethernet addresses., Samuel Thibault, 2016/11/16
- [hurd] 05/28: Mark library stubs as weak, Samuel Thibault, 2016/11/16
- [hurd] 13/28: boot: Quote arguments containing spaces., Samuel Thibault, 2016/11/16
- [hurd] 09/28: boot: Remove hacks for running boot on UX., Samuel Thibault, 2016/11/16
- [hurd] 27/28: mach-defpager: Fix daemonization., Samuel Thibault, 2016/11/16
- [hurd] 07/28: libdiskfs: Factorize code for last hard reference being released, Samuel Thibault, 2016/11/16