Hello everyone,
Da Zheng wrote:
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 created a proxy for all RPCs on the master host port, modified the
code of proc so that proc can ignore the error of task_priority (the
problem in proc as I mention in my previous letter).
However, there is still a problem in proc:
The function add_tasks (proc/mgt.c) gets all tasks in the host by
calling host_processor_sets(), host_processor_set_priv() and
processor_set_tasks() because the process server needs to check if the
port is a task port or not.
Obviously, the process server in the subhurd cannot get all tasks in the
host. Instead, it should only get the tasks that belong to the subhurd.
I am thinking of a way to trace tasks in subhurd.
One way I can think of is that boot creates a proxy for the RPC
task_create. As a result, boot needs to create pseudo task ports for all
tasks in subhurd and run as a proxy for all RPCs on the task port. Extra
RPCs are needed for the tasks to get the pseudo task ports, and
mach_task_self() in glibc need to be modified.
This solution should be powerful enough (it can solve all problems I
have got so far) as long as all programs in subhurd uses the modified
mach_task_self() in glibc.
But it has two drawback:
1. There isn't an effective way to prevent the programs in subhurd
calling the system trap mach_task_self(). If the program does use the
system trap, it might not have the right behavior, but at least it
doesn't harm the tasks in main Hurd and other subhurds.
2. It seems a bit heavy. Almost all of RPCs to the kernel are redirected
to the boot.
Anyone has comments for the solution I suggested above?
I hope there is an easier way in Mach/Hurd to trace tasks.
Best regards,
Zheng Da