Page MenuHomeFreeBSD

D38717.id117729.diff
No OneTemporary

D38717.id117729.diff

diff --git a/tests/sys/fs/fusefs/Makefile b/tests/sys/fs/fusefs/Makefile
--- a/tests/sys/fs/fusefs/Makefile
+++ b/tests/sys/fs/fusefs/Makefile
@@ -11,6 +11,7 @@
# out, so we get more granular reporting.
GTESTS+= access
GTESTS+= allow_other
+GTESTS+= bad_server
GTESTS+= bmap
GTESTS+= cache
GTESTS+= copy_file_range
diff --git a/tests/sys/fs/fusefs/bad_server.cc b/tests/sys/fs/fusefs/bad_server.cc
new file mode 100644
--- /dev/null
+++ b/tests/sys/fs/fusefs/bad_server.cc
@@ -0,0 +1,105 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2023 Axcient
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+extern "C" {
+#include <fcntl.h>
+#include <unistd.h>
+}
+
+#include "mockfs.hh"
+#include "utils.hh"
+
+using namespace testing;
+
+class BadServer: public FuseTest {};
+
+/*
+ * If the server sends a response for an unknown request, the kernel should
+ * gracefully return EINVAL.
+ */
+TEST_F(BadServer, UnknownUnique)
+{
+ mockfs_buf_out out;
+
+ out.header.len = sizeof(out.header);
+ out.header.error = 0;
+ out.header.unique = 99999; // Invalid!
+ out.expected_errno = EINVAL;
+ m_mock->write_response(out);
+}
+
+/*
+ * If the server sends less than a header's worth of data, the kernel should
+ * gracefully return EINVAL.
+ */
+TEST_F(BadServer, ShortWrite)
+{
+ mockfs_buf_out out;
+
+ out.header.len = sizeof(out.header) - 1;
+ out.header.error = 0;
+ out.header.unique = 0; // Asynchronous notification
+ out.expected_errno = EINVAL;
+ m_mock->write_response(out);
+}
+
+/*
+ * It is illegal to report an error, and also send back a payload.
+ */
+TEST_F(BadServer, ErrorWithPayload)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+
+ EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
+ .WillOnce(Invoke([&](auto in, auto &out) {
+ // First send an invalid response
+ std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
+ out0->header.unique = in.header.unique;
+ out0->header.error = -ENOENT;
+ SET_OUT_HEADER_LEN(*out0, entry); // Invalid!
+ out0->expected_errno = EINVAL;
+ out.push_back(std::move(out0));
+
+ // Then, respond to the lookup so we can complete the test
+ std::unique_ptr<mockfs_buf_out> out1(new mockfs_buf_out);
+ out1->header.unique = in.header.unique;
+ out1->header.error = -ENOENT;
+ out1->header.len = sizeof(out1->header);
+ out.push_back(std::move(out1));
+
+ // The kernel may disconnect us for bad behavior, so don't try
+ // to read any more.
+ m_mock->m_quit = true;
+ }));
+
+ EXPECT_NE(0, access(FULLPATH, F_OK));
+
+ EXPECT_EQ(ENOENT, errno);
+}
diff --git a/tests/sys/fs/fusefs/fallocate.cc b/tests/sys/fs/fusefs/fallocate.cc
--- a/tests/sys/fs/fusefs/fallocate.cc
+++ b/tests/sys/fs/fusefs/fallocate.cc
@@ -70,6 +70,7 @@
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in, auto& out) {
+ assert(in.body.read.size <= sizeof(out.body.bytes));
out.header.len = sizeof(struct fuse_out_header) +
in.body.read.size;
memset(out.body.bytes, 'X', in.body.read.size);
@@ -79,6 +80,7 @@
const char *buf = (const char*)in.body.bytes +
sizeof(struct fuse_write_in);
+ assert(length <= sizeof(in.body.bytes));
return (in.header.opcode == FUSE_WRITE &&
in.header.nodeid == ino &&
in.body.write.offset == off &&
diff --git a/tests/sys/fs/fusefs/io.cc b/tests/sys/fs/fusefs/io.cc
--- a/tests/sys/fs/fusefs/io.cc
+++ b/tests/sys/fs/fusefs/io.cc
@@ -141,6 +141,7 @@
ssize_t isize = in.body.write.size;
off_t iofs = in.body.write.offset;
+ assert((size_t)isize <= sizeof(in.body.bytes));
ASSERT_EQ(isize, pwrite(m_backing_fd, buf, isize, iofs))
<< strerror(errno);
SET_OUT_HEADER_LEN(out, write);
@@ -158,6 +159,7 @@
void *buf = out.body.bytes;
ssize_t osize;
+ assert((size_t)isize <= sizeof(out.body.bytes));
osize = pread(m_backing_fd, buf, isize, iofs);
ASSERT_LE(0, osize) << strerror(errno);
out.header.len = sizeof(struct fuse_out_header) + osize;
diff --git a/tests/sys/fs/fusefs/lookup.cc b/tests/sys/fs/fusefs/lookup.cc
--- a/tests/sys/fs/fusefs/lookup.cc
+++ b/tests/sys/fs/fusefs/lookup.cc
@@ -289,7 +289,7 @@
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
out.header.len = sizeof(out.header);
out.header.error = 2;
- m_mock->m_expected_write_errno = EINVAL;
+ out.expected_errno = EINVAL;
})));
EXPECT_NE(0, access(FULLPATH, F_OK));
diff --git a/tests/sys/fs/fusefs/mockfs.hh b/tests/sys/fs/fusefs/mockfs.hh
--- a/tests/sys/fs/fusefs/mockfs.hh
+++ b/tests/sys/fs/fusefs/mockfs.hh
@@ -206,7 +206,7 @@
* The protocol places no limits on the size of bytes. Choose
* a size big enough for anything we'll test.
*/
- uint8_t bytes[0x20000];
+ uint8_t bytes[0x40000];
fuse_entry_out entry;
fuse_entry_out_7_8 entry_7_8;
fuse_lk_out getlk;
@@ -233,6 +233,8 @@
struct mockfs_buf_out {
fuse_out_header header;
union fuse_payloads_out body;
+ /* the expected errno of the write to /dev/fuse */
+ int expected_errno;
/* Default constructor: zero everything */
mockfs_buf_out() {
@@ -333,16 +335,13 @@
*/
void read_request(mockfs_buf_in& in, ssize_t& res);
+ public:
/* Write a single response back to the kernel */
void write_response(const mockfs_buf_out &out);
- public:
/* pid of child process, for two-process test cases */
pid_t m_child_pid;
- /* the expected errno of the next write to /dev/fuse */
- int m_expected_write_errno;
-
/* Maximum size of a FUSE_WRITE write */
uint32_t m_maxwrite;
diff --git a/tests/sys/fs/fusefs/mockfs.cc b/tests/sys/fs/fusefs/mockfs.cc
--- a/tests/sys/fs/fusefs/mockfs.cc
+++ b/tests/sys/fs/fusefs/mockfs.cc
@@ -431,7 +431,6 @@
const bool trueval = true;
m_daemon_id = NULL;
- m_expected_write_errno = 0;
m_kernel_minor_version = kernel_minor_version;
m_maxreadahead = max_readahead;
m_maxwrite = MIN(max_write, max_max_write);
@@ -801,7 +800,6 @@
bzero(in.get(), sizeof(*in));
read_request(*in, buflen);
- m_expected_write_errno = 0;
if (m_quit)
break;
if (verbosity > 0)
@@ -1034,9 +1032,9 @@
FAIL() << "not yet implemented";
}
r = write(m_fuse_fd, &out, out.header.len);
- if (m_expected_write_errno) {
+ if (out.expected_errno) {
ASSERT_EQ(-1, r);
- ASSERT_EQ(m_expected_write_errno, errno) << strerror(errno);
+ ASSERT_EQ(out.expected_errno, errno) << strerror(errno);
} else {
ASSERT_TRUE(r > 0 || errno == EAGAIN) << strerror(errno);
}
diff --git a/tests/sys/fs/fusefs/setattr.cc b/tests/sys/fs/fusefs/setattr.cc
--- a/tests/sys/fs/fusefs/setattr.cc
+++ b/tests/sys/fs/fusefs/setattr.cc
@@ -530,6 +530,7 @@
auto osize = std::min(
static_cast<uint64_t>(cur_size) - in.body.read.offset,
static_cast<uint64_t>(in.body.read.size));
+ assert(osize <= sizeof(out.body.bytes));
out.header.len = sizeof(struct fuse_out_header) + osize;
if (should_have_data)
memset(out.body.bytes, 'X', osize);
diff --git a/tests/sys/fs/fusefs/utils.cc b/tests/sys/fs/fusefs/utils.cc
--- a/tests/sys/fs/fusefs/utils.cc
+++ b/tests/sys/fs/fusefs/utils.cc
@@ -400,6 +400,7 @@
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
+ assert(osize <= sizeof(out.body.bytes));
out.header.len = sizeof(struct fuse_out_header) + osize;
memmove(out.body.bytes, contents, osize);
}))).RetiresOnSaturation();
@@ -497,6 +498,7 @@
{
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
+ assert(isize <= sizeof(in.body.bytes));
const char *buf = (const char*)in.body.bytes +
sizeof(struct fuse_write_in);
bool pid_ok;
@@ -531,6 +533,7 @@
{
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
+ assert(isize <= sizeof(in.body.bytes));
const char *buf = (const char*)in.body.bytes +
FUSE_COMPAT_WRITE_IN_SIZE;
bool pid_ok = (pid_t)in.header.pid == getpid();
diff --git a/tests/sys/fs/fusefs/write.cc b/tests/sys/fs/fusefs/write.cc
--- a/tests/sys/fs/fusefs/write.cc
+++ b/tests/sys/fs/fusefs/write.cc
@@ -94,6 +94,7 @@
{
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
+ assert(size <= sizeof(in.body.bytes));
const char *buf = (const char*)in.body.bytes +
sizeof(struct fuse_write_in);

File Metadata

Mime Type
text/plain
Expires
Tue, May 26, 7:07 PM (18 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33535826
Default Alt Text
D38717.id117729.diff (9 KB)

Event Timeline