Hello,
Mikhail Karpov, le lun. 26 oct. 2026 00:27:41 +0700, a ecrit:
> diff --git a/console/console.c b/console/console.c
> index efc83da..7157588 100644
> --- a/console/console.c
> +++ b/console/console.c
> @@ -1234,6 +1234,7 @@ netfs_S_io_map (struct protid *cred,
>
> flags = cred->po->openstat & (O_READ | O_WRITE);
>
> + error_t err;
> pthread_mutex_lock (&np->lock);
> switch (flags)
> {
> @@ -1242,7 +1243,13 @@ netfs_S_io_map (struct protid *cred,
> VM_PROT_READ | VM_PROT_WRITE);
> if (*wrobj == MACH_PORT_NULL)
> goto error;
> - mach_port_mod_refs (mach_task_self (), *rdobj, MACH_PORT_RIGHT_SEND,
> 1);
> + err = mach_port_mod_refs (mach_task_self (), *rdobj,
> + MACH_PORT_RIGHT_SEND, 1);
> + if (err)
> + {
Before returning, *rdobj needs to be deallocate to drop the send right
taken by display_get_filemap, which is otherwise leaked.
> + pthread_mutex_unlock (&np->lock);
> + return err;
> + }
> break;
> case O_READ:
> *rdobj = display_get_filemap (vcons->display, VM_PROT_READ);
> diff --git a/libdiskfs/peropen-make.c b/libdiskfs/peropen-make.c
> index b4564a9..5b0f316 100644
> --- a/libdiskfs/peropen-make.c
> +++ b/libdiskfs/peropen-make.c
> po->shadow_root = context->shadow_root;
> if (po->shadow_root)
> @@ -69,8 +72,12 @@ diskfs_make_peropen (struct node *np, int flags, struct
> peropen *context,
>
> po->shadow_root_parent = context->shadow_root_parent;
> if (po->shadow_root_parent != MACH_PORT_NULL)
> - mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
> - MACH_PORT_RIGHT_SEND, 1);
> + {
> + err = mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
> + MACH_PORT_RIGHT_SEND, 1);
> + if (err)
> + goto free_path;
There is also the nref on po->shadow_root that needs to be released.
> diff --git a/libfshelp/translator-list.c b/libfshelp/translator-list.c
> index 6d4f941..6a42549 100644
> --- a/libfshelp/translator-list.c
> +++ b/libfshelp/translator-list.c
> @@ -147,8 +147,12 @@ fshelp_set_active_translator (struct port_info *pi,
>
> if (MACH_PORT_VALID (t->active))
> mach_port_deallocate (mach_task_self (), t->active);
> - mach_port_mod_refs (mach_task_self (), transbox->active,
> - MACH_PORT_RIGHT_SEND, +1);
> +
> + err = mach_port_mod_refs (mach_task_self (), transbox->active,
> + MACH_PORT_RIGHT_SEND, +1);
> + if (err)
> + goto out;
kMmm, we will have already modified stuff above. Better move
the mod_refs call above to avoid doing anything if the mod_refs
fails. Also, on mod_refs failure, we need to revert the
mach_port_request_notification() action.
> diff --git a/libnetfs/make-peropen.c b/libnetfs/make-peropen.c
> index 9bb4892..1ebe5ee 100644
> --- a/libnetfs/make-peropen.c
> +++ b/libnetfs/make-peropen.c
> @@ -75,11 +72,22 @@ netfs_make_peropen (struct node *np, int flags, struct
> peropen *context)
>
> po->shadow_root_parent = context->shadow_root_parent;
> if (po->shadow_root_parent != MACH_PORT_NULL)
> - mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
> - MACH_PORT_RIGHT_SEND, 1);
> + {
> + err = mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
> + MACH_PORT_RIGHT_SEND, 1);
> + if (err)
> + goto free_path;
Same here.
> diff --git a/libports/complete-deallocate.c b/libports/complete-deallocate.c
> index b7d5f76..a6fe0ee 100644
> --- a/libports/complete-deallocate.c
> +++ b/libports/complete-deallocate.c
> @@ -47,8 +47,9 @@ _ports_complete_deallocate (struct port_info *pi)
> refcounts_deref_weak (&pi->refcounts, &result);
> pthread_rwlock_unlock (&_ports_htable_lock);
>
> - mach_port_mod_refs (mach_task_self (), pi->port_right,
> - MACH_PORT_RIGHT_RECEIVE, -1);
> + error_t err = mach_port_mod_refs (mach_task_self (), pi->port_right,
> + MACH_PORT_RIGHT_RECEIVE, -1);
> + assert_perror_backtrace (err);
Yes, that's not supposed to fail.
> diff --git a/libshouldbeinlibc/exec-reauth.c b/libshouldbeinlibc/exec-reauth.c
> index b830f22..c04fe05 100644
> --- a/libshouldbeinlibc/exec-reauth.c
> +++ b/libshouldbeinlibc/exec-reauth.c
> @@ -59,25 +59,29 @@ exec_reauth (auth_t auth, int secure, int must_reauth,
> if (!err)
> err = auth_user_authenticate (auth, ref, MACH_MSG_TYPE_MAKE_SEND,
> &newport);
> - mach_port_mod_refs (mach_task_self (), ref, MACH_PORT_RIGHT_RECEIVE,
> -1);
> - /* If they gave us nothing, make sure not to proceed. */
> - if (!err && newport == MACH_PORT_NULL)
> - err = KERN_INVALID_ARGUMENT;
> + error_t refs_err = mach_port_mod_refs (mach_task_self (), ref,
> + MACH_PORT_RIGHT_RECEIVE, -1);
Here as well, that's not supposed to fail, better abort than trying to
fix up things, we're very screwed anyway if things went that badly that
we don't even have a receive right to drop.
> diff --git a/libshouldbeinlibc/portxlate.c b/libshouldbeinlibc/portxlate.c
> index eb6abfb..2ff8b7a 100644
> --- a/libshouldbeinlibc/portxlate.c
> +++ b/libshouldbeinlibc/portxlate.c
> @@ -30,55 +30,53 @@ port_name_xlator_create (mach_port_t from_task,
> mach_port_t to_task,
> struct port_name_xlator **xlator)
> {
> error_t err;
> - struct port_name_xlator *x = malloc (sizeof (struct port_name_xlator));
> + struct port_name_xlator *x = calloc (1, sizeof (struct port_name_xlator));
>
> if (! x)
> - return ENOMEM;
> + return errno;
> +
> + err = mach_port_mod_refs (mach_task_self (), from_task,
> + MACH_PORT_RIGHT_SEND, +1);
> + if (err)
> + goto error;
>
> - mach_port_mod_refs (mach_task_self (), from_task, MACH_PORT_RIGHT_SEND,
> +1);
> x->from_task = from_task;
> - mach_port_mod_refs (mach_task_self (), to_task, MACH_PORT_RIGHT_SEND, +1);
> + err = mach_port_mod_refs (mach_task_self (), to_task,
> + MACH_PORT_RIGHT_SEND, +1);
> + if (err)
Here you need to deallocate from_task.
> diff --git a/libstore/unknown.c b/libstore/unknown.c
> index 624c184..058285c 100644
> --- a/libstore/unknown.c
> +++ b/libstore/unknown.c
> @@ -60,10 +60,7 @@ noflags (struct store *store, int flags)
> static struct store_enc *
> duplicate_encoding (struct store_enc *enc)
> {
> - struct store_enc *us;
> - size_t i;
> -
> - us = calloc (1, sizeof *us);
> + struct store_enc *us = calloc (1, sizeof *us);
> if (us == NULL)
> return NULL;
>
> @@ -98,9 +95,14 @@ duplicate_encoding (struct store_enc *enc)
> us->num_offsets = enc->num_offsets;
> us->data_len = enc->data_len;
>
> - for (i = 0; i < us->num_ports; ++i)
> - mach_port_mod_refs (mach_task_self (), us->ports[i],
> - MACH_PORT_RIGHT_SEND, +1);
> + error_t err;
> + for (size_t i = 0; i < us->num_ports; ++i)
> + {
> + err = mach_port_mod_refs (mach_task_self (), us->ports[i],
> + MACH_PORT_RIGHT_SEND, +1);
> + if (err)
> + goto no_memory;
store_enc_dealloc needs to properly deallocate only the first part of
the ports of the array. You can memset to NULL the rest of the array for
instance.
> diff --git a/proc/host.c b/proc/host.c
> index adda74d..9d3f204 100644
> --- a/proc/host.c
> +++ b/proc/host.c
> @@ -139,7 +139,6 @@ S_proc_getexecdata (struct proc *p,
> int **ints,
> mach_msg_type_number_t *nints)
> {
> - int i;
> int ports_allocated = 0;
> /* No need to check P here; we don't use it. */
>
> @@ -151,28 +150,45 @@ S_proc_getexecdata (struct proc *p,
> *ports = mmap (0, round_page (n_std_ports * sizeof (mach_port_t)),
> PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
> if (*ports == MAP_FAILED)
> - return ENOMEM;
> + return errno;
> ports_allocated = 1;
> }
> memcpy (*ports, std_port_array, n_std_ports * sizeof (mach_port_t));
> *nports = n_std_ports;
>
> + error_t err;
> + int ints_allocated = 0;
> if (*nints < n_std_ints)
> {
> *ints = mmap (0, round_page (n_std_ints * sizeof (int)),
> PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
> if (*ints == MAP_FAILED)
> {
> + err = errno;
> if (ports_allocated)
> munmap (*ports, round_page (n_std_ports * sizeof (mach_port_t)));
> - return ENOMEM;
> + return err;
> }
> +
> + ints_allocated = 1;
> }
> memcpy (*ints, std_int_array, n_std_ints * sizeof (int));
> *nints = n_std_ints;
>
> - for (i = 0; i < n_std_ports; i++)
> - mach_port_mod_refs (mach_task_self (), std_port_array[i],
> MACH_PORT_RIGHT_SEND, 1);
> + for (int i = 0; i < n_std_ports; i++)
> + {
> + err = mach_port_mod_refs (mach_task_self (), std_port_array[i],
> + MACH_PORT_RIGHT_SEND, 1);
> + if (err)
> + {
You also need to deallocate the first part of the ports of the array.
> + if (ports_allocated)
> + munmap (*ports, round_page (n_std_ports * sizeof (mach_port_t)));
> + if (ints_allocated)
> + munmap (*ints, round_page (n_std_ints * sizeof (int)));
> + return err;
It's worth factorizing this with error labels.
> diff --git a/proc/mgt.c b/proc/mgt.c
> index 8223bf5..18ee1e5 100644
> --- a/proc/mgt.c
> +++ b/proc/mgt.c
> @@ -283,8 +283,12 @@ S_proc_child (struct proc *parentp,
>
> if (MACH_PORT_VALID (parentp->p_task_namespace))
> {
> - mach_port_mod_refs (mach_task_self (), parentp->p_task_namespace,
> - MACH_PORT_RIGHT_SEND, +1);
> + error_t err = mach_port_mod_refs (mach_task_self (),
> + parentp->p_task_namespace,
> + MACH_PORT_RIGHT_SEND, +1);
> + if (err)
> + return err;
That's very late for returning an error... We'd want to move that up to
avoid doing anything on error.
> @@ -1386,19 +1390,25 @@ S_mach_notify_new_task (struct port_info *notify,
> if (! parentp)
> return ESRCH;
>
> + error_t err;
> childp = task_find_nocreate (task);
> if (! childp)
> {
> - mach_port_mod_refs (mach_task_self (), task, MACH_PORT_RIGHT_SEND, +1);
> + err = mach_port_mod_refs (mach_task_self (), task,
> + MACH_PORT_RIGHT_SEND, +1);
> + if (err)
> + return err;
> +
> childp = new_proc (task);
> }
>
> if (MACH_PORT_VALID (parentp->p_task_namespace))
> {
> - error_t err;
> /* Tasks in a task namespace are not expected to call
> proc_child, so we do it on their behalf. */
> - mach_port_mod_refs (mach_task_self (), task, MACH_PORT_RIGHT_SEND, +1);
> + err = mach_port_mod_refs (mach_task_self (), task,
> + MACH_PORT_RIGHT_SEND, +1);
> + assert_perror_backtrace (err);
No, it's fine to return an error, we can still do it at this point (just
need to deallocate on task if the mod_refs was done above).
> err = S_proc_child (parentp, task);
> assert_perror_backtrace (err);
That however is really not supposed to happen, thus the assertion.
> diff --git a/proc/pgrp.c b/proc/pgrp.c
> index e2b497e..81129c2 100644
> --- a/proc/pgrp.c
> +++ b/proc/pgrp.c
> @@ -116,7 +120,17 @@ S_proc_setsid (struct proc *p)
> leave_pgrp (p);
>
> sess = new_session (p);
> - p->p_pgrp= new_pgrp (p->p_pid, sess);
> + if (!sess)
> + return errno;
> +
> + p->p_pgrp = new_pgrp (p->p_pid, sess);
> + if (!p->p_pgrp)
Those are again too late, move them up so we don't leave_pgrp if we
error out actually.
I have applied the rest, thanks!
Samuel