Offer COREDUMP_SPARSE in coredump_req->mask now that there is something
behind it. Refuse it without COREDUMP_HEADER. A zero frame cannot exist
outside a framed stream.

A trailing hole is flushed by coredump_write() the way it always was. So
its last byte goes out as a one-byte data frame and the frames cover the
whole coredump.

Signed-off-by: Christian Brauner (Amutable) <[email protected]>
---
 fs/coredump.c                                      | 34 +++++++++++++++++++++-
 .../selftests/coredump/coredump_test_helpers.c     |  3 +-
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/fs/coredump.c b/fs/coredump.c
index 364c89c5f82a..bdf2eae948d0 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -799,7 +799,7 @@ static bool coredump_sock_request(struct core_name *cn, 
struct coredump_params *
                .size           = sizeof(struct coredump_req),
                .mask           = COREDUMP_KERNEL | COREDUMP_USERSPACE |
                                  COREDUMP_REJECT | COREDUMP_WAIT |
-                                 COREDUMP_HEADER,
+                                 COREDUMP_HEADER | COREDUMP_SPARSE,
                .size_ack       = sizeof(struct coredump_ack),
        };
        struct coredump_ack ack = {};
@@ -854,6 +854,12 @@ static bool coredump_sock_request(struct core_name *cn, 
struct coredump_params *
                return false;
        }
 
+       /* Zero frames only exist inside a framed stream. */
+       if ((ack.mask & COREDUMP_SPARSE) && !(ack.mask & COREDUMP_HEADER)) {
+               coredump_sock_mark(cprm->file, COREDUMP_MARK_CONFLICTING);
+               return false;
+       }
+
        if (ack.spare) {
                coredump_sock_mark(cprm->file, COREDUMP_MARK_UNSUPPORTED);
                return false;
@@ -1229,6 +1235,11 @@ static bool dump_framed(const struct coredump_params 
*cprm)
        return cprm->mask & COREDUMP_HEADER;
 }
 
+static bool dump_sparse(const struct coredump_params *cprm)
+{
+       return cprm->mask & COREDUMP_SPARSE;
+}
+
 /* Describe the next @len bytes of the coredump. Returns the header size. */
 static size_t dump_frame_init(struct coredump_params *cprm,
                              enum coredump_frame_type type, u64 len)
@@ -1292,11 +1303,32 @@ static int __dump_emit(struct coredump_params *cprm, 
const void *addr, int nr)
        return dump_write_iter(cprm, &iter, nr);
 }
 
+/* Hand the server the length of the hole instead of the hole itself. */
+static int dump_skip_frame(struct coredump_params *cprm, size_t nr)
+{
+       struct kvec kvec;
+       struct iov_iter iter;
+       size_t hdr;
+
+       if (dump_interrupted())
+               return 0;
+
+       hdr = dump_frame_init(cprm, COREDUMP_FRAME_ZERO, nr);
+       kvec.iov_base = cprm->frame;
+       kvec.iov_len = hdr;
+       iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, hdr);
+
+       return dump_write_iter(cprm, &iter, nr);
+}
+
 static int __dump_skip(struct coredump_params *cprm, size_t nr)
 {
        static char zeroes[PAGE_SIZE];
        struct file *file = cprm->file;
 
+       if (dump_sparse(cprm))
+               return dump_skip_frame(cprm, nr);
+
        if (file->f_mode & FMODE_LSEEK) {
                if (dump_interrupted() || vfs_llseek(file, nr, SEEK_CUR) < 0)
                        return 0;
diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.c 
b/tools/testing/selftests/coredump/coredump_test_helpers.c
index bfe10bc51618..ee669969605b 100644
--- a/tools/testing/selftests/coredump/coredump_test_helpers.c
+++ b/tools/testing/selftests/coredump/coredump_test_helpers.c
@@ -290,7 +290,8 @@ bool send_coredump_ack(int fd, const struct coredump_req 
*req,
 /* Every option the kernel is expected to advertise in coredump_req->mask. */
 #define COREDUMP_REQ_MASK_ALL                                  \
        (COREDUMP_KERNEL | COREDUMP_USERSPACE |                 \
-        COREDUMP_REJECT | COREDUMP_WAIT | COREDUMP_HEADER)
+        COREDUMP_REJECT | COREDUMP_WAIT |                      \
+        COREDUMP_HEADER | COREDUMP_SPARSE)
 
 bool check_coredump_req(const struct coredump_req *req)
 {

-- 
2.53.0


Reply via email to