Put in a check in read subreq termination to detect more data being read
for a subrequest than was requested.

Signed-off-by: David Howells <[email protected]>
cc: Paulo Alcantara <[email protected]>
cc: [email protected]
cc: [email protected]
---
 fs/netfs/read_collect.c      | 18 ++++++++++++++++++
 include/trace/events/netfs.h |  1 +
 2 files changed, 19 insertions(+)

diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c
index 802d1c40cce5..c0170f80d67f 100644
--- a/fs/netfs/read_collect.c
+++ b/fs/netfs/read_collect.c
@@ -227,6 +227,8 @@ static void netfs_collect_read_results(struct 
netfs_io_request *rreq)
                        notes |= HIT_PENDING;
                smp_rmb(); /* Read counters after IN_PROGRESS flag. */
                transferred = READ_ONCE(front->transferred);
+               if (transferred > front->len)
+                       transferred = front->len;
 
                /* If we can now collect the next folio, do so.  We don't want
                 * to defer this as we have to decide whether we need to copy
@@ -543,6 +545,22 @@ void netfs_read_subreq_terminated(struct 
netfs_io_subrequest *subreq)
                break;
        }
 
+       /* If the subrequest read more than it was supposed to, abort
+        * the request with EIO as we may have clobbered other parts
+        * of the buffer that are already read.
+        */
+       if (subreq->transferred > subreq->len) {
+               trace_netfs_sreq(subreq, netfs_sreq_trace_too_much);
+               __set_bit(NETFS_SREQ_FAILED, &subreq->flags);
+               __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags);
+               subreq->transferred = 0;
+               subreq->error = -EIO;
+               trace_netfs_failure(rreq, subreq, subreq->error, 
netfs_fail_read);
+               trace_netfs_rreq(rreq, netfs_rreq_trace_set_pause);
+               set_bit(NETFS_RREQ_PAUSE, &rreq->flags);
+               goto skip_error_checks;
+       }
+
        /* Deal with retry requests, short reads and errors.  If we retry
         * but don't make progress, we abandon the attempt.
         */
diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
index 071d20e80f13..723cb7315308 100644
--- a/include/trace/events/netfs.h
+++ b/include/trace/events/netfs.h
@@ -132,6 +132,7 @@
        EM(netfs_sreq_trace_submit,             "SUBMT")        \
        EM(netfs_sreq_trace_superfluous,        "SPRFL")        \
        EM(netfs_sreq_trace_terminated,         "TERM ")        \
+       EM(netfs_sreq_trace_too_much,           "!TOOM")        \
        EM(netfs_sreq_trace_wait_for,           "_WAIT")        \
        EM(netfs_sreq_trace_write,              "WRITE")        \
        EM(netfs_sreq_trace_write_skip,         "SKIP ")        \


Reply via email to