fuse permission fixes

This commit is contained in:
Scott E. Graves 2024-10-21 11:52:21 -05:00
parent bd25904371
commit 841d57cf13
4 changed files with 149 additions and 35 deletions

View File

@ -170,6 +170,9 @@ renterd
richtext
rocksdb_library
rpcrt4
s_igid
s_isvtx
s_iuid
sddl_revision_1
secp256k1
secur32
@ -218,4 +221,4 @@ wsign-conversion
wunused
wuseless
wxwidgets_version
xattr
xattr

View File

@ -67,6 +67,11 @@ auto fuse_drive::chmod_impl(std::string api_path, mode_t mode,
auto fuse_drive::chmod_impl(std::string api_path, mode_t mode) -> api_error {
#endif // FUSE_USE_VERSION >= 30
return check_and_perform(api_path, X_OK, [&](api_meta_map &) -> api_error {
if ((mode & (S_IGID | S_IUID | S_ISVTX) != 0) &&
(get_effective_uid() != 0)) {
return api_error::permission_denied;
}
return provider_.set_item_meta(api_path, META_MODE, std::to_string(mode));
});
}
@ -86,23 +91,24 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
if (get_effective_uid() != 0) {
return api_error::permission_denied;
}
meta[META_UID] = std::to_string(uid);
}
if (gid != static_cast<gid_t>(-1)) {
if (get_effective_uid() != 0) {
if (not utils::is_uid_member_of_group(get_effective_uid(), gid)) {
return api_error::permission_denied;
}
if (get_effective_uid() != 0 &&
not utils::is_uid_member_of_group(get_effective_uid(), gid)) {
return api_error::permission_denied;
}
meta[META_GID] = std::to_string(gid);
}
if (not meta.empty()) {
return provider_.set_item_meta(api_path, meta);
if (meta.empty()) {
return api_error::success;
}
return api_error::success;
return provider_.set_item_meta(api_path, meta);
});
}

View File

