From patchwork Sun Aug 7 09:48:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Sakamoto X-Patchwork-Id: 9266271 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 18DBB60754 for ; Sun, 7 Aug 2016 09:51:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 097A127F2B for ; Sun, 7 Aug 2016 09:51:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F262D2808C; Sun, 7 Aug 2016 09:51:22 +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=-1.9 required=2.0 tests=BAYES_00, 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 CEA5C27FAC for ; Sun, 7 Aug 2016 09:51:21 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id DA417266B43; Sun, 7 Aug 2016 11:51:20 +0200 (CEST) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 83D47265E0E; Sun, 7 Aug 2016 11:49:50 +0200 (CEST) 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 45CED26588F; Sun, 7 Aug 2016 11:49:46 +0200 (CEST) Received: from smtp-proxy004.phy.lolipop.jp (smtp-proxy004.phy.lolipop.jp [157.7.104.45]) by alsa0.perex.cz (Postfix) with ESMTP id 6E95926058F for ; Sun, 7 Aug 2016 11:49:36 +0200 (CEST) Received: from smtp-proxy004.phy.lolipop.lan (HELO smtp-proxy004.phy.lolipop.jp) (172.19.44.45) (smtp-auth username m12129643-o-takashi, mechanism plain) by smtp-proxy004.phy.lolipop.jp (qpsmtpd/0.82) with ESMTPA; Sun, 07 Aug 2016 18:49:33 +0900 Received: from 127.0.0.1 (127.0.0.1) by smtp-proxy004.phy.lolipop.jp (LOLIPOP-Fsecure); Sun, 07 Aug 2016 18:49:15 +0900 (JST) X-Virus-Status: clean(LOLIPOP-Fsecure) From: Takashi Sakamoto To: clemens@ladisch.de, tiwai@suse.de Date: Sun, 7 Aug 2016 18:48:40 +0900 Message-Id: <1470563355-18368-5-git-send-email-o-takashi@sakamocchi.jp> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1470563355-18368-1-git-send-email-o-takashi@sakamocchi.jp> References: <1470563355-18368-1-git-send-email-o-takashi@sakamocchi.jp> Cc: alsa-devel@alsa-project.org Subject: [alsa-devel] [PATCH 04/39] ALSA: seq: copy ioctl data from user space to kernel stack 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 ALSA sequencer core allows kernel-mode tasks to execute operations corresponding to ioctls by user-mode tasks. This is for compatibility layers such as ABIs for 32/64 bit and I/O operations via Open Sound System. This design requires to handle ioctl data in kernel space. For this requirement, ALSA sequencer core temporarily changes address limit for the task by get_fs()/set_fs() macro. Although, this way get shape of code worse, because even when an pointer has '__user' qualifier, actually it refers to kernel space, depending on the task. This easily misleads readers. This commit is a preparation for following patches to solve this issue. Data from user space is once copied to kernel stack, then operated and copied to user space, in a consistent manner. This manner forces all ioctl operations to copy the data from/to user space, even if it's read-only or write-only. Thus, it has an overhead for simpler ioctl commands. Signed-off-by: Takashi Sakamoto --- sound/core/seq/seq_clientmgr.c | 136 ++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 35 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index d6c1219..17d988a 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2182,40 +2182,70 @@ static int seq_ioctl_query_next_port(struct snd_seq_client *client, static const struct seq_ioctl_table { unsigned int cmd; - int (*func)(struct snd_seq_client *client, void __user * arg); + int (*func)(struct snd_seq_client *client, void *arg); + size_t arg_size; } ioctl_tables[] = { - { SNDRV_SEQ_IOCTL_PVERSION, seq_ioctl_pversion }, - { SNDRV_SEQ_IOCTL_CLIENT_ID, seq_ioctl_client_id }, - { SNDRV_SEQ_IOCTL_SYSTEM_INFO, seq_ioctl_system_info }, - { SNDRV_SEQ_IOCTL_RUNNING_MODE, seq_ioctl_running_mode }, - { SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, seq_ioctl_get_client_info }, - { SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, seq_ioctl_set_client_info }, - { SNDRV_SEQ_IOCTL_CREATE_PORT, seq_ioctl_create_port }, - { SNDRV_SEQ_IOCTL_DELETE_PORT, seq_ioctl_delete_port }, - { SNDRV_SEQ_IOCTL_GET_PORT_INFO, seq_ioctl_get_port_info }, - { SNDRV_SEQ_IOCTL_SET_PORT_INFO, seq_ioctl_set_port_info }, - { SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, seq_ioctl_subscribe_port }, - { SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, seq_ioctl_unsubscribe_port }, - { SNDRV_SEQ_IOCTL_CREATE_QUEUE, seq_ioctl_create_queue }, - { SNDRV_SEQ_IOCTL_DELETE_QUEUE, seq_ioctl_delete_queue }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, seq_ioctl_get_queue_info }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, seq_ioctl_set_queue_info }, - { SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, seq_ioctl_get_named_queue }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, seq_ioctl_get_queue_status }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, seq_ioctl_get_queue_tempo }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, seq_ioctl_set_queue_tempo }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, seq_ioctl_get_queue_timer }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, seq_ioctl_set_queue_timer }, - { SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, seq_ioctl_get_queue_client }, - { SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, seq_ioctl_set_queue_client }, - { SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, seq_ioctl_get_client_pool }, - { SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, seq_ioctl_set_client_pool }, - { SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, seq_ioctl_get_subscription }, - { SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, seq_ioctl_query_next_client }, - { SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, seq_ioctl_query_next_port }, - { SNDRV_SEQ_IOCTL_REMOVE_EVENTS, seq_ioctl_remove_events }, - { SNDRV_SEQ_IOCTL_QUERY_SUBS, seq_ioctl_query_subs }, - { 0, NULL }, + { SNDRV_SEQ_IOCTL_PVERSION, seq_ioctl_pversion, sizeof(int) }, + { SNDRV_SEQ_IOCTL_CLIENT_ID, seq_ioctl_client_id, sizeof(int) }, + { SNDRV_SEQ_IOCTL_SYSTEM_INFO, seq_ioctl_system_info, + sizeof(struct snd_seq_system_info) }, + { SNDRV_SEQ_IOCTL_RUNNING_MODE, seq_ioctl_running_mode, + sizeof(struct snd_seq_running_info) }, + { SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, seq_ioctl_get_client_info, + sizeof(struct snd_seq_client_info) }, + { SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, seq_ioctl_set_client_info, + sizeof(struct snd_seq_client_info) }, + { SNDRV_SEQ_IOCTL_CREATE_PORT, seq_ioctl_create_port, + sizeof(struct snd_seq_port_info) }, + { SNDRV_SEQ_IOCTL_DELETE_PORT, seq_ioctl_delete_port, + sizeof(struct snd_seq_port_info) }, + { SNDRV_SEQ_IOCTL_GET_PORT_INFO, seq_ioctl_get_port_info, + sizeof(struct snd_seq_port_info) }, + { SNDRV_SEQ_IOCTL_SET_PORT_INFO, seq_ioctl_set_port_info, + sizeof(struct snd_seq_port_info) }, + { SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, seq_ioctl_subscribe_port, + sizeof(struct snd_seq_port_subscribe) }, + { SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, seq_ioctl_unsubscribe_port, + sizeof(struct snd_seq_port_subscribe) }, + { SNDRV_SEQ_IOCTL_CREATE_QUEUE, seq_ioctl_create_queue, + sizeof(struct snd_seq_queue_info) }, + { SNDRV_SEQ_IOCTL_DELETE_QUEUE, seq_ioctl_delete_queue, + sizeof(struct snd_seq_queue_info) }, + { SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, seq_ioctl_get_queue_info, + sizeof(struct snd_seq_queue_info) }, + { SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, seq_ioctl_set_queue_info, + sizeof(struct snd_seq_queue_info) }, + { SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, seq_ioctl_get_named_queue, + sizeof(struct snd_seq_queue_info) }, + { SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, seq_ioctl_get_queue_status, + sizeof(struct snd_seq_queue_status) }, + { SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, seq_ioctl_get_queue_tempo, + sizeof(struct snd_seq_queue_tempo) }, + { SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, seq_ioctl_set_queue_tempo, + sizeof(struct snd_seq_queue_tempo) }, + { SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, seq_ioctl_get_queue_timer, + sizeof(struct snd_seq_queue_timer) }, + { SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, seq_ioctl_set_queue_timer, + sizeof(struct snd_seq_queue_timer) }, + { SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, seq_ioctl_get_queue_client, + sizeof(struct snd_seq_queue_client) }, + { SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, seq_ioctl_set_queue_client, + sizeof(struct snd_seq_queue_client) }, + { SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, seq_ioctl_get_client_pool, + sizeof(struct snd_seq_client_pool) }, + { SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, seq_ioctl_set_client_pool, + sizeof(struct snd_seq_client_pool) }, + { SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, seq_ioctl_get_subscription, + sizeof(struct snd_seq_port_subscribe) }, + { SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, seq_ioctl_query_next_client, + sizeof(struct snd_seq_client_info) }, + { SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, seq_ioctl_query_next_port, + sizeof(struct snd_seq_port_info) }, + { SNDRV_SEQ_IOCTL_REMOVE_EVENTS, seq_ioctl_remove_events, + sizeof(struct snd_seq_remove_events) }, + { SNDRV_SEQ_IOCTL_QUERY_SUBS, seq_ioctl_query_subs, + sizeof(struct snd_seq_query_subs) }, + { 0, NULL, 0 }, }; static int seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd, @@ -2235,14 +2265,50 @@ static int seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd, } -static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long snd_seq_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { struct snd_seq_client *client = file->private_data; + const struct seq_ioctl_table *p; + union ioctl_arg { + int pversion; + int client_id; + struct snd_seq_system_info system_info; + struct snd_seq_running_info running_info; + struct snd_seq_client_info client_info; + struct snd_seq_port_info port_info; + struct snd_seq_port_subscribe port_subscribe; + struct snd_seq_queue_info queue_info; + struct snd_seq_queue_status queue_status; + struct snd_seq_queue_tempo tempo; + struct snd_seq_queue_timer queue_timer; + struct snd_seq_queue_client queue_client; + struct snd_seq_client_pool client_pool; + struct snd_seq_remove_events remove_events; + struct snd_seq_query_subs query_subs; + } buf = {0}; + int err; if (snd_BUG_ON(!client)) return -ENXIO; + + for (p = ioctl_tables; p->cmd > 0; ++p) { + if (p->cmd == cmd) + break; + } + if (p->cmd == 0) + return -ENOTTY; + + if (copy_from_user(&buf, (const void __user *)arg, p->arg_size)) + return -EFAULT; - return seq_do_ioctl(client, cmd, (void __user *) arg); + err = p->func(client, &buf); + if (err >= 0) { + if (copy_to_user((void __user *)arg, &buf, p->arg_size)) + return -EFAULT; + } + + return err; } #ifdef CONFIG_COMPAT