2424#include <sound/minors.h>
2525#include <linux/uio.h>
2626#include <linux/delay.h>
27+ #include <linux/bitops.h>
2728
2829#include "pcm_local.h"
2930
@@ -3051,49 +3052,87 @@ static inline int snd_pcm_hwsync(struct snd_pcm_substream *substream)
30513052 return snd_pcm_delay (substream , NULL );
30523053}
30533054
3055+ #define snd_pcm_sync_ptr_get_user (__f , __c , __ptr ) ({ \
3056+ __label__ failed, failed_begin; \
3057+ int __err = -EFAULT; \
3058+ typeof(*(__ptr)) __user *__src = (__ptr); \
3059+ \
3060+ if (!user_read_access_begin(__src, sizeof(*__src))) \
3061+ goto failed_begin; \
3062+ unsafe_get_user(__f, &__src->flags, failed); \
3063+ unsafe_get_user(__c.appl_ptr, &__src->c.control.appl_ptr, failed); \
3064+ unsafe_get_user(__c.avail_min, &__src->c.control.avail_min, failed); \
3065+ __err = 0; \
3066+ failed: \
3067+ user_read_access_end(); \
3068+ failed_begin: \
3069+ __err; \
3070+ })
3071+
3072+ #define snd_pcm_sync_ptr_put_user (__s , __c , __ptr ) ({ \
3073+ __label__ failed, failed_begin; \
3074+ int __err = -EFAULT; \
3075+ typeof(*(__ptr)) __user *__src = (__ptr); \
3076+ \
3077+ if (!user_write_access_begin(__src, sizeof(*__src))) \
3078+ goto failed_begin; \
3079+ unsafe_put_user(__s.state, &__src->s.status.state, failed); \
3080+ unsafe_put_user(__s.hw_ptr, &__src->s.status.hw_ptr, failed); \
3081+ unsafe_put_user(__s.tstamp.tv_sec, &__src->s.status.tstamp.tv_sec, failed); \
3082+ unsafe_put_user(__s.tstamp.tv_nsec, &__src->s.status.tstamp.tv_nsec, failed); \
3083+ unsafe_put_user(__s.suspended_state, &__src->s.status.suspended_state, failed); \
3084+ unsafe_put_user(__s.audio_tstamp.tv_sec, &__src->s.status.audio_tstamp.tv_sec, failed); \
3085+ unsafe_put_user(__s.audio_tstamp.tv_nsec, &__src->s.status.audio_tstamp.tv_nsec, failed);\
3086+ unsafe_put_user(__c.appl_ptr, &__src->c.control.appl_ptr, failed); \
3087+ unsafe_put_user(__c.avail_min, &__src->c.control.avail_min, failed); \
3088+ __err = 0; \
3089+ failed: \
3090+ user_write_access_end(); \
3091+ failed_begin: \
3092+ __err; \
3093+ })
3094+
30543095static int snd_pcm_sync_ptr (struct snd_pcm_substream * substream ,
30553096 struct snd_pcm_sync_ptr __user * _sync_ptr )
30563097{
30573098 struct snd_pcm_runtime * runtime = substream -> runtime ;
3058- struct snd_pcm_sync_ptr sync_ptr ;
30593099 volatile struct snd_pcm_mmap_status * status ;
30603100 volatile struct snd_pcm_mmap_control * control ;
3101+ u32 sflags ;
3102+ struct snd_pcm_mmap_control scontrol ;
3103+ struct snd_pcm_mmap_status sstatus ;
30613104 int err ;
30623105
3063- memset (& sync_ptr , 0 , sizeof (sync_ptr ));
3064- if (get_user (sync_ptr .flags , (unsigned __user * )& (_sync_ptr -> flags )))
3106+ if (snd_pcm_sync_ptr_get_user (sflags , scontrol , _sync_ptr ))
30653107 return - EFAULT ;
3066- if (copy_from_user (& sync_ptr .c .control , & (_sync_ptr -> c .control ), sizeof (struct snd_pcm_mmap_control )))
3067- return - EFAULT ;
30683108 status = runtime -> status ;
30693109 control = runtime -> control ;
3070- if (sync_ptr . flags & SNDRV_PCM_SYNC_PTR_HWSYNC ) {
3110+ if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC ) {
30713111 err = snd_pcm_hwsync (substream );
30723112 if (err < 0 )
30733113 return err ;
30743114 }
30753115 scoped_guard (pcm_stream_lock_irq , substream ) {
3076- if (!(sync_ptr .flags & SNDRV_PCM_SYNC_PTR_APPL )) {
3077- err = pcm_lib_apply_appl_ptr (substream ,
3078- sync_ptr .c .control .appl_ptr );
3116+ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL )) {
3117+ err = pcm_lib_apply_appl_ptr (substream , scontrol .appl_ptr );
30793118 if (err < 0 )
30803119 return err ;
30813120 } else {
3082- sync_ptr . c . control .appl_ptr = control -> appl_ptr ;
3121+ scontrol .appl_ptr = control -> appl_ptr ;
30833122 }
3084- if (!(sync_ptr . flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN ))
3085- control -> avail_min = sync_ptr . c . control .avail_min ;
3123+ if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN ))
3124+ control -> avail_min = scontrol .avail_min ;
30863125 else
3087- sync_ptr . c . control .avail_min = control -> avail_min ;
3088- sync_ptr . s . status .state = status -> state ;
3089- sync_ptr . s . status .hw_ptr = status -> hw_ptr ;
3090- sync_ptr . s . status .tstamp = status -> tstamp ;
3091- sync_ptr . s . status .suspended_state = status -> suspended_state ;
3092- sync_ptr . s . status .audio_tstamp = status -> audio_tstamp ;
3126+ scontrol .avail_min = control -> avail_min ;
3127+ sstatus .state = status -> state ;
3128+ sstatus .hw_ptr = status -> hw_ptr ;
3129+ sstatus .tstamp = status -> tstamp ;
3130+ sstatus .suspended_state = status -> suspended_state ;
3131+ sstatus .audio_tstamp = status -> audio_tstamp ;
30933132 }
3094- if (!(sync_ptr . flags & SNDRV_PCM_SYNC_PTR_APPL ))
3133+ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL ))
30953134 snd_pcm_dma_buffer_sync (substream , SNDRV_DMA_SYNC_DEVICE );
3096- if (copy_to_user ( _sync_ptr , & sync_ptr , sizeof ( sync_ptr ) ))
3135+ if (snd_pcm_sync_ptr_put_user ( sstatus , scontrol , _sync_ptr ))
30973136 return - EFAULT ;
30983137 return 0 ;
30993138}
@@ -3102,11 +3141,9 @@ struct snd_pcm_mmap_status32 {
31023141 snd_pcm_state_t state ;
31033142 s32 pad1 ;
31043143 u32 hw_ptr ;
3105- s32 tstamp_sec ;
3106- s32 tstamp_nsec ;
3144+ struct __snd_timespec tstamp ;
31073145 snd_pcm_state_t suspended_state ;
3108- s32 audio_tstamp_sec ;
3109- s32 audio_tstamp_nsec ;
3146+ struct __snd_timespec audio_tstamp ;
31103147} __packed ;
31113148
31123149struct snd_pcm_mmap_control32 {
@@ -3130,13 +3167,23 @@ struct snd_pcm_sync_ptr32 {
31303167static snd_pcm_uframes_t recalculate_boundary (struct snd_pcm_runtime * runtime )
31313168{
31323169 snd_pcm_uframes_t boundary ;
3170+ snd_pcm_uframes_t border ;
3171+ int order ;
31333172
31343173 if (! runtime -> buffer_size )
31353174 return 0 ;
3136- boundary = runtime -> buffer_size ;
3137- while (boundary * 2 <= 0x7fffffffUL - runtime -> buffer_size )
3138- boundary *= 2 ;
3139- return boundary ;
3175+
3176+ border = 0x7fffffffUL - runtime -> buffer_size ;
3177+ if (runtime -> buffer_size > border )
3178+ return runtime -> buffer_size ;
3179+
3180+ order = __fls (border ) - __fls (runtime -> buffer_size );
3181+ boundary = runtime -> buffer_size << order ;
3182+
3183+ if (boundary <= border )
3184+ return boundary ;
3185+ else
3186+ return boundary / 2 ;
31403187}
31413188
31423189static int snd_pcm_ioctl_sync_ptr_compat (struct snd_pcm_substream * substream ,
@@ -3154,9 +3201,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
31543201 if (snd_BUG_ON (!runtime ))
31553202 return - EINVAL ;
31563203
3157- if (get_user (sflags , & src -> flags ) ||
3158- get_user (scontrol .appl_ptr , & src -> c .control .appl_ptr ) ||
3159- get_user (scontrol .avail_min , & src -> c .control .avail_min ))
3204+ if (snd_pcm_sync_ptr_get_user (sflags , scontrol , src ))
31603205 return - EFAULT ;
31613206 if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC ) {
31623207 err = snd_pcm_hwsync (substream );
@@ -3189,15 +3234,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
31893234 }
31903235 if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL ))
31913236 snd_pcm_dma_buffer_sync (substream , SNDRV_DMA_SYNC_DEVICE );
3192- if (put_user (sstatus .state , & src -> s .status .state ) ||
3193- put_user (sstatus .hw_ptr , & src -> s .status .hw_ptr ) ||
3194- put_user (sstatus .tstamp .tv_sec , & src -> s .status .tstamp_sec ) ||
3195- put_user (sstatus .tstamp .tv_nsec , & src -> s .status .tstamp_nsec ) ||
3196- put_user (sstatus .suspended_state , & src -> s .status .suspended_state ) ||
3197- put_user (sstatus .audio_tstamp .tv_sec , & src -> s .status .audio_tstamp_sec ) ||
3198- put_user (sstatus .audio_tstamp .tv_nsec , & src -> s .status .audio_tstamp_nsec ) ||
3199- put_user (scontrol .appl_ptr , & src -> c .control .appl_ptr ) ||
3200- put_user (scontrol .avail_min , & src -> c .control .avail_min ))
3237+ if (snd_pcm_sync_ptr_put_user (sstatus , scontrol , src ))
32013238 return - EFAULT ;
32023239
32033240 return 0 ;
0 commit comments