From b18bc714fd52149220fc9b6c04690c4f91f2bd75 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 3 Oct 2019 21:35:14 -0500 Subject: [PATCH] retry: Check size before transactions Although it is unusual for a plugin to shrink size on reopen, it is not impossible. Failure to check our bounds could result in violating assumptions in the plugin that all requests are in-bounds. Note that if the plugin gains a larger size, we merely never access the new tail of the file (when the NBD protocol ever gains dynamic resize support, we'll get to revisit how the retry filter fits in). If it reports a smaller size, and the request tries to access that portion of the file, then retry just the same as if can_write or similar disappears, on the hopes that yet another retry will fix the problem. Fixes: f0f0ec49 Signed-off-by: Eric Blake --- filters/retry/retry.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/filters/retry/retry.c b/filters/retry/retry.c index 840d7383..0f249936 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -149,6 +149,17 @@ struct retry_data { }; static bool +valid_range (struct nbdkit_next_ops *next_ops, void *nxdata, + uint32_t count, uint64_t offset, bool is_write, int *err) +{ + if ((int64_t) offset + count > next_ops->get_size (nxdata)) { + *err = is_write ? ENOSPC : EIO; + return false; + } + return true; +} + +static bool do_retry (struct retry_handle *h, struct retry_data *data, struct nbdkit_next_ops *next_ops, void *nxdata, @@ -204,7 +215,10 @@ retry_pread (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - r = next_ops->pread (nxdata, buf, count, offset, flags, err); + if (! valid_range (next_ops, nxdata, count, offset, false, err)) + r = -1; + else + r = next_ops->pread (nxdata, buf, count, offset, flags, err); if (r == -1 && do_retry (h, &data, next_ops, nxdata, err)) goto again; return r; @@ -226,7 +240,9 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, *err = EROFS; return -1; } - if (next_ops->can_write (nxdata) != 1) { + if (! valid_range (next_ops, nxdata, count, offset, true, err)) + r = -1; + else if (next_ops->can_write (nxdata) != 1) { *err = EROFS; r = -1; } @@ -258,7 +274,9 @@ retry_trim (struct nbdkit_next_ops *next_ops, void *nxdata, *err = EROFS; return -1; } - if (next_ops->can_trim (nxdata) != 1) { + if (! valid_range (next_ops, nxdata, count, offset, true, err)) + r = -1; + else if (next_ops->can_trim (nxdata) != 1) { *err = EROFS; r = -1; } @@ -313,11 +331,13 @@ retry_zero (struct nbdkit_next_ops *next_ops, void *nxdata, return -1; } if (flags & NBDKIT_FLAG_FAST_ZERO && - next_ops->can_fast_zero (nxdata) != 1) { + next_ops->can_fast_zero (nxdata) != 1) { *err = EOPNOTSUPP; return -1; } - if (next_ops->can_zero (nxdata) <= NBDKIT_ZERO_NONE) { + if (! valid_range (next_ops, nxdata, count, offset, true, err)) + r = -1; + else if (next_ops->can_zero (nxdata) <= NBDKIT_ZERO_NONE) { *err = EROFS; r = -1; } @@ -347,7 +367,9 @@ retry_extents (struct nbdkit_next_ops *next_ops, void *nxdata, size_t i; again: - if (next_ops->can_extents (nxdata) != 1) { + if (! valid_range (next_ops, nxdata, count, offset, false, err)) + r = -1; + else if (next_ops->can_extents (nxdata) != 1) { *err = EIO; r = -1; } @@ -390,7 +412,9 @@ retry_cache (struct nbdkit_next_ops *next_ops, void *nxdata, int r; again: - if (next_ops->can_cache (nxdata) <= NBDKIT_CACHE_NONE) { + if (! valid_range (next_ops, nxdata, count, offset, false, err)) + r = -1; + else if (next_ops->can_cache (nxdata) <= NBDKIT_CACHE_NONE) { *err = EIO; r = -1; } -- 2.11.4.GIT