From patchwork Wed Jan 30 12:41:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaroslav Kysela X-Patchwork-Id: 10788511 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A06576C2 for ; Wed, 30 Jan 2019 12:42:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B5622EB72 for ; Wed, 30 Jan 2019 12:42:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 893342EB7F; Wed, 30 Jan 2019 12:42:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8BDDA2EB72 for ; Wed, 30 Jan 2019 12:42:14 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 97E9C26799D; Wed, 30 Jan 2019 13:42:12 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9E42826745C; Wed, 30 Jan 2019 13:42:09 +0100 (CET) Received: from mail1.perex.cz (mail1.perex.cz [77.48.224.245]) by alsa0.perex.cz (Postfix) with ESMTP id BF3C726745C for ; Wed, 30 Jan 2019 13:42:07 +0100 (CET) Received: from mail1.perex.cz (localhost [127.0.0.1]) by smtp1.perex.cz (Perex's E-mail Delivery System) with ESMTP id A1695A003F; Wed, 30 Jan 2019 13:42:07 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.perex.cz A1695A003F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=perex.cz; s=default; t=1548852127; bh=B6S4adNa62/ODkSxJMwueYqVuqgqy0co1Fgplbd0GTo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bhte8xrLpBdpfUkqxvT3HYPRUgAyKqoLa+LMpZKezjjLVWcuHMRECGwMOVejpsrYS 4Jcj9IzqqBZrkUyS0eJ4Tr6ZH8bGRUo3lSou1xF9qQfNfXrI5/jWsES5Xz3k2PNftK fY8w6sfZ0JIuzJtcbc9ZNlaQ5cJe6MhO3mbJqaJ0= Received: from p50.perex-int.cz (unknown [192.168.100.94]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: perex) by mail1.perex.cz (Perex's E-mail Delivery System) with ESMTPSA; Wed, 30 Jan 2019 13:42:00 +0100 (CET) From: Jaroslav Kysela To: ALSA development Date: Wed, 30 Jan 2019 13:41:39 +0100 Message-Id: <20190130124139.10439-3-perex@perex.cz> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20190130124139.10439-1-perex@perex.cz> References: <20190130124139.10439-1-perex@perex.cz> Cc: Baolin Wang , Takashi Iwai , Phil Burk , Mark Brown , Leo Yan Subject: [alsa-devel] [PATCH 2/2] ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Create seven control bits to allow the various restrictions for the anonymous file descriptor. Signed-off-by: Jaroslav Kysela Reviewed-by: Takashi Iwai --- include/sound/pcm.h | 1 + include/uapi/sound/asound.h | 9 +++++ sound/core/pcm_native.c | 93 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 102 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 bb14658e4482..57512f7131f2 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; @@ -2894,10 +2895,11 @@ static int snd_pcm_anonymous_dup(struct file *file, int fd, err, perm, flags; struct file *nfile; struct snd_pcm *pcm = substream->pcm; + struct snd_pcm_file *pcm_file; if (get_user(perm, 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; @@ -2922,6 +2924,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, arg); return 0; } @@ -2933,6 +2937,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) @@ -2947,6 +3018,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; @@ -3108,6 +3182,8 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, substream = pcm_file->substream; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; + if (!(pcm_file->perm & SNDRV_PCM_PERM_RW)) + return -EPERM; runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -3132,6 +3208,8 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf, substream = pcm_file->substream; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; + if (!(pcm_file->perm & SNDRV_PCM_PERM_RW)) + return -EPERM; runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -3158,6 +3236,8 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) substream = pcm_file->substream; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; + if (!(pcm_file->perm & SNDRV_PCM_PERM_RW)) + return -EPERM; runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -3194,6 +3274,8 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) substream = pcm_file->substream; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; + if (!(pcm_file->perm & SNDRV_PCM_PERM_RW)) + return -EPERM; runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -3295,6 +3377,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; @@ -3331,6 +3416,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; @@ -3505,11 +3593,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;