On Sun, Dec 22, 2024 at 1:45 PM Samuel Thibault <samuel.thiba...@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