Message ID | 20190130084733.979-3-perex@perex.cz (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ALSA: pcm: implement the anonymous dup v2 | expand |
On Wed, 30 Jan 2019 09:47:33 +0100, Jaroslav Kysela wrote: > > Create seven control bits to allow the various restrictions for the > anonymous file descriptor. > > Signed-off-by: Jaroslav Kysela <perex@perex.cz> I think we need to check SNDRV_PCM_PERM_RW for read/write ops, too. Other than that, looks good to me. Reviewed-by: Takashi Iwai <tiwai@suse.de> thanks, Takashi > --- > include/sound/pcm.h | 1 + > include/uapi/sound/asound.h | 9 +++++ > sound/core/pcm_native.c | 85 ++++++++++++++++++++++++++++++++++++++++++++- > 3 files changed, 94 insertions(+), 1 deletion(-) > > diff --git a/include/sound/pcm.h b/include/sound/pcm.h > index b79ffaa0241d..e0469b2c1115 100644 > --- a/include/sound/pcm.h > +++ b/include/sound/pcm.h > @@ -227,6 +227,7 @@ struct snd_pcm_ops { > struct snd_pcm_file { > struct snd_pcm_substream *substream; > int no_compat_mmap; > + unsigned int perm; /* file descriptor permissions */ > unsigned int user_pversion; /* supported protocol version */ > }; > > diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h > index ebc17d5a3490..8d99aa8916f0 100644 > --- a/include/uapi/sound/asound.h > +++ b/include/uapi/sound/asound.h > @@ -571,6 +571,15 @@ enum { > #define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) > #define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) > > +#define SNDRV_PCM_PERM_MMAP (1<<0) > +#define SNDRV_PCM_PERM_MMAP_STATUS (1<<1) > +#define SNDRV_PCM_PERM_MMAP_CONTROL (1<<2) > +#define SNDRV_PCM_PERM_RW (1<<3) > +#define SNDRV_PCM_PERM_CONTROL (1<<4) > +#define SNDRV_PCM_PERM_STATUS (1<<5) > +#define SNDRV_PCM_PERM_SYNC (1<<6) > +#define SNDRV_PCM_PERM_MASK ((SNDRV_PCM_PERM_SYNC<<1)-1) > + > #define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) > #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) > #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) > diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c > index 8874a685f1e8..0fceed62b839 100644 > --- a/sound/core/pcm_native.c > +++ b/sound/core/pcm_native.c > @@ -2502,6 +2502,7 @@ static int snd_pcm_open_file(struct file *file, > return -ENOMEM; > } > pcm_file->substream = substream; > + pcm_file->perm = ~0; > if (substream->ref_count == 1) > substream->pcm_release = pcm_release_private; > file->private_data = pcm_file; > @@ -2897,10 +2898,11 @@ static int snd_pcm_anonymous_dup(struct file *file, > int flags; > struct file *nfile; > struct snd_pcm *pcm = substream->pcm; > + struct snd_pcm_file *pcm_file; > > if (get_user(perm, (int __user *)arg)) > return -EFAULT; > - if (perm < 0) > + if (perm & ~SNDRV_PCM_PERM_MASK) > return -EPERM; > flags = file->f_flags & (O_ACCMODE | O_NONBLOCK); > flags |= O_APPEND | O_CLOEXEC; > @@ -2925,6 +2927,8 @@ static int snd_pcm_anonymous_dup(struct file *file, > err = snd_pcm_open_file(nfile, substream->pcm, > substream->stream, substream->number); > if (err >= 0) { > + pcm_file = nfile->private_data; > + pcm_file->perm = perm; > put_user(fd, (int __user *)arg); > return 0; > } > @@ -2936,6 +2940,73 @@ static int snd_pcm_anonymous_dup(struct file *file, > return err; > } > > +static int snd_pcm_ioctl_check_perm(struct snd_pcm_file *pcm_file, > + unsigned int cmd) > +{ > + if (pcm_file->perm == ~0) > + return 1; > + /* > + * the setup, linking and anonymous dup is not allowed > + * for the restricted file descriptors > + */ > + switch (cmd) { > + case SNDRV_PCM_IOCTL_PVERSION: > + case SNDRV_PCM_IOCTL_INFO: > + case SNDRV_PCM_IOCTL_USER_PVERSION: > + case SNDRV_PCM_IOCTL_CHANNEL_INFO: > + return 1; > + } > + if (pcm_file->perm & SNDRV_PCM_PERM_CONTROL) { > + switch (cmd) { > + case SNDRV_PCM_IOCTL_PREPARE: > + case SNDRV_PCM_IOCTL_RESET: > + case SNDRV_PCM_IOCTL_START: > + case SNDRV_PCM_IOCTL_XRUN: > + case SNDRV_PCM_IOCTL_RESUME: > + case SNDRV_PCM_IOCTL_DRAIN: > + case SNDRV_PCM_IOCTL_DROP: > + case SNDRV_PCM_IOCTL_PAUSE: > + return 1; > + default: > + break; > + } > + } > + if (pcm_file->perm & SNDRV_PCM_PERM_STATUS) { > + switch (cmd) { > + case SNDRV_PCM_IOCTL_STATUS: > + case SNDRV_PCM_IOCTL_STATUS_EXT: > + case SNDRV_PCM_IOCTL_DELAY: > + return 1; > + default: > + break; > + } > + } > + if (pcm_file->perm & SNDRV_PCM_PERM_SYNC) { > + switch (cmd) { > + case SNDRV_PCM_IOCTL_HWSYNC: > + case SNDRV_PCM_IOCTL_SYNC_PTR: > + case SNDRV_PCM_IOCTL_REWIND: > + case SNDRV_PCM_IOCTL_FORWARD: > + return 1; > + default: > + break; > + } > + } > + if (pcm_file->perm & SNDRV_PCM_PERM_RW) { > + switch (cmd) { > + case SNDRV_PCM_IOCTL_WRITEI_FRAMES: > + case SNDRV_PCM_IOCTL_READI_FRAMES: > + case SNDRV_PCM_IOCTL_WRITEN_FRAMES: > + case SNDRV_PCM_IOCTL_READN_FRAMES: > + return 1; > + default: > + break; > + } > + } > + > + return 0; > +} > + > static int snd_pcm_common_ioctl(struct file *file, > struct snd_pcm_substream *substream, > unsigned int cmd, void __user *arg) > @@ -2950,6 +3021,9 @@ static int snd_pcm_common_ioctl(struct file *file, > if (res < 0) > return res; > > + if (!snd_pcm_ioctl_check_perm(pcm_file, cmd)) > + return -EPERM; > + > switch (cmd) { > case SNDRV_PCM_IOCTL_PVERSION: > return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; > @@ -3298,6 +3372,9 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file > struct vm_area_struct *area) > { > long size; > + struct snd_pcm_file *pcm_file = file->private_data; > + if (!(pcm_file->perm & SNDRV_PCM_PERM_MMAP_STATUS)) > + return -EPERM; > if (!(area->vm_flags & VM_READ)) > return -EINVAL; > size = area->vm_end - area->vm_start; > @@ -3334,6 +3411,9 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file > struct vm_area_struct *area) > { > long size; > + struct snd_pcm_file *pcm_file = file->private_data; > + if (!(pcm_file->perm & SNDRV_PCM_PERM_MMAP_CONTROL)) > + return -EPERM; > if (!(area->vm_flags & VM_READ)) > return -EINVAL; > size = area->vm_end - area->vm_start; > @@ -3508,11 +3588,14 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, > struct vm_area_struct *area) > { > struct snd_pcm_runtime *runtime; > + struct snd_pcm_file *pcm_file = file->private_data; > long size; > unsigned long offset; > size_t dma_bytes; > int err; > > + if (!(pcm_file->perm & SNDRV_PCM_PERM_MMAP)) > + return -EPERM; > if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { > if (!(area->vm_flags & (VM_WRITE|VM_READ))) > return -EINVAL; > -- > 2.13.6 > _______________________________________________ > Alsa-devel mailing list > Alsa-devel@alsa-project.org > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel > o
Dne 30.1.2019 v 12:27 Takashi Iwai napsal(a): > On Wed, 30 Jan 2019 09:47:33 +0100, > Jaroslav Kysela wrote: >> >> Create seven control bits to allow the various restrictions for the >> anonymous file descriptor. >> >> Signed-off-by: Jaroslav Kysela <perex@perex.cz> > > I think we need to check SNDRV_PCM_PERM_RW for read/write ops, too. Yes, it will be in v3. Thanks for the review. Jaroslav
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index b79ffaa0241d..e0469b2c1115 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -227,6 +227,7 @@ struct snd_pcm_ops { struct snd_pcm_file { struct snd_pcm_substream *substream; int no_compat_mmap; + unsigned int perm; /* file descriptor permissions */ unsigned int user_pversion; /* supported protocol version */ }; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index ebc17d5a3490..8d99aa8916f0 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -571,6 +571,15 @@ enum { #define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) #define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) +#define SNDRV_PCM_PERM_MMAP (1<<0) +#define SNDRV_PCM_PERM_MMAP_STATUS (1<<1) +#define SNDRV_PCM_PERM_MMAP_CONTROL (1<<2) +#define SNDRV_PCM_PERM_RW (1<<3) +#define SNDRV_PCM_PERM_CONTROL (1<<4) +#define SNDRV_PCM_PERM_STATUS (1<<5) +#define SNDRV_PCM_PERM_SYNC (1<<6) +#define SNDRV_PCM_PERM_MASK ((SNDRV_PCM_PERM_SYNC<<1)-1) + #define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8874a685f1e8..0fceed62b839 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2502,6 +2502,7 @@ static int snd_pcm_open_file(struct file *file, return -ENOMEM; } pcm_file->substream = substream; + pcm_file->perm = ~0; if (substream->ref_count == 1) substream->pcm_release = pcm_release_private; file->private_data = pcm_file; @@ -2897,10 +2898,11 @@ static int snd_pcm_anonymous_dup(struct file *file, int flags; struct file *nfile; struct snd_pcm *pcm = substream->pcm; + struct snd_pcm_file *pcm_file; if (get_user(perm, (int __user *)arg)) return -EFAULT; - if (perm < 0) + if (perm & ~SNDRV_PCM_PERM_MASK) return -EPERM; flags = file->f_flags & (O_ACCMODE | O_NONBLOCK); flags |= O_APPEND | O_CLOEXEC; @@ -2925,6 +2927,8 @@ static int snd_pcm_anonymous_dup(struct file *file, err = snd_pcm_open_file(nfile, substream->pcm, substream->stream, substream->number); if (err >= 0) { + pcm_file = nfile->private_data; + pcm_file->perm = perm; put_user(fd, (int __user *)arg); return 0; } @@ -2936,6 +2940,73 @@ static int snd_pcm_anonymous_dup(struct file *file, return err; } +static int snd_pcm_ioctl_check_perm(struct snd_pcm_file *pcm_file, + unsigned int cmd) +{ + if (pcm_file->perm == ~0) + return 1; + /* + * the setup, linking and anonymous dup is not allowed + * for the restricted file descriptors + */ + switch (cmd) { + case SNDRV_PCM_IOCTL_PVERSION: + case SNDRV_PCM_IOCTL_INFO: + case SNDRV_PCM_IOCTL_USER_PVERSION: + case SNDRV_PCM_IOCTL_CHANNEL_INFO: + return 1; + } + if (pcm_file->perm & SNDRV_PCM_PERM_CONTROL) { + switch (cmd) { + case SNDRV_PCM_IOCTL_PREPARE: + case SNDRV_PCM_IOCTL_RESET: + case SNDRV_PCM_IOCTL_START: + case SNDRV_PCM_IOCTL_XRUN: + case SNDRV_PCM_IOCTL_RESUME: + case SNDRV_PCM_IOCTL_DRAIN: + case SNDRV_PCM_IOCTL_DROP: + case SNDRV_PCM_IOCTL_PAUSE: + return 1; + default: + break; + } + } + if (pcm_file->perm & SNDRV_PCM_PERM_STATUS) { + switch (cmd) { + case SNDRV_PCM_IOCTL_STATUS: + case SNDRV_PCM_IOCTL_STATUS_EXT: + case SNDRV_PCM_IOCTL_DELAY: + return 1; + default: + break; + } + } + if (pcm_file->perm & SNDRV_PCM_PERM_SYNC) { + switch (cmd) { + case SNDRV_PCM_IOCTL_HWSYNC: + case SNDRV_PCM_IOCTL_SYNC_PTR: + case SNDRV_PCM_IOCTL_REWIND: + case SNDRV_PCM_IOCTL_FORWARD: + return 1; + default: + break; + } + } + if (pcm_file->perm & SNDRV_PCM_PERM_RW) { + switch (cmd) { + case SNDRV_PCM_IOCTL_WRITEI_FRAMES: + case SNDRV_PCM_IOCTL_READI_FRAMES: + case SNDRV_PCM_IOCTL_WRITEN_FRAMES: + case SNDRV_PCM_IOCTL_READN_FRAMES: + return 1; + default: + break; + } + } + + return 0; +} + static int snd_pcm_common_ioctl(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) @@ -2950,6 +3021,9 @@ static int snd_pcm_common_ioctl(struct file *file, if (res < 0) return res; + if (!snd_pcm_ioctl_check_perm(pcm_file, cmd)) + return -EPERM; + switch (cmd) { case SNDRV_PCM_IOCTL_PVERSION: return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; @@ -3298,6 +3372,9 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file struct vm_area_struct *area) { long size; + struct snd_pcm_file *pcm_file = file->private_data; + if (!(pcm_file->perm & SNDRV_PCM_PERM_MMAP_STATUS)) + return -EPERM; if (!(area->vm_flags & VM_READ)) return -EINVAL; size = area->vm_end - area->vm_start; @@ -3334,6 +3411,9 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file struct vm_area_struct *area) { long size; + struct snd_pcm_file *pcm_file = file->private_data; + if (!(pcm_file->perm & SNDRV_PCM_PERM_MMAP_CONTROL)) + return -EPERM; if (!(area->vm_flags & VM_READ)) return -EINVAL; size = area->vm_end - area->vm_start; @@ -3508,11 +3588,14 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) { struct snd_pcm_runtime *runtime; + struct snd_pcm_file *pcm_file = file->private_data; long size; unsigned long offset; size_t dma_bytes; int err; + if (!(pcm_file->perm & SNDRV_PCM_PERM_MMAP)) + return -EPERM; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!(area->vm_flags & (VM_WRITE|VM_READ))) return -EINVAL;
Create seven control bits to allow the various restrictions for the anonymous file descriptor. Signed-off-by: Jaroslav Kysela <perex@perex.cz> --- include/sound/pcm.h | 1 + include/uapi/sound/asound.h | 9 +++++ sound/core/pcm_native.c | 85 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 1 deletion(-)