[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC] Implementing RLIMIT_AS
From: |
Sergey Bugaev |
Subject: |
Re: [RFC] Implementing RLIMIT_AS |
Date: |
Mon, 23 Dec 2024 09:35:43 +0300 |
On Sun, Dec 22, 2024 at 1:45 PM Samuel Thibault <samuel.thibault@gnu.org> wrote:
> > FWIW, this means that the caller would be potentially sending the host
> > priv port to someone who's not necessarily the kernel. That's fine if
> > we're acting on mach_task_self (since if someone is interposing our
> > task port, we can trust them), but not fine if we're a privileged
> > server who's willing to raise the given task's memory allowance
> > according to some policy.
>
> Task ports are created only by task_create, so only managed by gnumach.
> Privileges servers do trust that their task ports are indeed from that.
What I meant is imagine you have
routine foo_server_raise_memory_size_limit (reqport: foo_server_t;
task: task_t; desired_limit: vm_size_t);
error_t
S_foo_server_raise_memory_size_limit (... reqport, task_t task,
vm_size_t desired_limit)
{
error_t err;
if (/* some permission or policy checks */)
return EACCESS;
err = vm_set_size_limit (task, host_priv, desired_limit);
if (!err)
mach_port_deallocate (mach_task_self (), task);
return err;
}
then if 'task' was not a real task port, we've sent the host priv port
to someone.
You can of course be careful to never write servers that do that, but
a good practice is to design APIs so that they're harder to misuse in
the first place. This means only using the host priv port as a message
destination, unless we explicitly mean to send it in a message (like
proc_getprivports). I don't remember seeing an RPC so far that
would've done it differently. So we should either have two RPCs:
routine vm_limit_size (task: vm_task_t; limit: vm_size_t);
routine vm_increase_size_limit (host_priv: host_priv_t; task:
vm_task_t; limit: vm_size_t);
or we could have a single routine that accepts either the host or host
priv port, but it would require some more ceremony to check which one,
perhaps like this:
routine vm_set_size_limit (host: mach_port_t; target_task: task_t;
limit: vm_size_t);
kern_return_t vm_set_size_limit(
const ipc_port_t host_port,
vm_map_t map,
vm_size_t limit)
{
ipc_kobject_type_t ikot_host = IKOT_NONE;
if (!IP_VALID(host_port))
return(KERN_INVALID_HOST);
ip_lock(host_port);
if (ip_active(port))
ikot_host = ip_kotype(host_port);
ip_unlock(host_port);
if (ikot_host != IKOT_HOST && ikot_host != IKOT_HOST_PRIV)
return(KERN_INVALID_HOST);
if (map == VM_MAP_NULL)
return(KERN_INVALID_ARGUMENT);
vm_map_lock(map);
/*
* Must pass the host priv port to increase the limit.
*/
if (limit > map->size_limit && ikot_host != IKOT_HOST_PRIV) {
vm_map_unlock(map);
return(KERN_INVALID_HOST);
}
...
}
Sergey