Hello everyone,
I am trying to make subhurd run without root's permission.
AFAIK, the reason that subhurd needs the root's permission is that the
subhurd needs the master device port and privileged host port, and the
current implementation gets the real ones from mach.
It's relatively easy to handle the master device port and boot has
already done part of the work (it gives the subhurd a pseudo master
device port and acts as a device proxy itself). The device proxy can
access some real devices with the help of other translators. As long as
the user has the permission to access the device file, it should work fine.
However, the same method cannot apply to the privileged host port.
As I understand, the privileged host port is used to communicate with
the kernel and manipulate the host. Again I can give the subhurd a
pseudo one, create a host proxy, and implement the server side of RPC.
The RPCs directly involved to the privileged host port are:
routine vm_set_default_memory_manager(
host_priv : host_priv_t;
inout default_manager : mach_port_make_send_t);
hurd/boot/boot.c <<main>>
hurd/libdiskfs/init-init.c <<diskfs_init_diskfs>>
hurd/mach-defpager/main.c <<main>>
hurd/serverboot/default_pager.c <<default_pager_initialize>>
hurd/sutils/swapon.c <<swaponoff>>
hurd/tmpfs/tmpfs.c <<main>>
hurd/trans/proxy-defpager.c <<main>>
hurd/utils/vmstat.c <<ensure_def_pager_info>>
routine host_adjust_time(
host_priv : host_priv_t;
in new_adjustment : time_value_t;
out old_adjustment : time_value_t);
routine host_get_boot_info(
host_priv : host_priv_t;
out boot_info : kernel_boot_info_t);
routine host_reboot(
host_priv : host_priv_t;
options : int);
hurd/init/init.c
hurd/serverboot/bootstrap.c
hurd/serverboot/panic.c
routine host_set_time(
host_priv : host_priv_t;
new_time : time_value_t);
routine host_processors(
host_priv : host_priv_t;
out processor_list : processor_array_t);
routine host_processor_set_priv(
host_priv : host_priv_t;
set_name : processor_set_name_t;
out set : processor_set_t);
hurd/proc/main.c,
hurd/proc/mgt.c
routine vm_wire(
host_priv : host_priv_t;
task : vm_task_t;
address : vm_address_t;
size : vm_size_t;
access : vm_prot_t);
hurd/libshouldbeinlibc/wire.c
hurd/serverboot/wiring.c
routine thread_wire(
host_priv : host_priv_t;
thread : thread_t;
wired : boolean_t);
hurd/serverboot/wiring.c
I list all routines and the place where they are called in Hurd below them.
Note: several of them are not used by Hurd.
The problem here is host_processor_set_priv, which converts a processor
set name port to a control port.
proc gets the control port with host_processor_set_priv, but instead of
calling an RPC to this port, it calls an RPC to its thread port and uses
this port as a parameter, so the host proxy cannot get the RPC. The host
proxy cannot return a real control port, either, because it doesn't has
the root permission. The code in proc/main.c (shown below) will fail for
sure:
err = host_processor_set_priv (master_host_port, pset, &psetcntl);
assert_perror (err);
thread_max_priority (mach_thread_self (), psetcntl, 0);
assert_perror (err);
err = task_priority (mach_task_self (), 2, 1);
assert_perror (err);
A simple solution might be to modify the code of proc since it is the
only place having this problem.
For a long run, it might not be a good idea. It might limit the ability
of subhurd and I don't know if more similar code will be used in the
future Hurd.
The other solution is to give pseudo task ports and thread ports to the
subhurd, so boot can receive all RPCs from subhurd (which should go to
the kernel). Now boot can get the full control of subhurd (it might give
subhurd more features even though I don't know yet). The problem I
mentioned above can be solved easily. However, this solution needs more
work and makes the things more complicated. I wonder if it is worth the
work.
The more important question is how to give pseudo task ports and thread
ports.
mach_thread_self () and mach_task_self () are system trap.
Maybe I can modify the implementation of mach_thread_self () and
mach_task_self () in glibc and use an RPC to ask boot for the ports, but
then every task has to know the port to boot. It needs much work and
seems quite ugly.
I wonder if there is a better solution to get the pseudo task and thread
port from boot, or even a better solution to solve the problem caused by
host_processor_set_priv.
By the way, how are mach_thread_self () and mach_task_self ()
implemented in glibc (at least, how does glibc wrap these two system
calls)?
I see the implementation of mach_task_self (), but it's quite weird.
In mach/mach_init.h, there is
extern mach_port_t __mach_task_self_;
#define __mach_task_self() (__mach_task_self_ + 0) /* Not an
lvalue. */
#define mach_task_self() (__mach_task_self ())
In mach/mach_init.c, there is
void
__mach_init (void)
{
kern_return_t err;
__mach_task_self_ = (__mach_task_self) ();
...
I am totally confused by the code. If I find the right code, then
__mach_task_self_ is always 0.
Thank you very much.
Zheng Da