Re: [PATCH] ipc/util.c: sysvipc_find_ipc() incorrectly updates position index

From: Andrew Morton
Date: Thu May 07 2020 - 20:02:45 EST


On Wed, 6 May 2020 09:25:54 +0300 Vasily Averin <vvs@xxxxxxxxxxxxx> wrote:

> new_pos should jump through hole of unused ids,
> pos can be updated inside "for" cycle.
>
> Cc: stable@xxxxxxxxxxxxxxx
> Fixes: 89163f93c6f9 ("ipc/util.c: sysvipc_find_ipc() should increase position index")

This:

> --- a/ipc/util.c
> +++ b/ipc/util.c
> @@ -764,21 +764,21 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
> total++;
> }
>
> - *new_pos = pos + 1;
> + ipc = NULL;
> if (total >= ids->in_use)
> - return NULL;
> + goto out;
>
> for (; pos < ipc_mni; pos++) {
> ipc = idr_find(&ids->ipcs_idr, pos);
> if (ipc != NULL) {
> rcu_read_lock();
> ipc_lock_object(ipc);
> - return ipc;
> + break;
> }
> }
> -
> - /* Out of range - return NULL to terminate iteration */
> - return NULL;
> +out:
> + *new_pos = pos + 1;
> + return ipc;
> }
>
> static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)

Messes up Matthew's "ipc: convert ipcs_idr to XArray"
(http://lkml.kernel.org/r/20200326151418.27545-1-willy@xxxxxxxxxxxxx).

Here's how I resolved things. Please check?

static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
loff_t *new_pos)
{
unsigned long index = pos;
struct kern_ipc_perm *ipc;

rcu_read_lock();
ipc = xa_find(&ids->ipcs, &index, ULONG_MAX, XA_PRESENT);
if (ipc)
ipc_lock_object(ipc);
else
rcu_read_unlock();
*new_pos = pos + 1;
return ipc;
}