From patchwork Wed Apr 21 17:16:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kleber Sacilotto de Souza X-Patchwork-Id: 1468775 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FQS15496xz9sWX; Thu, 22 Apr 2021 03:17:44 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1lZGTq-0003jz-Gm; Wed, 21 Apr 2021 17:17:38 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1lZGTn-0003jV-GG for kernel-team@lists.ubuntu.com; Wed, 21 Apr 2021 17:17:35 +0000 Received: from mail-ed1-f72.google.com ([209.85.208.72]) by youngberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1lZGTn-0006CZ-93 for kernel-team@lists.ubuntu.com; Wed, 21 Apr 2021 17:17:35 +0000 Received: by mail-ed1-f72.google.com with SMTP id h13-20020a05640250cdb02903790a9c55acso15367806edb.4 for ; Wed, 21 Apr 2021 10:17:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=GWO+EFWThK/645dypK5m5d0tIQgly5n4NOPrM4lNotw=; b=cEfR6lHgTKT9UZy1tvPpp/77pLzAm4ClmhmXynx4f6bdr+n6T2rIB+nf0UyK6HiSPz dIPfd2Sq3XUf3/ZdEj7j74ZRdoKNmiSV1UG0Vq46IAtdcH3HQrxCXjs9fS4up1RUMHT1 N0DN11w+osTq2wlXyKO3U/3LPifwipXKhuVIcqfgUTRZYsW1JAPN0HjZhYNtSI3fzO/j 22poO0Mrr+vNZuWjUOdIIP5cZu51Wwje6vl21m8WUms0HKPrFq64ivk3X39+9z0rGIXU 7m/aYpXnLDpkr23VT6hbLZ+kGHTKDt2owm8SaVz20vPvgkrAjsuxFKZmvJUGcRmZ6MZI w1fg== X-Gm-Message-State: AOAM531GGwCkRn99sdaRBX87L1JKw++GUdHRYxAi0tynzzS0Sj9uFMgd JbltiRfEgKXg/I9PWwnU8ENy18wr7363r3P9LnXIEa8x69/dRI8PonxBPp9EgrEQBVUaEJ+UfNZ C5ea+jL82GlTKvWI/gdJhKxzOUyPQ1UUz8FBElvr+rw== X-Received: by 2002:a17:907:ea7:: with SMTP id ho39mr27465358ejc.315.1619025454979; Wed, 21 Apr 2021 10:17:34 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwKzAqwH99WIOYz7Z6yOQr/LWygveqVw3rmGqtfVD7ffZqswMiZyJB0wGcqJIQ5C0S17nrn6Q== X-Received: by 2002:a17:907:ea7:: with SMTP id ho39mr27465334ejc.315.1619025454717; Wed, 21 Apr 2021 10:17:34 -0700 (PDT) Received: from localhost.localdomain (ipbcc333e7.dynamic.kabel-deutschland.de. [188.195.51.231]) by smtp.gmail.com with ESMTPSA id h16sm35142edr.19.2021.04.21.10.17.34 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Apr 2021 10:17:34 -0700 (PDT) From: Kleber Sacilotto de Souza To: kernel-team@lists.ubuntu.com Subject: [SRU][Groovy][PATCH 1/2] UBUNTU: SAUCE: Revert "tty: implement read_iter" Date: Wed, 21 Apr 2021 19:16:59 +0200 Message-Id: <20210421171700.3357543-2-kleber.souza@canonical.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210421171700.3357543-1-kleber.souza@canonical.com> References: <20210421171700.3357543-1-kleber.souza@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1925290 This reverts commit b7bfa1af145a6aa3868894a4be82f7b2034c564a (Upstream commit dd78b0c483e33225e0e0782b0ed887129b00f956). This commit introduced a regression on the tty code caught by hangup01 testcase from ltp pty tests, so revert it until a follow-up fix is not found. Signed-off-by: Kleber Sacilotto de Souza --- drivers/tty/tty_io.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 895763337afc..c2b19e10423b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -142,7 +142,7 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ /* Mutex to protect creating and releasing a tty */ DEFINE_MUTEX(tty_mutex); -static ssize_t tty_read(struct kiocb *, struct iov_iter *); +static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_write(struct kiocb *, struct iov_iter *); static __poll_t tty_poll(struct file *, poll_table *); static int tty_open(struct inode *, struct file *); @@ -473,9 +473,8 @@ static void tty_show_fdinfo(struct seq_file *m, struct file *file) static const struct file_operations tty_fops = { .llseek = no_llseek, - .read_iter = tty_read, + .read = tty_read, .write_iter = tty_write, - .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .poll = tty_poll, .unlocked_ioctl = tty_ioctl, @@ -488,9 +487,8 @@ static const struct file_operations tty_fops = { static const struct file_operations console_fops = { .llseek = no_llseek, - .read_iter = tty_read, + .read = tty_read, .write_iter = redirected_tty_write, - .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .poll = tty_poll, .unlocked_ioctl = tty_ioctl, @@ -843,17 +841,16 @@ static void tty_update_time(struct timespec64 *time) * data or clears the cookie. The cookie may be something that the * ldisc maintains state for and needs to free. */ -static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, - struct file *file, struct iov_iter *to) +static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, struct file *file, + char __user *buf, size_t count) { int retval = 0; void *cookie = NULL; unsigned long offset = 0; char kernel_buf[64]; - size_t count = iov_iter_count(to); do { - int size, copied; + int size, uncopied; size = count > sizeof(kernel_buf) ? sizeof(kernel_buf) : count; size = ld->ops->read(tty, file, kernel_buf, size, &cookie, offset); @@ -869,9 +866,10 @@ static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, return size; } - copied = copy_to_iter(kernel_buf, size, to); - offset += copied; - count -= copied; + uncopied = copy_to_user(buf+offset, kernel_buf, size); + size -= uncopied; + offset += size; + count -= size; /* * If the user copy failed, we still need to do another ->read() @@ -879,7 +877,7 @@ static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, * * But make sure size is zeroed. */ - if (unlikely(copied != size)) { + if (unlikely(uncopied)) { count = 0; retval = -EFAULT; } @@ -906,10 +904,10 @@ static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, * read calls may be outstanding in parallel. */ -static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to) +static ssize_t tty_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) { int i; - struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; @@ -922,9 +920,11 @@ static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to) /* We want to wait for the line discipline to sort out in this situation */ ld = tty_ldisc_ref_wait(tty); + if (!ld) + return hung_up_tty_read(file, buf, count, ppos); i = -EIO; - if (ld && ld->ops->read) - i = iterate_tty_read(ld, tty, file, to); + if (ld->ops->read) + i = iterate_tty_read(ld, tty, file, buf, count); tty_ldisc_deref(ld); if (i > 0) @@ -2945,7 +2945,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, static int this_tty(const void *t, struct file *file, unsigned fd) { - if (likely(file->f_op->read_iter != tty_read)) + if (likely(file->f_op->read != tty_read)) return 0; return file_tty(file) != t ? 0 : fd + 1; } From patchwork Wed Apr 21 17:17:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kleber Sacilotto de Souza X-Patchwork-Id: 1468777 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FQS15521Zz9sWd; Thu, 22 Apr 2021 03:17:45 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1lZGTt-0003kv-P2; Wed, 21 Apr 2021 17:17:41 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1lZGTo-0003jl-OK for kernel-team@lists.ubuntu.com; Wed, 21 Apr 2021 17:17:36 +0000 Received: from mail-ej1-f71.google.com ([209.85.218.71]) by youngberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1lZGTo-0006Cf-Eq for kernel-team@lists.ubuntu.com; Wed, 21 Apr 2021 17:17:36 +0000 Received: by mail-ej1-f71.google.com with SMTP id j25-20020a1709060519b029037cb8ca241aso6140998eja.19 for ; Wed, 21 Apr 2021 10:17:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=atXN0aXLmQKCW6Kgx58d4vBy7XP6to90PRpKS9znIbM=; b=Z2sikEly63TfF7P+rMQYu7qf/YP8P71qgS2W/Fh78zPcesMj4Iq80wm39uqQHS2exJ tqYP46SfnPK0SJv4R3R9UjPpb/uqVQLtoSyxSDwoNl+1thJQ1ozsLlesWi2se7CYFy7U d4A4OMpUwdRgfl2mfl5ik4GwvXNNg1b1VS5kpautNrWjCfsalOpQuY+RrhPo2D867iqR rTHktjCXYQPxTdzL71ABnvLIGb4lcq2eK2ULGcumBVoJNK/AQRTwBXD22Pc3iL8QqGBn JTeUpQe2rm9aQZsByNerGLzEiyxFNzNIkTpKUu+4w/6Oe9+FRzO9SF5VrOPj3Dx+oBQl vNbw== X-Gm-Message-State: AOAM532LRMS1nH8SPWEAAnE4nNVNuPv9RoSEnL00SywYhgvNpv3kk1Dn uw96L+vFtoCePVjEb0qrktj5cIIKf1zupMqA21O6xxx1ryIseDX9wohIlUNDlQz6x3a+5LTvIsx pL0ws0ZhPxfxFrJnuCoYZsJ3Dlpipi8EeYp5cWIULuw== X-Received: by 2002:a17:906:90b:: with SMTP id i11mr34103343ejd.168.1619025456035; Wed, 21 Apr 2021 10:17:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyZKb9Gg0FAbhdgyy3eYGmjxiekF4Evv6oNkqw1Fw9sMjNH6Nk31NVQ1t2Eu0Lk8Ysb4+gytA== X-Received: by 2002:a17:906:90b:: with SMTP id i11mr34103314ejd.168.1619025455625; Wed, 21 Apr 2021 10:17:35 -0700 (PDT) Received: from localhost.localdomain (ipbcc333e7.dynamic.kabel-deutschland.de. [188.195.51.231]) by smtp.gmail.com with ESMTPSA id h16sm35142edr.19.2021.04.21.10.17.34 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Apr 2021 10:17:35 -0700 (PDT) From: Kleber Sacilotto de Souza To: kernel-team@lists.ubuntu.com Subject: [SRU][Groovy][PATCH 2/2] UBUNTU: SAUCE: Revert "tty: convert tty_ldisc_ops 'read()' function to take a kernel pointer" Date: Wed, 21 Apr 2021 19:17:00 +0200 Message-Id: <20210421171700.3357543-3-kleber.souza@canonical.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210421171700.3357543-1-kleber.souza@canonical.com> References: <20210421171700.3357543-1-kleber.souza@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1925290 This reverts commit 4b71b60ef2cb9f930b8056049a1d8de170be42bc (Upstream commit 3b830a9c34d5897be07176ce4e6f2d75e2c8cfd7). This commit introduced a regression on the tty code caught by hangup01 testcase from ltp pty tests, so revert it until a follow-up fix is not found. Signed-off-by: Kleber Sacilotto de Souza --- drivers/bluetooth/hci_ldisc.c | 34 +++++++-------- drivers/input/serio/serport.c | 4 +- drivers/net/ppp/ppp_async.c | 3 +- drivers/net/ppp/ppp_synctty.c | 3 +- drivers/tty/n_gsm.c | 3 +- drivers/tty/n_hdlc.c | 60 ++++++++----------------- drivers/tty/n_null.c | 3 +- drivers/tty/n_r3964.c | 10 +++-- drivers/tty/n_tracerouter.c | 4 +- drivers/tty/n_tracesink.c | 4 +- drivers/tty/n_tty.c | 82 ++++++++++++++++++++--------------- drivers/tty/tty_io.c | 64 ++------------------------- include/linux/tty_ldisc.h | 3 +- net/nfc/nci/uart.c | 3 +- 14 files changed, 102 insertions(+), 178 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 637c5b8c2aa1..8be4d807d137 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -801,8 +801,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, * We don't provide read/write/poll interface for user space. */ static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t nr, - void **cookie, unsigned long offset) + unsigned char __user *buf, size_t nr) { return 0; } @@ -819,28 +818,29 @@ static __poll_t hci_uart_tty_poll(struct tty_struct *tty, return 0; } -static struct tty_ldisc_ops hci_uart_ldisc = { - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "n_hci", - .open = hci_uart_tty_open, - .close = hci_uart_tty_close, - .read = hci_uart_tty_read, - .write = hci_uart_tty_write, - .ioctl = hci_uart_tty_ioctl, - .compat_ioctl = hci_uart_tty_ioctl, - .poll = hci_uart_tty_poll, - .receive_buf = hci_uart_tty_receive, - .write_wakeup = hci_uart_tty_wakeup, -}; - static int __init hci_uart_init(void) { + static struct tty_ldisc_ops hci_uart_ldisc; int err; BT_INFO("HCI UART driver ver %s", VERSION); /* Register the tty discipline */ + + memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc)); + hci_uart_ldisc.magic = TTY_LDISC_MAGIC; + hci_uart_ldisc.name = "n_hci"; + hci_uart_ldisc.open = hci_uart_tty_open; + hci_uart_ldisc.close = hci_uart_tty_close; + hci_uart_ldisc.read = hci_uart_tty_read; + hci_uart_ldisc.write = hci_uart_tty_write; + hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; + hci_uart_ldisc.compat_ioctl = hci_uart_tty_ioctl; + hci_uart_ldisc.poll = hci_uart_tty_poll; + hci_uart_ldisc.receive_buf = hci_uart_tty_receive; + hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; + hci_uart_ldisc.owner = THIS_MODULE; + err = tty_register_ldisc(N_HCI, &hci_uart_ldisc); if (err) { BT_ERR("HCI line discipline registration failed. (%d)", err); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 33e9d9bfd036..8ac970a423de 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -156,9 +156,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c * returning 0 characters. */ -static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, - unsigned char *kbuf, size_t nr, - void **cookie, unsigned long offset) +static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr) { struct serport *serport = (struct serport*) tty->disc_data; struct serio *serio; diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index f14a9d190de9..29a0917a81e6 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -259,8 +259,7 @@ static int ppp_asynctty_hangup(struct tty_struct *tty) */ static ssize_t ppp_asynctty_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t count, - void **cookie, unsigned long offset) + unsigned char __user *buf, size_t count) { return -EAGAIN; } diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index f774b7e52da4..0f338752c38b 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -257,8 +257,7 @@ static int ppp_sync_hangup(struct tty_struct *tty) */ static ssize_t ppp_sync_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t count, - void **cookie, unsigned long offset) + unsigned char __user *buf, size_t count) { return -EAGAIN; } diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 2ed18274604a..0a29a94ec438 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2561,8 +2561,7 @@ static void gsmld_write_wakeup(struct tty_struct *tty) */ static ssize_t gsmld_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t nr, - void **cookie, unsigned long offset) + unsigned char __user *buf, size_t nr) { return -EOPNOTSUPP; } diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 16f621ccdc79..b09eac4b6d64 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -416,19 +416,13 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, * Returns the number of bytes returned or error code. */ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, - __u8 *kbuf, size_t nr, - void **cookie, unsigned long offset) + __u8 __user *buf, size_t nr) { struct n_hdlc *n_hdlc = tty->disc_data; int ret = 0; struct n_hdlc_buf *rbuf; DECLARE_WAITQUEUE(wait, current); - /* Is this a repeated call for an rbuf we already found earlier? */ - rbuf = *cookie; - if (rbuf) - goto have_rbuf; - add_wait_queue(&tty->read_wait, &wait); for (;;) { @@ -442,8 +436,25 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, set_current_state(TASK_INTERRUPTIBLE); rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); - if (rbuf) + if (rbuf) { + if (rbuf->count > nr) { + /* too large for caller's buffer */ + ret = -EOVERFLOW; + } else { + __set_current_state(TASK_RUNNING); + if (copy_to_user(buf, rbuf->buf, rbuf->count)) + ret = -EFAULT; + else + ret = rbuf->count; + } + + if (n_hdlc->rx_free_buf_list.count > + DEFAULT_RX_BUF_COUNT) + kfree(rbuf); + else + n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf); break; + } /* no data */ if (tty_io_nonblock(tty, file)) { @@ -462,39 +473,6 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, remove_wait_queue(&tty->read_wait, &wait); __set_current_state(TASK_RUNNING); - if (!rbuf) - return ret; - *cookie = rbuf; - -have_rbuf: - /* Have we used it up entirely? */ - if (offset >= rbuf->count) - goto done_with_rbuf; - - /* More data to go, but can't copy any more? EOVERFLOW */ - ret = -EOVERFLOW; - if (!nr) - goto done_with_rbuf; - - /* Copy as much data as possible */ - ret = rbuf->count - offset; - if (ret > nr) - ret = nr; - memcpy(kbuf, rbuf->buf+offset, ret); - offset += ret; - - /* If we still have data left, we leave the rbuf in the cookie */ - if (offset < rbuf->count) - return ret; - -done_with_rbuf: - *cookie = NULL; - - if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) - kfree(rbuf); - else - n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf); - return ret; } /* end of n_hdlc_tty_read() */ diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c index ce03ae78f5c6..96feabae4740 100644 --- a/drivers/tty/n_null.c +++ b/drivers/tty/n_null.c @@ -20,8 +20,7 @@ static void n_null_close(struct tty_struct *tty) } static ssize_t n_null_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t nr, - void **cookie, unsigned long offset) + unsigned char __user * buf, size_t nr) { return -EOPNOTSUPP; } diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 99210a2cf702..f75696f0ee2d 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -129,7 +129,7 @@ static void remove_client_block(struct r3964_info *pInfo, static int r3964_open(struct tty_struct *tty); static void r3964_close(struct tty_struct *tty); static ssize_t r3964_read(struct tty_struct *tty, struct file *file, - void *cookie, unsigned char *buf, size_t nr); + unsigned char __user * buf, size_t nr); static ssize_t r3964_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr); static int r3964_ioctl(struct tty_struct *tty, struct file *file, @@ -1059,8 +1059,7 @@ static void r3964_close(struct tty_struct *tty) } static ssize_t r3964_read(struct tty_struct *tty, struct file *file, - unsigned char *kbuf, size_t nr, - void **cookie, unsigned long offset) + unsigned char __user * buf, size_t nr) { struct r3964_info *pInfo = tty->disc_data; struct r3964_client_info *pClient; @@ -1111,7 +1110,10 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, kfree(pMsg); TRACE_M("r3964_read - msg kfree %p", pMsg); - memcpy(kbuf, &theMsg, ret); + if (copy_to_user(buf, &theMsg, ret)) { + ret = -EFAULT; + goto unlock; + } TRACE_PS("read - return %d", ret); goto unlock; diff --git a/drivers/tty/n_tracerouter.c b/drivers/tty/n_tracerouter.c index 3490ed51b1a3..4479af4d2fa5 100644 --- a/drivers/tty/n_tracerouter.c +++ b/drivers/tty/n_tracerouter.c @@ -118,9 +118,7 @@ static void n_tracerouter_close(struct tty_struct *tty) * -EINVAL */ static ssize_t n_tracerouter_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t nr, - void **cookie, unsigned long offset) -{ + unsigned char __user *buf, size_t nr) { return -EINVAL; } diff --git a/drivers/tty/n_tracesink.c b/drivers/tty/n_tracesink.c index 1d9931041fd8..d96ba82cc356 100644 --- a/drivers/tty/n_tracesink.c +++ b/drivers/tty/n_tracesink.c @@ -115,9 +115,7 @@ static void n_tracesink_close(struct tty_struct *tty) * -EINVAL */ static ssize_t n_tracesink_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t nr, - void **cookie, unsigned long offset) -{ + unsigned char __user *buf, size_t nr) { return -EINVAL; } diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 76adaa3c7581..0130579fa79d 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -164,24 +164,29 @@ static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size) memset(buffer, 0x00, size); } -static void tty_copy(struct tty_struct *tty, void *to, size_t tail, size_t n) +static int tty_copy_to_user(struct tty_struct *tty, void __user *to, + size_t tail, size_t n) { struct n_tty_data *ldata = tty->disc_data; size_t size = N_TTY_BUF_SIZE - tail; void *from = read_buf_addr(ldata, tail); + int uncopied; if (n > size) { tty_audit_add_data(tty, from, size); - memcpy(to, from, size); - zero_buffer(tty, from, size); + uncopied = copy_to_user(to, from, size); + zero_buffer(tty, from, size - uncopied); + if (uncopied) + return uncopied; to += size; n -= size; from = ldata->read_buf; } tty_audit_add_data(tty, from, n); - memcpy(to, from, n); - zero_buffer(tty, from, n); + uncopied = copy_to_user(to, from, n); + zero_buffer(tty, from, n - uncopied); + return uncopied; } /** @@ -1937,16 +1942,15 @@ static inline int input_available_p(struct tty_struct *tty, int poll) /** * copy_from_read_buf - copy read data directly * @tty: terminal device - * @kbp: data + * @b: user data * @nr: size of data * * Helper function to speed up n_tty_read. It is only called when - * ICANON is off; it copies characters straight from the tty queue. - * - * It can be profitably called twice; once to drain the space from - * the tail pointer to the (physical) end of the buffer, and once - * to drain the space from the (physical) beginning of the buffer - * to head pointer. + * ICANON is off; it copies characters straight from the tty queue to + * user space directly. It can be profitably called twice; once to + * drain the space from the tail pointer to the (physical) end of the + * buffer, and once to drain the space from the (physical) beginning of + * the buffer to head pointer. * * Called under the ldata->atomic_read_lock sem * @@ -1956,7 +1960,7 @@ static inline int input_available_p(struct tty_struct *tty, int poll) */ static int copy_from_read_buf(struct tty_struct *tty, - unsigned char **kbp, + unsigned char __user **b, size_t *nr) { @@ -1972,7 +1976,8 @@ static int copy_from_read_buf(struct tty_struct *tty, n = min(*nr, n); if (n) { unsigned char *from = read_buf_addr(ldata, tail); - memcpy(*kbp, from, n); + retval = copy_to_user(*b, from, n); + n -= retval; is_eof = n == 1 && *from == EOF_CHAR(tty); tty_audit_add_data(tty, from, n); zero_buffer(tty, from, n); @@ -1981,7 +1986,7 @@ static int copy_from_read_buf(struct tty_struct *tty, if (L_EXTPROC(tty) && ldata->icanon && is_eof && (head == ldata->read_tail)) n = 0; - *kbp += n; + *b += n; *nr -= n; } return retval; @@ -1990,12 +1995,12 @@ static int copy_from_read_buf(struct tty_struct *tty, /** * canon_copy_from_read_buf - copy read data in canonical mode * @tty: terminal device - * @kbp: data + * @b: user data * @nr: size of data * * Helper function for n_tty_read. It is only called when ICANON is on; * it copies one line of input up to and including the line-delimiting - * character into the result buffer. + * character into the user-space buffer. * * NB: When termios is changed from non-canonical to canonical mode and * the read buffer contains data, n_tty_set_termios() simulates an EOF @@ -2011,14 +2016,14 @@ static int copy_from_read_buf(struct tty_struct *tty, */ static int canon_copy_from_read_buf(struct tty_struct *tty, - unsigned char **kbp, + unsigned char __user **b, size_t *nr) { struct n_tty_data *ldata = tty->disc_data; size_t n, size, more, c; size_t eol; size_t tail; - int found = 0; + int ret, found = 0; /* N.B. avoid overrun if nr == 0 */ if (!*nr) @@ -2054,8 +2059,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n", __func__, eol, found, n, c, tail, more); - tty_copy(tty, *kbp, tail, n); - *kbp += n; + ret = tty_copy_to_user(tty, *b, tail, n); + if (ret) + return -EFAULT; + *b += n; *nr -= n; if (found) @@ -2120,11 +2127,10 @@ static int job_control(struct tty_struct *tty, struct file *file) */ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, - unsigned char *kbuf, size_t nr, - void **cookie, unsigned long offset) + unsigned char __user *buf, size_t nr) { struct n_tty_data *ldata = tty->disc_data; - unsigned char *kb = kbuf; + unsigned char __user *b = buf; DEFINE_WAIT_FUNC(wait, woken_wake_function); int c; int minimum, time; @@ -2170,13 +2176,17 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, /* First test for status change. */ if (packet && tty->link->ctrl_status) { unsigned char cs; - if (kb != kbuf) + if (b != buf) break; spin_lock_irq(&tty->link->ctrl_lock); cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; spin_unlock_irq(&tty->link->ctrl_lock); - *kb++ = cs; + if (put_user(cs, b)) { + retval = -EFAULT; + break; + } + b++; nr--; break; } @@ -2219,20 +2229,24 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } if (ldata->icanon && !L_EXTPROC(tty)) { - retval = canon_copy_from_read_buf(tty, &kb, &nr); + retval = canon_copy_from_read_buf(tty, &b, &nr); if (retval) break; } else { int uncopied; /* Deal with packet mode. */ - if (packet && kb == kbuf) { - *kb++ = TIOCPKT_DATA; + if (packet && b == buf) { + if (put_user(TIOCPKT_DATA, b)) { + retval = -EFAULT; + break; + } + b++; nr--; } - uncopied = copy_from_read_buf(tty, &kb, &nr); - uncopied += copy_from_read_buf(tty, &kb, &nr); + uncopied = copy_from_read_buf(tty, &b, &nr); + uncopied += copy_from_read_buf(tty, &b, &nr); if (uncopied) { retval = -EFAULT; break; @@ -2241,7 +2255,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, n_tty_check_unthrottle(tty); - if (kb - kbuf >= minimum) + if (b - buf >= minimum) break; if (time) timeout = time; @@ -2253,8 +2267,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, remove_wait_queue(&tty->read_wait, &wait); mutex_unlock(&ldata->atomic_read_lock); - if (kb - kbuf) - retval = kb - kbuf; + if (b - buf) + retval = b - buf; return retval; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c2b19e10423b..7115e09634b9 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -830,65 +830,6 @@ static void tty_update_time(struct timespec64 *time) time->tv_sec = sec; } -/* - * Iterate on the ldisc ->read() function until we've gotten all - * the data the ldisc has for us. - * - * The "cookie" is something that the ldisc read function can fill - * in to let us know that there is more data to be had. - * - * We promise to continue to call the ldisc until it stops returning - * data or clears the cookie. The cookie may be something that the - * ldisc maintains state for and needs to free. - */ -static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, struct file *file, - char __user *buf, size_t count) -{ - int retval = 0; - void *cookie = NULL; - unsigned long offset = 0; - char kernel_buf[64]; - - do { - int size, uncopied; - - size = count > sizeof(kernel_buf) ? sizeof(kernel_buf) : count; - size = ld->ops->read(tty, file, kernel_buf, size, &cookie, offset); - if (!size) - break; - - /* - * A ldisc read error return will override any previously copied - * data (eg -EOVERFLOW from HDLC) - */ - if (size < 0) { - memzero_explicit(kernel_buf, sizeof(kernel_buf)); - return size; - } - - uncopied = copy_to_user(buf+offset, kernel_buf, size); - size -= uncopied; - offset += size; - count -= size; - - /* - * If the user copy failed, we still need to do another ->read() - * call if we had a cookie to let the ldisc clear up. - * - * But make sure size is zeroed. - */ - if (unlikely(uncopied)) { - count = 0; - retval = -EFAULT; - } - } while (cookie); - - /* We always clear tty buffer in case they contained passwords */ - memzero_explicit(kernel_buf, sizeof(kernel_buf)); - return offset ? offset : retval; -} - - /** * tty_read - read method for tty device files * @file: pointer to tty file @@ -922,9 +863,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, ld = tty_ldisc_ref_wait(tty); if (!ld) return hung_up_tty_read(file, buf, count, ppos); - i = -EIO; if (ld->ops->read) - i = iterate_tty_read(ld, tty, file, buf, count); + i = ld->ops->read(tty, file, buf, count); + else + i = -EIO; tty_ldisc_deref(ld); if (i > 0) diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 572a07976116..b1e6043e9917 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -185,8 +185,7 @@ struct tty_ldisc_ops { void (*close)(struct tty_struct *); void (*flush_buffer)(struct tty_struct *tty); ssize_t (*read)(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t nr, - void **cookie, unsigned long offset); + unsigned char __user *buf, size_t nr); ssize_t (*write)(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr); int (*ioctl)(struct tty_struct *tty, struct file *file, diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 1204c438e87d..11b554ce07ff 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -292,8 +292,7 @@ static int nci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, /* We don't provide read/write/poll interface for user space. */ static ssize_t nci_uart_tty_read(struct tty_struct *tty, struct file *file, - unsigned char *buf, size_t nr, - void **cookie, unsigned long offset) + unsigned char __user *buf, size_t nr) { return 0; }