deleter(new UserBufferDeleter(ictx->cct, aio_completion))));
}
+static int get_iovec_length(const struct iovec *iov, int iovcnt, size_t &len)
+{
+ len = 0;
+
+ if (iovcnt <= 0) {
+ return -EINVAL;
+ }
+
+ for (int i = 0; i < iovcnt; ++i) {
+ const struct iovec &io = iov[i];
+ // check for overflow
+ if (len + io.iov_len < len) {
+ return -EINVAL;
+ }
+ len += io.iov_len;
+ }
+
+ return 0;
+}
+
+static bufferlist iovec_to_bufferlist(librbd::ImageCtx *ictx,
+ const struct iovec *iov,
+ int iovcnt,
+ librbd::io::AioCompletion* aio_completion)
+{
+ bufferlist bl;
+ for (int i = 0; i < iovcnt; ++i) {
+ const struct iovec &io = iov[i];
+ bl.push_back(create_write_raw(ictx, static_cast<char*>(io.iov_base),
+ io.iov_len, aio_completion));
+ }
+ return bl;
+}
+
CephContext* get_cct(IoCtx &io_ctx) {
return reinterpret_cast<CephContext*>(io_ctx.cct());
}
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
- // convert the scatter list into a bufferlist
- auto aio_completion = get_aio_completion(comp);
- ssize_t len = 0;
- bufferlist bl;
- for (int i = 0; i < iovcnt; ++i) {
- const struct iovec &io = iov[i];
- len += io.iov_len;
- if (len < 0) {
- break;
- }
-
- bl.push_back(create_write_raw(ictx, static_cast<char*>(io.iov_base),
- io.iov_len, aio_completion));
- }
-
- int r = 0;
- if (iovcnt <= 0 || len < 0) {
- r = -EINVAL;
- }
+ size_t len;
+ int r = get_iovec_length(iov, iovcnt, len);
tracepoint(librbd, aio_write_enter, ictx, ictx->name.c_str(),
ictx->snap_name.c_str(), ictx->read_only, off, len, NULL,
comp->pc);
+
if (r == 0) {
+ auto aio_completion = get_aio_completion(comp);
+ auto bl = iovec_to_bufferlist(ictx, iov, iovcnt, aio_completion);
ictx->io_work_queue->aio_write(aio_completion, off, len, std::move(bl), 0);
}
tracepoint(librbd, aio_write_exit, r);
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
- ssize_t len = 0;
- for (int i = 0; i < iovcnt; ++i) {
- len += iov[i].iov_len;
- if (len < 0) {
- break;
- }
- }
-
- int r = 0;
- if (iovcnt == 0 || len < 0) {
- r = -EINVAL;
- }
+ size_t len;
+ int r = get_iovec_length(iov, iovcnt, len);
tracepoint(librbd, aio_read_enter, ictx, ictx->name.c_str(),
ictx->snap_name.c_str(), ictx->read_only, off, len, NULL,
#include <set>
#include <thread>
#include <vector>
+#include <limits>
#include "test/librados/test.h"
#include "test/librados/test_cxx.h"
ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
std::string write_buffer("This is a test");
+ // These iovecs should produce a length overflow
struct iovec bad_iovs[] = {
- {.iov_base = NULL, .iov_len = static_cast<size_t>(-1)}
+ {.iov_base = &write_buffer[0], .iov_len = 5},
+ {.iov_base = NULL, .iov_len = std::numeric_limits<size_t>::max()}
};
struct iovec write_iovs[] = {
{.iov_base = &write_buffer[0], .iov_len = 5},
rbd_completion_t comp;
rbd_aio_create_completion(NULL, NULL, &comp);
ASSERT_EQ(-EINVAL, rbd_aio_writev(image, write_iovs, 0, 0, comp));
- ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 1, 0, comp));
+ ASSERT_EQ(-EINVAL, rbd_aio_writev(image, bad_iovs, 2, 0, comp));
ASSERT_EQ(0, rbd_aio_writev(image, write_iovs,
sizeof(write_iovs) / sizeof(struct iovec),
1<<order, comp));
rbd_aio_create_completion(NULL, NULL, &comp);
ASSERT_EQ(-EINVAL, rbd_aio_readv(image, read_iovs, 0, 0, comp));
- ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 1, 0, comp));
+ ASSERT_EQ(-EINVAL, rbd_aio_readv(image, bad_iovs, 2, 0, comp));
ASSERT_EQ(0, rbd_aio_readv(image, read_iovs,
sizeof(read_iovs) / sizeof(struct iovec),
1<<order, comp));