All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] ALSA: pcm: implement the anonymous dup
@ 2019-01-29 17:59 Jaroslav Kysela
  2019-01-29 17:59 ` [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor) Jaroslav Kysela
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Jaroslav Kysela @ 2019-01-29 17:59 UTC (permalink / raw)
  To: ALSA development; +Cc: Takashi Iwai, Mark Brown, Baolin Wang, Leo Yan

This patchset contains the anonymous dup implementation with permissions
checking for the ALSA's PCM interface in kernel to enable the restricted
DMA sound buffer sharing for the restricted tasks.

The code was tested through qemu and it seems to be pretty stable.

The initial tinyalsa implementation can be found here:

  https://github.com/perexg/tinyalsa/commits/anondup

The filtering might be refined. It depends on the real requirements.
Perhaps, we may create more ioctl groups. Any comments are more than
welcome.

Cc: Mark Brown <broonie@kernel.org>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Baolin Wang <baolin.wang@linaro.org>

Jaroslav Kysela (3):
  ALSA: pcm: implement the anonymous dup (inode file descriptor)
  ALSA: pcm: remove the file member from struct pcm
  ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup

 include/sound/pcm.h         |  10 +--
 include/uapi/sound/asound.h |  12 +++-
 sound/core/oss/pcm_oss.c    |   3 +-
 sound/core/pcm.c            |  48 +++++++++-----
 sound/core/pcm_compat.c     |   1 +
 sound/core/pcm_native.c     | 154 +++++++++++++++++++++++++++++++++++++++++---
 6 files changed, 195 insertions(+), 33 deletions(-)

-- 
2.13.6

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor)
  2019-01-29 17:59 [PATCH 0/3] ALSA: pcm: implement the anonymous dup Jaroslav Kysela
@ 2019-01-29 17:59 ` Jaroslav Kysela
  2019-01-29 18:44   ` Takashi Iwai
  2019-01-29 17:59 ` [PATCH 2/3] ALSA: pcm: remove the file member from struct pcm Jaroslav Kysela
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Jaroslav Kysela @ 2019-01-29 17:59 UTC (permalink / raw)
  To: ALSA development; +Cc: Takashi Iwai, Mark Brown, Baolin Wang, Leo Yan

This patch implements new SNDRV_PCM_IOCTL_ANONYMOUS_DUP ioctl which
returns the new duplicated anonymous inode file descriptor
(anon_inode:snd-pcm) which can be passed to the restricted clients.

This patch is meant to be the alternative for the dma-buf interface. Both
implementation have some pros and cons:

anon_inode:dmabuf

- a bit standard export API for the DMA buffers
- fencing for the concurrent access [1]
- driver/kernel interface for the DMA buffer [1]
- multiple attach/detach scheme [1]

[1] the real usage for the sound PCM is unknown at the moment for this feature

anon_inode:snd-pcm

- simple (no problem with ref-counting, non-standard mmap implementation etc.)
- allow to use more sound interfaces for the file descriptor like status ioctls
- more fine grained security policies (another anon_inode name unshared with
  other drivers)
---
 include/sound/pcm.h         |  8 +++---
 include/uapi/sound/asound.h |  3 +-
 sound/core/oss/pcm_oss.c    |  2 +-
 sound/core/pcm.c            | 48 ++++++++++++++++++++------------
 sound/core/pcm_compat.c     |  1 +
 sound/core/pcm_native.c     | 67 +++++++++++++++++++++++++++++++++++++++++----
 6 files changed, 101 insertions(+), 28 deletions(-)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 2c30c1ad1b0d..e7deb03b6702 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -590,11 +590,11 @@ static inline int snd_pcm_suspend_all(struct snd_pcm *pcm)
 }
 #endif
 int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
-int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file,
-			   struct snd_pcm_substream **rsubstream);
+int snd_pcm_open_substream(struct snd_pcm *pcm, struct snd_pcm_substream *clone,
+			   int stream, struct file *file, struct snd_pcm_substream **rsubstream);
 void snd_pcm_release_substream(struct snd_pcm_substream *substream);
