From patchwork Sat Nov 10 16:35:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 10677335 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 4EF0A139B for ; Sat, 10 Nov 2018 16:36:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3DC9F2C6DF for ; Sat, 10 Nov 2018 16:36:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 31D362C95B; Sat, 10 Nov 2018 16:36:02 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8E2BD2C6DF for ; Sat, 10 Nov 2018 16:36:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727132AbeKKCVQ (ORCPT ); Sat, 10 Nov 2018 21:21:16 -0500 Received: from mx1.redhat.com ([209.132.183.28]:51986 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727114AbeKKCVQ (ORCPT ); Sat, 10 Nov 2018 21:21:16 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B586F3082125; Sat, 10 Nov 2018 16:35:39 +0000 (UTC) Received: from 640k.localdomain.com (ovpn-112-24.ams2.redhat.com [10.36.112.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id B1B65608C2; Sat, 10 Nov 2018 16:35:37 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org Cc: linux-scsi@vger.kernel.org, Hannes Reinecke , "Martin K. Petersen" , James Bottomley Subject: [PATCH 1/3] block: add back queue-private command filter Date: Sat, 10 Nov 2018 17:35:31 +0100 Message-Id: <1541867733-7836-2-git-send-email-pbonzini@redhat.com> In-Reply-To: <1541867733-7836-1-git-send-email-pbonzini@redhat.com> References: <1541867733-7836-1-git-send-email-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Sat, 10 Nov 2018 16:35:39 +0000 (UTC) Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The command filter used to be mutable via sysfs, but this was broken and backed out. Let's add it back. This patch adds the infrastructure for filtering, but unlike the old code this one just adds a pointer to request_queue, so as to make it cheaper in the majority of cases where no special filtering is desired. This is a revert of commit 018e044 ("block: get rid of queue-private command filter", 2009-06-26), though with many changes. Cc: linux-scsi@vger.kernel.org Cc: Hannes Reinecke Cc: Martin K. Petersen Cc: James Bottomley Signed-off-by: Paolo Bonzini --- block/blk-sysfs.c | 2 ++ block/bsg-lib.c | 4 ++-- block/bsg.c | 8 ++++---- block/scsi_ioctl.c | 19 +++++++++---------- drivers/scsi/sg.c | 5 +++-- include/linux/blkdev.h | 9 ++++++++- include/linux/bsg.h | 4 ++-- 7 files changed, 30 insertions(+), 21 deletions(-) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 3772671cf2bc..d1ec150a3478 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -838,6 +838,8 @@ static void __blk_release_queue(struct work_struct *work) blk_exit_rl(q, &q->root_rl); + kfree(q->cmd_filter); + if (q->queue_tags) __blk_queue_free_tags(q); diff --git a/block/bsg-lib.c b/block/bsg-lib.c index f3501cdaf1a6..23200d8b035d 100644 --- a/block/bsg-lib.c +++ b/block/bsg-lib.c @@ -41,8 +41,8 @@ static int bsg_transport_check_proto(struct sg_io_v4 *hdr) return 0; } -static int bsg_transport_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, - fmode_t mode) +static int bsg_transport_fill_hdr(struct request_queue *q, struct request *rq, + struct sg_io_v4 *hdr, fmode_t mode) { struct bsg_job *job = blk_mq_rq_to_pdu(rq); diff --git a/block/bsg.c b/block/bsg.c index 9a442c23a715..ec8cbf3bf734 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -69,8 +69,8 @@ static int bsg_scsi_check_proto(struct sg_io_v4 *hdr) return 0; } -static int bsg_scsi_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, - fmode_t mode) +static int bsg_scsi_fill_hdr(struct request_queue *q, struct request *rq, + struct sg_io_v4 *hdr, fmode_t mode) { struct scsi_request *sreq = scsi_req(rq); @@ -83,7 +83,7 @@ static int bsg_scsi_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, if (copy_from_user(sreq->cmd, uptr64(hdr->request), sreq->cmd_len)) return -EFAULT; - if (blk_verify_command(sreq->cmd, mode)) + if (blk_verify_command(q, sreq->cmd, mode)) return -EPERM; return 0; } @@ -159,7 +159,7 @@ static void bsg_scsi_free_rq(struct request *rq) if (IS_ERR(rq)) return rq; - ret = q->bsg_dev.ops->fill_hdr(rq, hdr, mode); + ret = q->bsg_dev.ops->fill_hdr(q, rq, hdr, mode); if (ret) goto out; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 533f4aee8567..5d577c89f9e6 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -34,11 +34,6 @@ #include #include -struct blk_cmd_filter { - unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; - unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; -}; - static struct blk_cmd_filter blk_default_cmd_filter; /* Command group 3 is reserved and should never be used. */ @@ -207,14 +202,18 @@ static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok); } -int blk_verify_command(unsigned char *cmd, fmode_t mode) +int blk_verify_command(struct request_queue *q, unsigned char *cmd, + fmode_t mode) { - struct blk_cmd_filter *filter = &blk_default_cmd_filter; - + struct blk_cmd_filter *filter = q->cmd_filter; + /* root can do any command. */ if (capable(CAP_SYS_RAWIO)) return 0; + if (!filter) + filter = &blk_default_cmd_filter; + /* Anybody who can open the device can do a read-safe command */ if (test_bit(cmd[0], filter->read_ok)) return 0; @@ -234,7 +233,7 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, if (copy_from_user(req->cmd, hdr->cmdp, hdr->cmd_len)) return -EFAULT; - if (blk_verify_command(req->cmd, mode)) + if (blk_verify_command(q, req->cmd, mode)) return -EPERM; /* @@ -468,7 +467,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; - err = blk_verify_command(req->cmd, mode); + err = blk_verify_command(q, req->cmd, mode); if (err) goto error; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 8a254bb46a9b..1b04016d3bb8 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -240,11 +240,12 @@ static int sg_check_file_access(struct file *filp, const char *caller) static int sg_allow_access(struct file *filp, unsigned char *cmd) { struct sg_fd *sfp = filp->private_data; + struct scsi_device *device = sfp->parentdp->device; - if (sfp->parentdp->device->type == TYPE_SCANNER) + if (device->type == TYPE_SCANNER) return 0; - return blk_verify_command(cmd, filp->f_mode); + return blk_verify_command(device->request_queue, cmd, filp->f_mode); } static int diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6980014357d4..df46a36c9467 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -352,6 +352,11 @@ struct blk_queue_tag { #define BLK_SCSI_MAX_CMDS (256) #define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) +struct blk_cmd_filter { + unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; + unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; +}; + /* * Zoned block device models (zoned limit). */ @@ -639,6 +644,7 @@ struct request_queue { bsg_job_fn *bsg_job_fn; struct bsg_class_device bsg_dev; #endif + struct blk_cmd_filter *cmd_filter; #ifdef CONFIG_BLK_DEV_THROTTLING /* Throttle data */ @@ -1424,7 +1430,8 @@ static inline int sb_issue_zeroout(struct super_block *sb, sector_t block, gfp_mask, 0); } -extern int blk_verify_command(unsigned char *cmd, fmode_t mode); +extern int blk_verify_command(struct request_queue *q, unsigned char *cmd, + fmode_t mode); enum blk_default_limits { BLK_MAX_SEGMENTS = 128, diff --git a/include/linux/bsg.h b/include/linux/bsg.h index dac37b6e00ec..461ac68691b9 100644 --- a/include/linux/bsg.h +++ b/include/linux/bsg.h @@ -9,8 +9,8 @@ #ifdef CONFIG_BLK_DEV_BSG struct bsg_ops { int (*check_proto)(struct sg_io_v4 *hdr); - int (*fill_hdr)(struct request *rq, struct sg_io_v4 *hdr, - fmode_t mode); + int (*fill_hdr)(struct request_queue *q, struct request *rq, + struct sg_io_v4 *hdr, fmode_t mode); int (*complete_rq)(struct request *rq, struct sg_io_v4 *hdr); void (*free_rq)(struct request *rq); }; From patchwork Sat Nov 10 16:35:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 10677331 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 19E8D139B for ; Sat, 10 Nov 2018 16:35:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 09D902C6DF for ; Sat, 10 Nov 2018 16:35:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F21402C95B; Sat, 10 Nov 2018 16:35:43 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7677F2C6DF for ; Sat, 10 Nov 2018 16:35:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727215AbeKKCVR (ORCPT ); Sat, 10 Nov 2018 21:21:17 -0500 Received: from mx1.redhat.com ([209.132.183.28]:40822 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726946AbeKKCVR (ORCPT ); Sat, 10 Nov 2018 21:21:17 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 168A93DDB4; Sat, 10 Nov 2018 16:35:42 +0000 (UTC) Received: from 640k.localdomain.com (ovpn-112-24.ams2.redhat.com [10.36.112.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 347F9608C2; Sat, 10 Nov 2018 16:35:40 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org Cc: linux-scsi@vger.kernel.org, Hannes Reinecke , "Martin K. Petersen" , James Bottomley Subject: [PATCH 2/3] scsi: create an all-one filter for scanners Date: Sat, 10 Nov 2018 17:35:32 +0100 Message-Id: <1541867733-7836-3-git-send-email-pbonzini@redhat.com> In-Reply-To: <1541867733-7836-1-git-send-email-pbonzini@redhat.com> References: <1541867733-7836-1-git-send-email-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Sat, 10 Nov 2018 16:35:42 +0000 (UTC) Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Any command is allowed for scanners when /dev/sg is used. Reimplement this using customizable command filters, so that the sysfs knobs will work in this case, too. Cc: linux-scsi@vger.kernel.org Cc: Hannes Reinecke Cc: Martin K. Petersen Cc: James Bottomley Signed-off-by: Paolo Bonzini --- drivers/scsi/scsi_scan.c | 13 +++++++++++++ drivers/scsi/sg.c | 3 --- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 78ca63dfba4a..ceb7f5535f44 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -844,6 +844,19 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, *bflags |= BLIST_NOREPORTLUN; } + if (sdev->type == TYPE_SCANNER) { + sdev->request_queue->cmd_filter = + kzalloc(sizeof(struct blk_cmd_filter), GFP_KERNEL); + + if (!sdev->request_queue->cmd_filter) + return SCSI_SCAN_NO_RESPONSE; + + memset(sdev->request_queue->cmd_filter->read_ok, 0xFF, + sizeof(sdev->request_queue->cmd_filter->read_ok)); + memset(sdev->request_queue->cmd_filter->write_ok, 0xFF, + sizeof(sdev->request_queue->cmd_filter->write_ok)); + } + /* * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI * spec says: The device server is capable of supporting the diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 1b04016d3bb8..e04acf41f283 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -242,9 +242,6 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd) struct sg_fd *sfp = filp->private_data; struct scsi_device *device = sfp->parentdp->device; - if (device->type == TYPE_SCANNER) - return 0; - return blk_verify_command(device->request_queue, cmd, filp->f_mode); } From patchwork Sat Nov 10 16:35:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 10677333 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 DF2BC14DB for ; Sat, 10 Nov 2018 16:35:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CCDC92C6DF for ; Sat, 10 Nov 2018 16:35:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C13402C95B; Sat, 10 Nov 2018 16:35:52 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CE4792C6DF for ; Sat, 10 Nov 2018 16:35:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727298AbeKKCVV (ORCPT ); Sat, 10 Nov 2018 21:21:21 -0500 Received: from mx1.redhat.com ([209.132.183.28]:39082 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727271AbeKKCVU (ORCPT ); Sat, 10 Nov 2018 21:21:20 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6C62058E3F; Sat, 10 Nov 2018 16:35:44 +0000 (UTC) Received: from 640k.localdomain.com (ovpn-112-24.ams2.redhat.com [10.36.112.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 880B2608C2; Sat, 10 Nov 2018 16:35:42 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org Cc: linux-scsi@vger.kernel.org, Hannes Reinecke , "Martin K. Petersen" , James Bottomley Subject: [PATCH 3/3] block: add back command filter modification via sysfs Date: Sat, 10 Nov 2018 17:35:33 +0100 Message-Id: <1541867733-7836-4-git-send-email-pbonzini@redhat.com> In-Reply-To: <1541867733-7836-1-git-send-email-pbonzini@redhat.com> References: <1541867733-7836-1-git-send-email-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Sat, 10 Nov 2018 16:35:44 +0000 (UTC) Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds two new sysfs attributes to the queue kobject. The attributes allow reading and writing the whitelist of unprivileged commands. This is again a bit different from what was removed in commit 018e044 (block: get rid of queue-private command filter, 2009-06-26), but the idea is the same. One difference is that it does not use a separate kobject. Also, the supported sysfs syntax is a bit more expressive: it includes ranges, the ability to replace all of the filter with a single command, and does not force usage of hexadecimal. Since the names are different, and the old ones were anyway never really enabled, the different userspace API is not a problem. Cc: linux-scsi@vger.kernel.org Cc: Hannes Reinecke Cc: Martin K. Petersen Cc: James Bottomley Suggested-by: James Bottomley Signed-off-by: Paolo Bonzini --- Documentation/block/queue-sysfs.txt | 19 ++++++ block/Kconfig | 10 +++ block/blk-sysfs.c | 41 +++++++++++++ block/scsi_ioctl.c | 117 ++++++++++++++++++++++++++++++++++++ include/linux/blkdev.h | 9 +++ 5 files changed, 196 insertions(+) diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt index 2c1e67058fd3..1fe5fe5fd80a 100644 --- a/Documentation/block/queue-sysfs.txt +++ b/Documentation/block/queue-sysfs.txt @@ -162,6 +162,25 @@ control of this block device to that new IO scheduler. Note that writing an IO scheduler name to this file will attempt to load that IO scheduler module, if it isn't already present in the system. +sgio_read_filter (RW) +--------------------- +When read, this file will display a list of SCSI commands (i.e. values of +the first byte of a CDB) that are always available for unprivileged users +via /dev/bsg, /dev/sgNN, or ioctls such as SG_IO and CDROM_SEND_PACKET. +When written, the list of commands will be modified. The default filter +can be restored by writing "default" to the file; otherwise the input should +be a list of byte values or ranges such as "0x00-0xff". In the latter case, +instead of replacing the filter completely you can add to the commands, +by writing a string that begins with '+', or remove them by writing a +string that begins with '-'. + +sgio_write_filter (RW) +---------------------- +When read, this file will display a list of SCSI commands (i.e. values of +the first byte of a CDB) that are available for unprivileged users +when the block device is open for writing. Writing to this file behaves +as for sgio_read_filter. + write_cache (RW) ---------------- When read, this file will display whether the device has write back diff --git a/block/Kconfig b/block/Kconfig index 1f2469a0123c..a5bc37d50e07 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -71,6 +71,16 @@ config BLK_DEV_BSG access device serial numbers, etc. If unsure, say Y. + +config BLK_DEV_SG_FILTER_SYSFS + bool "Customizable SG_IO filters in sysfs" + default y + help + Saying Y here will let you use sysfs to customize the list + of SCSI commands that are available (via /dev/sg, /dev/bsg or + ioctls such as SG_IO) to unprivileged users. + + If unsure, say Y. config BLK_DEV_BSGLIB bool "Block layer SG support v4 helper lib" diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index d1ec150a3478..ea2a47272bcf 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -703,6 +703,43 @@ static ssize_t queue_dax_show(struct request_queue *q, char *page) }; #endif +#ifdef CONFIG_BLK_DEV_SG_FILTER_SYSFS +static ssize_t queue_sgio_filter_read_show(struct request_queue *q, char *page) +{ + return blk_filter_show(q, page, READ); +} + +static ssize_t queue_sgio_filter_write_show(struct request_queue *q, + char *page) +{ + return blk_filter_show(q, page, WRITE); +} + +static ssize_t queue_sgio_filter_read_store(struct request_queue *q, + const char *page, size_t count) +{ + return blk_filter_store(q, page, count, READ); +} + +static ssize_t queue_sgio_filter_write_store(struct request_queue *q, + const char *page, size_t count) +{ + return blk_filter_store(q, page, count, WRITE); +} + +static struct queue_sysfs_entry queue_sgio_filter_read_entry = { + .attr = { .name = "sgio_filter_read", .mode = S_IRUGO | S_IWUSR }, + .show = queue_sgio_filter_read_show, + .store = queue_sgio_filter_read_store, +}; + +static struct queue_sysfs_entry queue_sgio_filter_write_entry = { + .attr = {.name = "sgio_filter_write", .mode = S_IRUGO | S_IWUSR }, + .show = queue_sgio_filter_write_show, + .store = queue_sgio_filter_write_store, +}; +#endif + static struct attribute *default_attrs[] = { &queue_requests_entry.attr, &queue_ra_entry.attr, @@ -740,6 +777,10 @@ static ssize_t queue_dax_show(struct request_queue *q, char *page) #ifdef CONFIG_BLK_DEV_THROTTLING_LOW &throtl_sample_time_entry.attr, #endif +#ifdef CONFIG_BLK_DEV_SG_FILTER_SYSFS + &queue_sgio_filter_read_entry.attr, + &queue_sgio_filter_write_entry.attr, +#endif NULL, }; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 5d577c89f9e6..c5f089e7d869 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -725,6 +726,125 @@ void scsi_req_init(struct scsi_request *req) } EXPORT_SYMBOL(scsi_req_init); + +#ifdef CONFIG_BLK_DEV_SG_FILTER_SYSFS +ssize_t blk_filter_show(struct request_queue *q, char *page, int rw) +{ + struct blk_cmd_filter *filter; + char *p = page; + unsigned long *okbits; + int i; + + filter = q->cmd_filter; + if (!filter) + filter = &blk_default_cmd_filter; + + if (rw == READ) + okbits = filter->read_ok; + else + okbits = filter->write_ok; + + for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) + if (test_bit(i, okbits)) + p += sprintf(p, "0x%02x ", i); + + if (p > page) + p[-1] = '\n'; + + return p - page; +} +EXPORT_SYMBOL_GPL(blk_filter_show); + +ssize_t blk_filter_store(struct request_queue *q, + const char *page, size_t count, int rw) +{ + unsigned long bits[BLK_SCSI_CMD_PER_LONG], *target_bits; + bool set; + const char *p = page; + char *endp; + int start = -1, cmd; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (sysfs_streq(p, "default")) { + if (!q->cmd_filter) + return 0; + if (rw == READ) + memcpy(q->cmd_filter->read_ok, + blk_default_cmd_filter.read_ok, + sizeof(blk_default_cmd_filter.read_ok)); + else + memcpy(q->cmd_filter->write_ok, + blk_default_cmd_filter.write_ok, + sizeof(blk_default_cmd_filter.write_ok)); + return count; + } + + if (!q->cmd_filter) { + q->cmd_filter = kmemdup(&blk_default_cmd_filter, + sizeof(struct blk_cmd_filter), + GFP_KERNEL); + if (!q->cmd_filter) + return -ENOMEM; + } + + if (rw == READ) + target_bits = q->cmd_filter->read_ok; + else + target_bits = q->cmd_filter->write_ok; + + set = (p[0] != '-'); + if (p[0] != '-' && p[0] != '+') + memset(bits, 0, sizeof(bits)); + else { + memcpy(bits, target_bits, sizeof(bits)); + p++; + } + + while (p < page + count) { + if (start == -1 && isspace(*p)) { + p++; + continue; + } + + cmd = simple_strtol(p, &endp, 0); + if (endp == p || cmd < 0 || cmd >= BLK_SCSI_MAX_CMDS) + return -EINVAL; + + /* Verify the character immediately after the number, if any */ + p = endp; + if (p < page + count) { + if (start == -1 && *p == '-') { + start = cmd; + p++; + continue; + } + if (!isspace(*p)) + return -EINVAL; + } + + if (start == -1) + start = cmd; + + for (; start <= cmd; start++) + if (set) + __set_bit(start, bits); + else + __clear_bit(start, bits); + start = -1; + } + + /* Did the string end with a dash? */ + if (start != -1) + return -EINVAL; + + memcpy(target_bits, bits, sizeof(bits)); + return count; +} +EXPORT_SYMBOL_GPL(blk_filter_store); +#endif + static int __init blk_scsi_ioctl_init(void) { blk_set_cmd_filter_defaults(&blk_default_cmd_filter); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index df46a36c9467..5110cd6d0d16 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1430,9 +1430,18 @@ static inline int sb_issue_zeroout(struct super_block *sb, sector_t block, gfp_mask, 0); } +/* + * Command filter functions + */ extern int blk_verify_command(struct request_queue *q, unsigned char *cmd, fmode_t mode); +#ifdef CONFIG_BLK_DEV_SG_FILTER_SYSFS +ssize_t blk_filter_show(struct request_queue *q, char *page, int rw); +ssize_t blk_filter_store(struct request_queue *q, + const char *page, size_t count, int rw); +#endif /* CONFIG_BLK_DEV_SG_FILTER_SYSFS */ + enum blk_default_limits { BLK_MAX_SEGMENTS = 128, BLK_SAFE_MAX_SECTORS = 255,