Re: [PATCH] ALSA: pcm: reconstruct compat appl_ptr in SYNC_PTR ioctl
From: Cássio Gabriel
Date: Sat Mar 21 2026 - 01:20:44 EST
On Thu, Mar 19, 2026 at 01:23:40AM -0300, Cássio Gabriel wrote:
> The compat SYNC_PTR ioctl exposes appl_ptr and hw_ptr in a reduced
> 32-bit boundary domain. However, when compat user space passes appl_ptr
> back to the kernel, the value is currently fed to pcm_lib_apply_appl_ptr()
> as if it were already in the native runtime->boundary domain.
>
> This leaves the compat SYNC_PTR path asymmetric: appl_ptr is exported to
> compat user space modulo the compat boundary, but the value written back
> is not reconstructed in the native boundary domain before being applied.
>
> The mismatch becomes visible after appl_ptr wraps in the compat
> boundary. At that point, compat user space sends a small appl_ptr value
> again, but the kernel may interpret it as a different native appl_ptr
> position instead of the nearest congruent position around the current
> control->appl_ptr.
>
> Fix this by reconstructing the compat appl_ptr in the native runtime
> boundary before passing it to pcm_lib_apply_appl_ptr().
>
> Signed-off-by: Cássio Gabriel <cassiogabrielcontato@xxxxxxxxx>
> ---
> sound/core/pcm_native.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 46 insertions(+), 4 deletions(-)
>
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index 674b50c7c5f6..f2e2854847ae 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -3228,6 +3228,45 @@ static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
> return boundary / 2;
> }
>
> +/*
> + * Reconstruct the nearest native appl_ptr for a compat appl_ptr
> + * value modulo compat_boundary.
> + */
> +static snd_pcm_uframes_t
> +snd_pcm_compat_reconstruct_appl_ptr(struct snd_pcm_runtime *runtime,
> + snd_pcm_uframes_t compat_boundary,
> + u32 appl_ptr)
> +{
> + snd_pcm_uframes_t cur = runtime->control->appl_ptr;
> + snd_pcm_sframes_t rel; /* relative offset */
> + snd_pcm_sframes_t new_appl_ptr;
> +
> + if (!compat_boundary || compat_boundary >= runtime->boundary)
> + return appl_ptr;
> +
> + appl_ptr %= compat_boundary;
> + rel = (snd_pcm_sframes_t)appl_ptr -
> + (snd_pcm_sframes_t)(cur % compat_boundary);
> +
> + /*
> + * Pick the shortest relative distance in the compat ring so the
> + * reconstructed native appl_ptr stays nearest to the current
> + * position.
> + */
> + if (rel > (snd_pcm_sframes_t)(compat_boundary / 2))
> + rel -= compat_boundary;
> + else if (rel < -(snd_pcm_sframes_t)(compat_boundary / 2))
> + rel += compat_boundary;
> +
> + new_appl_ptr = (snd_pcm_sframes_t)cur + rel;
> + if (new_appl_ptr < 0)
> + new_appl_ptr += runtime->boundary;
> + else if ((snd_pcm_uframes_t)new_appl_ptr >= runtime->boundary)
> + new_appl_ptr -= runtime->boundary;
> +
> + return (snd_pcm_uframes_t)new_appl_ptr;
> +}
> +
> static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
> struct snd_pcm_sync_ptr32 __user *src)
> {
> @@ -3253,13 +3292,16 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
> status = runtime->status;
> control = runtime->control;
> boundary = recalculate_boundary(runtime);
> - if (! boundary)
> + if (!boundary)
> boundary = 0x7fffffff;
> scoped_guard(pcm_stream_lock_irq, substream) {
> - /* FIXME: we should consider the boundary for the sync from app */
> if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
> - err = pcm_lib_apply_appl_ptr(substream,
> - scontrol.appl_ptr);
> + err = pcm_lib_apply_appl_ptr
> + (substream,
> + snd_pcm_compat_reconstruct_appl_ptr
> + (runtime,
> + boundary,
> + scontrol.appl_ptr));
> if (err < 0)
> return err;
> } else
>
> ---
> base-commit: b3c48fa1fb397b490101785ddd87caf2e5513a66
> change-id: 20260318-alsa-pcm-compat-syncptr-boundary-0d52d2f8dc7e
>
> Best regards,
> --
> Cássio Gabriel <cassiogabrielcontato@xxxxxxxxx>
>
Please disregard this patch.
After further analysis, I concluded that the supported 32-bit
compat flow already handles the boundary correctly.
Although native PCM setup creates a large runtime->boundary on
64-bit kernels, the HW_PARAMS32 compat path reduces it to a
compat-safe value, and the SYNC_PTR32 path passes appl_ptr
through pcm_lib_apply_appl_ptr(), which already rejects values
greater than or equal to runtime->boundary.
So, in practice, the compat sync-from-user path already accounts
for the reduced boundary correctly.