-int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file,
-			     struct snd_pcm_substream **rsubstream);
+int snd_pcm_attach_substream(struct snd_pcm *pcm, struct snd_pcm_substream *clone, int stream,
+			     struct file *file, struct snd_pcm_substream **rsubstream);
 void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
 int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
 
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 404d4b9ffe76..ebc17d5a3490 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -153,7 +153,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 14)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 15)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -576,6 +576,7 @@ enum {
 #define SNDRV_PCM_IOCTL_TSTAMP		_IOW('A', 0x02, int)
 #define SNDRV_PCM_IOCTL_TTSTAMP		_IOW('A', 0x03, int)
 #define SNDRV_PCM_IOCTL_USER_PVERSION	_IOW('A', 0x04, int)
+#define SNDRV_PCM_IOCTL_ANONYMOUS_DUP   _IOWR('A', 0x05, int)
 #define SNDRV_PCM_IOCTL_HW_REFINE	_IOWR('A', 0x10, struct snd_pcm_hw_params)
 #define SNDRV_PCM_IOCTL_HW_PARAMS	_IOWR('A', 0x11, struct snd_pcm_hw_params)
 #define SNDRV_PCM_IOCTL_HW_FREE		_IO('A', 0x12)
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 467039b342b5..b3738c228f39 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2420,7 +2420,7 @@ static int snd_pcm_oss_open_file(struct file *file,
 			if (! (f_mode & FMODE_READ))
 				continue;
 		}
-		err = snd_pcm_open_substream(pcm, idx, file, &substream);
+		err = snd_pcm_open_substream(pcm, NULL, idx, file, &substream);
 		if (err < 0) {
 			snd_pcm_oss_release_file(pcm_oss_file);
 			return err;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index ca1ea3cf9350..6461dafdc5fb 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -964,15 +964,16 @@ static int snd_pcm_dev_free(struct snd_device *device)
 	return snd_pcm_free(pcm);
 }
 
-int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
-			     struct file *file,
+int snd_pcm_attach_substream(struct snd_pcm *pcm,
+			     struct snd_pcm_substream *clone,
+			     int stream, struct file *file,
 			     struct snd_pcm_substream **rsubstream)
 {
 	struct snd_pcm_str * pstr;
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_runtime *runtime;
 	struct snd_card *card;
-	int prefer_subdevice;
+	int prefer_subdevice = -1;
 	size_t size;
 
 	if (snd_BUG_ON(!pcm || !rsubstream))
@@ -986,7 +987,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 		return -ENODEV;
 
 	card = pcm->card;
-	prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
+	if (!clone)
+		prefer_subdevice =
+			snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
 
 	if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
 		int opposite = !stream;
@@ -999,15 +1002,19 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 	}
 
 	if (file->f_flags & O_APPEND) {
-		if (prefer_subdevice < 0) {
-			if (pstr->substream_count > 1)
-				return -EINVAL; /* must be unique */
-			substream = pstr->substream;
+		if (clone) {
+			substream = clone;
 		} else {
-			for (substream = pstr->substream; substream;
-			     substream = substream->next)
-				if (substream->number == prefer_subdevice)
-					break;
+			if (prefer_subdevice < 0) {
+				if (pstr->substream_count > 1)
+					return -EINVAL; /* must be unique */
+				substream = pstr->substream;
+			} else {
+				for (substream = pstr->substream; substream;
+				     substream = substream->next)
+					if (substream->number == prefer_subdevice)
+						break;
+			}
 		}
 		if (! substream)
 			return -ENODEV;
@@ -1018,11 +1025,18 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 		return 0;
 	}
 
-	for (substream = pstr->substream; substream; substream = substream->next) {
-		if (!SUBSTREAM_BUSY(substream) &&
-		    (prefer_subdevice == -1 ||
-		     substream->number == prefer_subdevice))
-			break;
+	if (clone) {
+		substream = clone;
+		if (SUBSTREAM_BUSY(substream))
+			return -EAGAIN;
+	} else {
+		for (substream = pstr->substream; substream;
+		     substream = substream->next) {
+			if (!SUBSTREAM_BUSY(substream) &&
+			    (prefer_subdevice == -1 ||
+			     substream->number == prefer_subdevice))
+				break;
+		}
 	}
 	if (substream == NULL)
 		return -EAGAIN;
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 946ab080ac00..22446cd574ee 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -675,6 +675,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
 	case SNDRV_PCM_IOCTL_TSTAMP:
 	case SNDRV_PCM_IOCTL_TTSTAMP:
 	case SNDRV_PCM_IOCTL_USER_PVERSION:
+	case SNDRV_PCM_IOCTL_ANONYMOUS_DUP:
 	case SNDRV_PCM_IOCTL_HWSYNC:
 	case SNDRV_PCM_IOCTL_PREPARE:
 	case SNDRV_PCM_IOCTL_RESET:
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 26afb6b0889a..a6d2a5024ab5 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -37,6 +37,8 @@
 #include <sound/minors.h>
 #include <linux/uio.h>
 #include <linux/delay.h>
+#include <linux/anon_inodes.h>
+#include <linux/syscalls.h>
 
 #include "pcm_local.h"
 
@@ -2393,14 +2395,14 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL(snd_pcm_release_substream);
 
-int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
-			   struct file *file,
+int snd_pcm_open_substream(struct snd_pcm *pcm, struct snd_pcm_substream *clone,
+			   int stream, struct file *file,
 			   struct snd_pcm_substream **rsubstream)
 {
 	struct snd_pcm_substream *substream;
 	int err;
 
-	err = snd_pcm_attach_substream(pcm, stream, file, &substream);
+	err = snd_pcm_attach_substream(pcm, clone, stream, file, &substream);
 	if (err < 0)
 		return err;
 	if (substream->ref_count > 1) {
@@ -2436,13 +2438,14 @@ EXPORT_SYMBOL(snd_pcm_open_substream);
 
 static int snd_pcm_open_file(struct file *file,
 			     struct snd_pcm *pcm,
+			     struct snd_pcm_substream *clone,
 			     int stream)
 {
 	struct snd_pcm_file *pcm_file;
 	struct snd_pcm_substream *substream;
 	int err;
 
-	err = snd_pcm_open_substream(pcm, stream, file, &substream);
+	err = snd_pcm_open_substream(pcm, clone, stream, file, &substream);
 	if (err < 0)
 		return err;
 
@@ -2509,7 +2512,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
 	add_wait_queue(&pcm->open_wait, &wait);
 	mutex_lock(&pcm->open_mutex);
 	while (1) {
-		err = snd_pcm_open_file(file, pcm, stream);
+		err = snd_pcm_open_file(file, pcm, NULL, stream);
 		if (err >= 0)
 			break;
 		if (err == -EAGAIN) {
@@ -2553,6 +2556,9 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
 	struct snd_pcm_file *pcm_file;
 
 	pcm_file = file->private_data;
+	/* a problem in the anonymous dup can hit the NULL pcm_file */
+	if (pcm_file == NULL)
+		return 0;
 	substream = pcm_file->substream;
 	if (snd_BUG_ON(!substream))
 		return -ENXIO;
@@ -2836,6 +2842,55 @@ static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
 	return result < 0 ? result : 0;
 }
 
+static int snd_pcm_anonymous_dup(struct file *file,
+				 struct snd_pcm_substream *substream,
+				 int __user *arg)
+{
+	int fd;
+	int err;
+	int perm;
+	int flags;
+	struct file *nfile;
+	struct snd_pcm *pcm = substream->pcm;
+
+	if (get_user(perm, (int __user *)arg))
+		return -EFAULT;
+	if (perm < 0)
+		return -ENOSYS;
+	flags = file->f_flags & (O_ACCMODE | O_NONBLOCK);
+	flags |= O_APPEND | O_CLOEXEC;
+	fd = get_unused_fd_flags(flags);
+	if (fd < 0)
+		return fd;
+	nfile = anon_inode_getfile("snd-pcm", file->f_op, NULL, flags);
+	if (IS_ERR(nfile)) {
+		put_unused_fd(fd);
+		return PTR_ERR(nfile);
+	}
+	/* anon_inode_getfile() filters the O_APPEND flag out */
+	nfile->f_flags |= O_APPEND;
+	fd_install(fd, nfile);
+	if (!try_module_get(pcm->card->module)) {
+		err = -EFAULT;
+		goto __error1;
+	}
+	err = snd_card_file_add(substream->pcm->card, nfile);
+	if (err < 0)
+		goto __error2;
+	err = snd_pcm_open_file(nfile, substream->pcm,
+				substream, substream->stream);
+	if (err >= 0) {
+		put_user(fd, (int __user *)arg);
+		return 0;
+	}
+	snd_card_file_remove(substream->pcm->card, nfile);
+      __error2:
+	module_put(pcm->card->module);
+      __error1:
+	ksys_close(fd);
+	return err;
+}
+
 static int snd_pcm_common_ioctl(struct file *file,
 				 struct snd_pcm_substream *substream,
 				 unsigned int cmd, void __user *arg)
@@ -2864,6 +2919,8 @@ static int snd_pcm_common_ioctl(struct file *file,
 			     (unsigned int __user *)arg))
 			return -EFAULT;
 		return 0;
+	case SNDRV_PCM_IOCTL_ANONYMOUS_DUP:
+		return snd_pcm_anonymous_dup(file, substream, (int __user *)arg);
 	case SNDRV_PCM_IOCTL_HW_REFINE:
 		return snd_pcm_hw_refine_user(substream, arg);
 	case SNDRV_PCM_IOCTL_HW_PARAMS:
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] ALSA: pcm: remove the file member from struct pcm
  2019-01-29 17:59 [PATCH 0/3] ALSA: pcm: implement the anonymous dup Jaroslav Kysela
  2019-01-29 17:59 ` [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor) Jaroslav Kysela
@ 2019-01-29 17:59 ` Jaroslav Kysela
  2019-01-29 18:45   ` Takashi Iwai
  2019-01-29 17:59 ` [PATCH 3/3] ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup Jaroslav Kysela
  2019-01-29 19:48 ` [PATCH 0/3] ALSA: pcm: implement " Mark Brown
  3 siblings, 1 reply; 9+ messages in thread
From: Jaroslav Kysela @ 2019-01-29 17:59 UTC (permalink / raw)
  To: ALSA development; +Cc: Takashi Iwai, Mark Brown, Baolin Wang, Leo Yan

This member is no longer used.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 include/sound/pcm.h      | 1 -
 sound/core/oss/pcm_oss.c | 1 -
 sound/core/pcm_native.c  | 4 +---
 3 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index e7deb03b6702..61e4c69e73c7 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -470,7 +470,6 @@ struct snd_pcm_substream {
 	struct snd_pcm_group self_group;	/* fake group for non linked substream (with substream lock inside) */
 	struct snd_pcm_group *group;		/* pointer to current group */
 	/* -- assigned files -- */
-	void *file;
 	int ref_count;
 	atomic_t mmap_count;
 	unsigned int f_flags;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index b3738c228f39..222ddf9e4859 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2427,7 +2427,6 @@ static int snd_pcm_oss_open_file(struct file *file,
 		}
 
 		pcm_oss_file->streams[idx] = substream;
-		substream->file = pcm_oss_file;
 		snd_pcm_oss_init_substream(substream, &setup[idx], minor);
 	}
 	
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a6d2a5024ab5..3ab6fbd7acae 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2455,10 +2455,8 @@ static int snd_pcm_open_file(struct file *file,
 		return -ENOMEM;
 	}
 	pcm_file->substream = substream;
-	if (substream->ref_count == 1) {
-		substream->file = pcm_file;
+	if (substream->ref_count == 1)
 		substream->pcm_release = pcm_release_private;
-	}
 	file->private_data = pcm_file;
 
 	return 0;
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup
  2019-01-29 17:59 [PATCH 0/3] ALSA: pcm: implement the anonymous dup Jaroslav Kysela
  2019-01-29 17:59 ` [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor) Jaroslav Kysela
  2019-01-29 17:59 ` [PATCH 2/3] ALSA: pcm: remove the file member from struct pcm Jaroslav Kysela
@ 2019-01-29 17:59 ` Jaroslav Kysela
  2019-01-29 18:47   ` Takashi Iwai
  2019-01-29 19:48 ` [PATCH 0/3] ALSA: pcm: implement " Mark Brown
  3 siblings, 1 reply; 9+ messages in thread
From: Jaroslav Kysela @ 2019-01-29 17:59 UTC (permalink / raw)
  To: ALSA development; +Cc: Takashi Iwai, Mark Brown, Baolin Wang, Leo Yan

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(-)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 61e4c69e73c7..29d22a3a458c 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -226,6 +226,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..29d3a16caa9a 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_MAX		((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 3ab6fbd7acae..6d011b0899b5 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2455,6 +2455,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;
@@ -2850,10 +2851,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 < 0 || perm > SNDRV_PCM_PERM_MAX)
 		return -ENOSYS;
 	flags = file->f_flags & (O_ACCMODE | O_NONBLOCK);
 	flags |= O_APPEND | O_CLOEXEC;
@@ -2878,6 +2880,8 @@ static int snd_pcm_anonymous_dup(struct file *file,
 	err = snd_pcm_open_file(nfile, substream->pcm,
 				substream, substream->stream);
 	if (err >= 0) {
+		pcm_file = nfile->private_data;
+		pcm_file->perm = perm;
 		put_user(fd, (int __user *)arg);
 		return 0;
 	}
@@ -2889,6 +2893,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)
@@ -2903,6 +2974,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;
@@ -3251,6 +3325,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;
@@ -3287,6 +3364,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;
@@ -3461,11 +3541,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

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor)
  2019-01-29 17:59 ` [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor) Jaroslav Kysela
@ 2019-01-29 18:44   ` Takashi Iwai
  2019-01-30  8:07     ` Jaroslav Kysela
  0 siblings, 1 reply; 9+ messages in thread
From: Takashi Iwai @ 2019-01-29 18:44 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: ALSA development, Mark Brown, Baolin Wang, Leo Yan

On Tue, 29 Jan 2019 18:59:07 +0100,
Jaroslav Kysela wrote:
> 
> This patch implements new SNDRV_PCM_IOCTL_ANONYMOUS_DUP ioctl which
> returns the new duplicated anonymous inode file descriptor
> (anon_inode:snd-pcm) which can be passed to the restricted clients.
> 
> This patch is meant to be the alternative for the dma-buf interface. Both
> implementation have some pros and cons:
> 
> anon_inode:dmabuf
> 
> - a bit standard export API for the DMA buffers
> - fencing for the concurrent access [1]
> - driver/kernel interface for the DMA buffer [1]
> - multiple attach/detach scheme [1]
> 
> [1] the real usage for the sound PCM is unknown at the moment for this feature
> 
> anon_inode:snd-pcm
> 
> - simple (no problem with ref-counting, non-standard mmap implementation etc.)
> - allow to use more sound interfaces for the file descriptor like status ioctls
> - more fine grained security policies (another anon_inode name unshared with
>   other drivers)

Your sign-off seems missing.


> @@ -999,15 +1002,19 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
>  	}
>  
>  	if (file->f_flags & O_APPEND) {
> -		if (prefer_subdevice < 0) {
> -			if (pstr->substream_count > 1)
> -				return -EINVAL; /* must be unique */
> -			substream = pstr->substream;
> +		if (clone) {
> +			substream = clone;
>  		} else {
> -			for (substream = pstr->substream; substream;
> -			     substream = substream->next)
> -				if (substream->number == prefer_subdevice)
> -					break;
> +			if (prefer_subdevice < 0) {
> +				if (pstr->substream_count > 1)
> +					return -EINVAL; /* must be unique */
> +				substream = pstr->substream;
> +			} else {
> +				for (substream = pstr->substream; substream;
> +				     substream = substream->next)
> +					if (substream->number == prefer_subdevice)
> +						break;
> +			}
>  		}
>  		if (! substream)
>  			return -ENODEV;

So the clone case should return via this block, then...

> @@ -1018,11 +1025,18 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
>  		return 0;
>  	}
>  
> -	for (substream = pstr->substream; substream; substream = substream->next) {
> -		if (!SUBSTREAM_BUSY(substream) &&
> -		    (prefer_subdevice == -1 ||
> -		     substream->number == prefer_subdevice))
> -			break;
> +	if (clone) {
> +		substream = clone;
> +		if (SUBSTREAM_BUSY(substream))
> +			return -EAGAIN;
> +	} else {
> +		for (substream = pstr->substream; substream;
> +		     substream = substream->next) {
> +			if (!SUBSTREAM_BUSY(substream) &&
> +			    (prefer_subdevice == -1 ||
> +			     substream->number == prefer_subdevice))
> +				break;
> +		}

... do we need to support cloning without O_APPEND?


thanks,

Takashi

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/3] ALSA: pcm: remove the file member from struct pcm
  2019-01-29 17:59 ` [PATCH 2/3] ALSA: pcm: remove the file member from struct pcm Jaroslav Kysela
@ 2019-01-29 18:45   ` Takashi Iwai
  0 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2019-01-29 18:45 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: ALSA development, Mark Brown, Baolin Wang, Leo Yan

On Tue, 29 Jan 2019 18:59:08 +0100,
Jaroslav Kysela wrote:
> 
> This member is no longer used.
> 
> Signed-off-by: Jaroslav Kysela <perex@perex.cz>

Heh, the very same change is already in my for-next branch :)


thanks,

Takashi

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup
  2019-01-29 17:59 ` [PATCH 3/3] ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup Jaroslav Kysela
@ 2019-01-29 18:47   ` Takashi Iwai
  0 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2019-01-29 18:47 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: ALSA development, Mark Brown, Baolin Wang, Leo Yan

On Tue, 29 Jan 2019 18:59:09 +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>
> ---
>  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 61e4c69e73c7..29d22a3a458c 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -226,6 +226,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..29d3a16caa9a 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_MAX		((SNDRV_PCM_PERM_SYNC<<1)-1)

I'd name it SNDRV_PCM_PERM_MASK, and ...

> @@ -2850,10 +2851,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 < 0 || perm > SNDRV_PCM_PERM_MAX)
>  		return -ENOSYS;

... check like
	if (perm & ~SNDRV_PCM_PER_MASK)
		return -EINVAL;


thanks,

Takashi

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/3] ALSA: pcm: implement the anonymous dup
  2019-01-29 17:59 [PATCH 0/3] ALSA: pcm: implement the anonymous dup Jaroslav Kysela
                   ` (2 preceding siblings ...)
  2019-01-29 17:59 ` [PATCH 3/3] ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup Jaroslav Kysela
@ 2019-01-29 19:48 ` Mark Brown
  3 siblings, 0 replies; 9+ messages in thread
From: Mark Brown @ 2019-01-29 19:48 UTC (permalink / raw)
  To: Jaroslav Kysela
  Cc: Takashi Iwai, ALSA development, Baolin Wang, Phil Burk, Leo Yan


[-- Attachment #1.1: Type: text/plain, Size: 1467 bytes --]

On Tue, Jan 29, 2019 at 06:59:06PM +0100, Jaroslav Kysela wrote:
> This patchset contains the anonymous dup implementation with permissions
> checking for the ALSA's PCM interface in kernel to enable the restricted
> DMA sound buffer sharing for the restricted tasks.

> The code was tested through qemu and it seems to be pretty stable.

> The initial tinyalsa implementation can be found here:

>   https://github.com/perexg/tinyalsa/commits/anondup

> The filtering might be refined. It depends on the real requirements.
> Perhaps, we may create more ioctl groups. Any comments are more than
> welcome.

Thanks for looking at this!  Copying in Phil who is probably best placed
to review these from an Android perspective.

> Cc: Mark Brown <broonie@kernel.org>
> Cc: Leo Yan <leo.yan@linaro.org>
> Cc: Baolin Wang <baolin.wang@linaro.org>
> 
> Jaroslav Kysela (3):
>   ALSA: pcm: implement the anonymous dup (inode file descriptor)
>   ALSA: pcm: remove the file member from struct pcm
>   ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup
> 
>  include/sound/pcm.h         |  10 +--
>  include/uapi/sound/asound.h |  12 +++-
>  sound/core/oss/pcm_oss.c    |   3 +-
>  sound/core/pcm.c            |  48 +++++++++-----
>  sound/core/pcm_compat.c     |   1 +
>  sound/core/pcm_native.c     | 154 +++++++++++++++++++++++++++++++++++++++++---
>  6 files changed, 195 insertions(+), 33 deletions(-)
> 
> -- 
> 2.13.6

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor)
  2019-01-29 18:44   ` Takashi Iwai
@ 2019-01-30  8:07     ` Jaroslav Kysela
  0 siblings, 0 replies; 9+ messages in thread
From: Jaroslav Kysela @ 2019-01-30  8:07 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: ALSA development, Mark Brown, Baolin Wang, Leo Yan

Dne 29.1.2019 v 19:44 Takashi Iwai napsal(a):
> On Tue, 29 Jan 2019 18:59:07 +0100,
> Jaroslav Kysela wrote:
>>
>> This patch implements new SNDRV_PCM_IOCTL_ANONYMOUS_DUP ioctl which
>> returns the new duplicated anonymous inode file descriptor
>> (anon_inode:snd-pcm) which can be passed to the restricted clients.
>>
>> This patch is meant to be the alternative for the dma-buf interface. Both
>> implementation have some pros and cons:
>>
>> anon_inode:dmabuf
>>
>> - a bit standard export API for the DMA buffers
>> - fencing for the concurrent access [1]
>> - driver/kernel interface for the DMA buffer [1]
>> - multiple attach/detach scheme [1]
>>
>> [1] the real usage for the sound PCM is unknown at the moment for this feature
>>
>> anon_inode:snd-pcm
>>
>> - simple (no problem with ref-counting, non-standard mmap implementation etc.)
>> - allow to use more sound interfaces for the file descriptor like status ioctls
>> - more fine grained security policies (another anon_inode name unshared with
>>   other drivers)
> 
> Your sign-off seems missing.

Fixed now. Thanks.

>> @@ -999,15 +1002,19 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
>>  	}
>>  
>>  	if (file->f_flags & O_APPEND) {
>> -		if (prefer_subdevice < 0) {
>> -			if (pstr->substream_count > 1)
>> -				return -EINVAL; /* must be unique */
>> -			substream = pstr->substream;
>> +		if (clone) {
>> +			substream = clone;
>>  		} else {
>> -			for (substream = pstr->substream; substream;
>> -			     substream = substream->next)
>> -				if (substream->number == prefer_subdevice)
>> -					break;
>> +			if (prefer_subdevice < 0) {
>> +				if (pstr->substream_count > 1)
>> +					return -EINVAL; /* must be unique */
>> +				substream = pstr->substream;
>> +			} else {
>> +				for (substream = pstr->substream; substream;
>> +				     substream = substream->next)
>> +					if (substream->number == prefer_subdevice)
>> +						break;
>> +			}
>>  		}
>>  		if (! substream)
>>  			return -ENODEV;
> 
> So the clone case should return via this block, then...
> 
>> @@ -1018,11 +1025,18 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
>>  		return 0;
>>  	}
>>  
>> -	for (substream = pstr->substream; substream; substream = substream->next) {
>> -		if (!SUBSTREAM_BUSY(substream) &&
>> -		    (prefer_subdevice == -1 ||
>> -		     substream->number == prefer_subdevice))
>> -			break;
>> +	if (clone) {
>> +		substream = clone;
>> +		if (SUBSTREAM_BUSY(substream))
>> +			return -EAGAIN;
>> +	} else {
>> +		for (substream = pstr->substream; substream;
>> +		     substream = substream->next) {
>> +			if (!SUBSTREAM_BUSY(substream) &&
>> +			    (prefer_subdevice == -1 ||
>> +			     substream->number == prefer_subdevice))
>> +				break;
>> +		}
> 
> ... do we need to support cloning without O_APPEND?

I think that it would be better to pass the subdevice number to
snd_pcm_attach_substream(). It will reduce the required modifications.
I will change this.

				Thanks,
					Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-01-30  8:07 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-29 17:59 [PATCH 0/3] ALSA: pcm: implement the anonymous dup Jaroslav Kysela
2019-01-29 17:59 ` [PATCH 1/3] ALSA: pcm: implement the anonymous dup (inode file descriptor) Jaroslav Kysela
2019-01-29 18:44   ` Takashi Iwai
2019-01-30  8:07     ` Jaroslav Kysela
2019-01-29 17:59 ` [PATCH 2/3] ALSA: pcm: remove the file member from struct pcm Jaroslav Kysela
2019-01-29 18:45   ` Takashi Iwai
2019-01-29 17:59 ` [PATCH 3/3] ALSA: pcm: implement the ioctl/mmap filter for the anonymous dup Jaroslav Kysela
2019-01-29 18:47   ` Takashi Iwai
2019-01-29 19:48 ` [PATCH 0/3] ALSA: pcm: implement " Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.