Re: [PATCH] dlm: validate userspace lock resource name length

Alexander Aring <[email protected]> Thu, 16 Jul 2026 14:23:59 -0400
Newsgroups dev.linux.lists.gfs2,org.kernel.vger.linux-kernel
Message-ID <CAK-6q+hf8X9g+hiPC5A3n4rr1C=vWjakB4tU-sRFQHEL9finMg@mail.gmail.com>
Hi,

On Mon, Jun 8, 2026 at 8:16=E2=80=AFPM Samuel Moelius
<[email protected]> wrote:
>
> The DLM userspace device accepts a flexible resource name after
> `struct dlm_write_request`.  `device_write()` bounded the total write
> size, but did not verify that `i.lock.namelen` was covered by the bytes
> actually supplied by the write.
>
> A short `DLM_USER_LOCK` request can therefore claim a full
> `DLM_RESNAME_MAXLEN` resource name while providing no name bytes.  The
> request path later hashes and copies the claimed name length, reading
> past the `memdup_user_nul()` allocation.
>
> Reject non-conversion lock requests whose claimed resource name length
> exceeds the flexible name payload supplied with the write.  Valid lock
> requests with complete names are unchanged.  Track the payload length
> before compat conversion so 32-bit requests keep using their own request
> header size.
>
> Assisted-by: Codex:gpt-5.5-cyber-preview
> Signed-off-by: Samuel Moelius <[email protected]>

Acked-by: Alexander Aring <[email protected]>

> ---
>  fs/dlm/user.c | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>
> diff --git a/fs/dlm/user.c b/fs/dlm/user.c
> index a8ed4c8fdc5b..205364329ce3 100644
> --- a/fs/dlm/user.c
> +++ b/fs/dlm/user.c
> @@ -511,6 +511,7 @@ static ssize_t device_write(struct file *file, const =
char __user *buf,
>                             size_t count, loff_t *ppos)
>  {
>         struct dlm_user_proc *proc =3D file->private_data;
> +       size_t name_payload =3D 0;
>         struct dlm_write_request *kbuf;
>         int error;
>
> @@ -544,6 +545,7 @@ static ssize_t device_write(struct file *file, const =
char __user *buf,
>
>                 if (count > sizeof(struct dlm_write_request32))
>                         namelen =3D count - sizeof(struct dlm_write_reque=
st32);
> +               name_payload =3D namelen;
>
>                 k32buf =3D (struct dlm_write_request32 *)kbuf;
>
> @@ -560,7 +562,13 @@ static ssize_t device_write(struct file *file, const=
 char __user *buf,
>
>                 compat_input(kbuf, k32buf, namelen);
>                 kfree(k32buf);
> +       } else {
> +               if (count > sizeof(*kbuf))
> +                       name_payload =3D count - sizeof(*kbuf);
>         }
> +#else
> +       if (count > sizeof(*kbuf))
> +               name_payload =3D count - sizeof(*kbuf);
>  #endif
>
>         /* do we really need this? can a write happen after a close? */
> @@ -570,6 +578,15 @@ static ssize_t device_write(struct file *file, const=
 char __user *buf,
>                 goto out_free;
>         }
>
> +       if (kbuf->cmd =3D=3D DLM_USER_LOCK &&
> +           !(kbuf->i.lock.flags & DLM_LKF_CONVERT)) {
> +               if (kbuf->i.lock.namelen > name_payload ||
> +                   kbuf->i.lock.namelen > DLM_RESNAME_MAXLEN) {

there is later a check in "set_lock_args" to do a "if (!(flags &
DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN))" check.
However there is a trace call in between that can access this array
out of bounds area if namelen is above DLM_RESNAME_MAXLEN.

I will add a cleanup patch to my list to check for "sane" parameters
as soon as they are known...

- Alex