@ -32,16 +32,22 @@
#include "providers/encrypt/encrypt_provider.hpp"
#include "providers/s3/s3_provider.hpp"
#include "providers/sia/sia_provider.hpp"
#include "types/repertory.hpp"
#include "utils/event_capture.hpp"
#include "utils/file_utils.hpp"
#include "utils/path.hpp"
#include "utils/utils.hpp"
#if !defined(ACCESSPERMS)
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */
#endif
namespace repertory {
inline constexpr const auto SLEEP_SECONDS{1.5s};
namespace {
std::atomic<std::size_t> idx{0U};
constexpr const auto SLEEP_SECONDS{1.5s};
} // namespace
namespace repertory {
template <typename provider_t> class fuse_test : public ::testing::Test {
public:
static std::string cfg_directory;
@ -147,7 +153,10 @@ protected:
public:
static auto create_file_and_test(std::string name) -> std::string {
auto file_path = utils::path::combine(mount_location, {name});
auto file_path =
utils::path::combine(mount_location, {
name + std::to_string(++idx),
});
auto fd =
open(file_path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
@ -166,6 +175,19 @@ public:
return file_path;
}
static auto create_root_file(std::string name) -> std::string {
auto file_path = create_file_and_test(name);
auto api_path =
utils::path::create_api_path(utils::path::strip_to_filename(file_path));
provider->set_item_meta(api_path, {
{META_UID, "0"},
{META_GID, "0"},
});
return file_path;
}
static void execute_mount(auto &&drive_args) {
auto mount_cmd = "./repertory -dd \"" + config->get_data_directory() +
"\"" + " " + utils::string::join(drive_args, ' ');
@ -200,6 +222,18 @@ public:
EXPECT_FALSE(utils::file::directory(file_path).exists());
EXPECT_FALSE(utils::file::file(file_path).exists());
}
static void unlink_root_file(const std::string &file_path) {
auto api_path =
utils::path::create_api_path(utils::path::strip_to_filename(file_path));
provider->set_item_meta(api_path, {
{META_UID, std::to_string(getuid())},
{META_GID, std::to_string(getgid())},
});
unlink_file_and_test(file_path);
}
};
template <typename provider_t>

View File

@ -19,22 +19,10 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#if 0
#if !defined(_WIN32)
#include "fixtures/fuse_fixture.hpp"
// #include "app_config.hpp"
// #include "comm/curl/curl_comm.hpp"
// #include "drives/fuse/fuse_drive.hpp"
// #include "platform/platform.hpp"
// #include "providers/s3/s3_provider.hpp"
// #include "providers/sia/sia_provider.hpp"
// #include "types/repertory.hpp"
// #include "utils/event_capture.hpp"
// #include "utils/file_utils.hpp"
// #include "utils/utils.hpp"
namespace repertory {
// static void rmdir_and_test(const std::string &directory_path) {
// std::cout << __FUNCTION__ << std::endl;
@ -529,36 +517,119 @@ namespace repertory {
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
TYPED_TEST(fuse_test, chmod) {
TYPED_TEST(fuse_test, can_chmod_if_owner) {
auto file_path = this->create_file_and_test("chmod_test");
EXPECT_EQ(0, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
std::this_thread::sleep_for(SLEEP_SECONDS);
struct stat64 unix_st {};
struct stat64 unix_st{};
stat64(file_path.c_str(), &unix_st);
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR),
ACCESSPERMS & unix_st.st_mode);
this->unlink_file_and_test(file_path);
}
TYPED_TEST(fuse_test, chown) {
TYPED_TEST(fuse_test, can_not_chmod_if_not_owner) {
auto file_path = this->create_root_file("chmod_test");
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
EXPECT_EQ(EPERM, errno);
this->unlink_root_file(file_path);
}
TYPED_TEST(fuse_test, can_not_chmod_setgid_if_not_root) {
auto file_path = this->create_file_and_test("chown_test");
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_IGID));
EXPECT_EQ(EPERM, errno);
this->unlink_file_and_test(file_path);
}
TYPED_TEST(fuse_test, can_not_chmod_setuid_if_not_root) {
auto file_path = this->create_file_and_test("chown_test");
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_IUID));
EXPECT_EQ(EPERM, errno);
this->unlink_file_and_test(file_path);
}
TYPED_TEST(fuse_test, can_not_chmod_set_sticky_if_not_root) {
auto file_path = this->create_file_and_test("chown_test");
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISVTX));
EXPECT_EQ(EPERM, errno);
this->unlink_file_and_test(file_path);
}
TYPED_TEST(fuse_test, can_chown_group_if_owner_and_a_member_of_the_group) {
auto file_path = this->create_file_and_test("chown_test");
struct stat64 unix_st{};
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
std::this_thread::sleep_for(SLEEP_SECONDS);
struct stat64 unix_st {};
stat64(file_path.c_str(), &unix_st);
EXPECT_EQ(0U, unix_st.st_gid);
struct stat64 unix_st2{};
stat64(file_path.c_str(), &unix_st2);
EXPECT_EQ(getgid(), unix_st2.st_gid);
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
EXPECT_EQ(0, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
std::this_thread::sleep_for(SLEEP_SECONDS);
this->unlink_file_and_test(file_path);
}
stat64(file_path.c_str(), &unix_st);
EXPECT_EQ(0U, unix_st.st_gid);
TYPED_TEST(fuse_test,
can_not_chown_group_if_owner_but_not_a_member_of_the_group) {
auto file_path = this->create_file_and_test("chown_test");
struct stat64 unix_st{};
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
EXPECT_EQ(EPERM, errno);
struct stat64 unix_st2{};
stat64(file_path.c_str(), &unix_st2);
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
this->unlink_file_and_test(file_path);
}
TYPED_TEST(fuse_test, can_not_chown_group_if_not_the_owner) {
auto file_path = this->create_root_file("chown_test");
struct stat64 unix_st{};
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
EXPECT_EQ(EPERM, errno);
struct stat64 unix_st2{};
stat64(file_path.c_str(), &unix_st2);
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
this->unlink_root_file(file_path);
}
TYPED_TEST(fuse_test, can_not_chown_user_if_not_root) {
auto file_path = this->create_file_and_test("chown_test");
struct stat64 unix_st{};
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
EXPECT_EQ(-1, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
EXPECT_EQ(EPERM, errno);
struct stat64 unix_st2{};
stat64(file_path.c_str(), &unix_st2);
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
this->unlink_file_and_test(file_path);
}
} // namespace repertory
#endif // !defined(_WIN32)
#endif // 0