From patchwork Fri Feb 10 14:24:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 9566855 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 457ED60573 for ; Fri, 10 Feb 2017 14:27:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 31F93281F9 for ; Fri, 10 Feb 2017 14:27:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 26A902855E; Fri, 10 Feb 2017 14:27:17 +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=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8FCDE2845D for ; Fri, 10 Feb 2017 14:27:16 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ccC80-0003KP-FW; Fri, 10 Feb 2017 14:24:48 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ccC7z-0003Ju-Cz for xen-devel@lists.xenproject.org; Fri, 10 Feb 2017 14:24:47 +0000 Received: from [85.158.137.68] by server-13.bemta-3.messagelabs.com id A9/41-25657-E2DCD985; Fri, 10 Feb 2017 14:24:46 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprAIsWRWlGSWpSXmKPExsXitHSDva7e2bk RBqv72Cy+b5nM5MDocfjDFZYAxijWzLyk/IoE1oyWtz2MBSdVK7Z+XsTYwLhLvouRk0NCwF9i 9sK1zCA2m4COxNSnl1hBbBEBF4n+bWfYQGxmgSqJ09MmM4LYwgL2Eo/XfgerYRFQldi3ZS5YL 6+Au8ScfReZIWbKSZw//hPM5hTwkJh4cRMTiC0EVNO9Yy4rhK0isX7qLDaIXkGJkzOfsEDskp A4+OIF8wRG3llIUrOQpBYwMq1iVC9OLSpLLdI11ksqykzPKMlNzMzRNTQw1stNLS5OTE/NSUw q1kvOz93ECAwdBiDYwdj8xekQoyQHk5Ior8DpuRFCfEn5KZUZicUZ8UWlOanFhxhlODiUJHit zwDlBItS01Mr0jJzgEEMk5bg4FES4RUEaeUtLkjMLc5Mh0idYtTlOHXj9EsmIZa8/LxUKXFef ZAZAiBFGaV5cCNgEXWJUVZKmJcR6CghnoLUotzMElT5V4ziHIxKwrzSIFN4MvNK4Da9AjqCCe iI66dngRxRkoiQkmpg5FFaXLPLYo5R+bOTh37MPX7FSjLOdEGx/WKXqPdM8a15Xuveiz6Xe/b 09cqdp6uOOx685sspdLDzAvvhf0JOosXfthQsb6/iWtD/+8aRWrFnvWxVD2/m6C4+GdT2LOe5 UfWm/ROj2EPf7pu0af1J/f2Pej4EXcoMWJrZMNtkhsHKffdnLfQV3KLEUpyRaKjFXFScCADSJ bj1owIAAA== X-Env-Sender: prvs=207696d45=Paul.Durrant@citrix.com X-Msg-Ref: server-3.tower-31.messagelabs.com!1486736683!84973040!1 X-Originating-IP: [66.165.176.63] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni42MyA9PiAzMDYwNDg=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.1.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 17990 invoked from network); 10 Feb 2017 14:24:45 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-3.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 10 Feb 2017 14:24:45 -0000 X-IronPort-AV: E=Sophos;i="5.35,141,1484006400"; d="scan'208";a="414975267" From: Paul Durrant To: , Date: Fri, 10 Feb 2017 14:24:37 +0000 Message-ID: <1486736677-10953-4-git-send-email-paul.durrant@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1486736677-10953-1-git-send-email-paul.durrant@citrix.com> References: <1486736677-10953-1-git-send-email-paul.durrant@citrix.com> MIME-Version: 1.0 Cc: Juergen Gross , Boris Ostrovsky , Paul Durrant Subject: [Xen-devel] [PATCH v2 3/3] xen/privcmd: add IOCTL_PRIVCMD_RESTRICT X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP The purpose if this ioctl is to allow a user of privcmd to restrict its operation such that it will no longer service arbitrary hypercalls via IOCTL_PRIVCMD_HYPERCALL, and will check for a matching domid when servicing IOCTL_PRIVCMD_DM_OP. The aim of this is to limit the attack surface for a compromised device model. Signed-off-by: Paul Durrant --- Cc: Boris Ostrovsky Cc: Juergen Gross v2: - Make sure that a restriction cannot be cleared --- drivers/xen/privcmd.c | 67 +++++++++++++++++++++++++++++++++++++++++++--- include/uapi/xen/privcmd.h | 2 ++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index d5cf042..e372aae 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -44,16 +44,25 @@ MODULE_LICENSE("GPL"); #define PRIV_VMA_LOCKED ((void *)1) +struct privcmd_data { + domid_t domid; +}; + static int privcmd_vma_range_is_mapped( struct vm_area_struct *vma, unsigned long addr, unsigned long nr_pages); -static long privcmd_ioctl_hypercall(void __user *udata) +static long privcmd_ioctl_hypercall(struct file *file, void __user *udata) { + struct privcmd_data *data = file->private_data; struct privcmd_hypercall hypercall; long ret; + /* Disallow arbitrary hypercalls if restricted */ + if (data->domid != DOMID_INVALID) + return -EPERM; + if (copy_from_user(&hypercall, udata, sizeof(hypercall))) return -EFAULT; @@ -591,8 +600,9 @@ static void unlock_pages(struct page *pages[], unsigned int nr_pages) } } -static long privcmd_ioctl_dm_op(void __user *udata) +static long privcmd_ioctl_dm_op(struct file *file, void __user *udata) { + struct privcmd_data *data = file->private_data; struct privcmd_dm_op kdata; struct privcmd_dm_op_buf *kbufs; unsigned int nr_pages = 0; @@ -604,6 +614,10 @@ static long privcmd_ioctl_dm_op(void __user *udata) if (copy_from_user(&kdata, udata, sizeof(kdata))) return -EFAULT; + /* If restriction is in place, check the domid matches */ + if (data->domid != DOMID_INVALID && data->domid != kdata.dom) + return -EPERM; + if (kdata.num == 0) return 0; @@ -682,6 +696,23 @@ static long privcmd_ioctl_dm_op(void __user *udata) return rc; } +static long privcmd_ioctl_restrict(struct file *file, void __user *udata) +{ + struct privcmd_data *data = file->private_data; + domid_t dom; + + if (copy_from_user(&dom, udata, sizeof(dom))) + return -EFAULT; + + /* Set restriction to the specified domain, or check it matches */ + if (data->domid == DOMID_INVALID) + data->domid = dom; + else if (data->domid != dom) + return -EINVAL; + + return 0; +} + static long privcmd_ioctl(struct file *file, unsigned int cmd, unsigned long data) { @@ -690,7 +721,7 @@ static long privcmd_ioctl(struct file *file, switch (cmd) { case IOCTL_PRIVCMD_HYPERCALL: - ret = privcmd_ioctl_hypercall(udata); + ret = privcmd_ioctl_hypercall(file, udata); break; case IOCTL_PRIVCMD_MMAP: @@ -706,7 +737,11 @@ static long privcmd_ioctl(struct file *file, break; case IOCTL_PRIVCMD_DM_OP: - ret = privcmd_ioctl_dm_op(udata); + ret = privcmd_ioctl_dm_op(file, udata); + break; + + case IOCTL_PRIVCMD_RESTRICT: + ret = privcmd_ioctl_restrict(file, udata); break; default: @@ -716,6 +751,28 @@ static long privcmd_ioctl(struct file *file, return ret; } +static int privcmd_open(struct inode *ino, struct file *file) +{ + struct privcmd_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + + if (!data) + return -ENOMEM; + + /* DOMID_INVALID implies no restriction */ + data->domid = DOMID_INVALID; + + file->private_data = data; + return 0; +} + +static int privcmd_release(struct inode *ino, struct file *file) +{ + struct privcmd_data *data = file->private_data; + + kfree(data); + return 0; +} + static void privcmd_close(struct vm_area_struct *vma) { struct page **pages = vma->vm_private_data; @@ -784,6 +841,8 @@ static int privcmd_vma_range_is_mapped( const struct file_operations xen_privcmd_fops = { .owner = THIS_MODULE, .unlocked_ioctl = privcmd_ioctl, + .open = privcmd_open, + .release = privcmd_release, .mmap = privcmd_mmap, }; EXPORT_SYMBOL_GPL(xen_privcmd_fops); diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h index f8c5d75..63ee95c 100644 --- a/include/uapi/xen/privcmd.h +++ b/include/uapi/xen/privcmd.h @@ -111,5 +111,7 @@ struct privcmd_dm_op { _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2)) #define IOCTL_PRIVCMD_DM_OP \ _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op)) +#define IOCTL_PRIVCMD_RESTRICT \ + _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t)) #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */