mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 06:18:07 +03:00
add unit test for access
Summary: This code has enough risk of a copy paste error that it deserves a unit test. Reviewed By: chadaustin Differential Revision: D35161787 fbshipit-source-id: 5691d13a74a0f059dfd6a93ea2852dca8399a165
This commit is contained in:
parent
fb599a7751
commit
ad04eb9bc1
@ -43,6 +43,20 @@ target_link_libraries(
|
||||
eden_nfs_rpc
|
||||
)
|
||||
|
||||
add_library(
|
||||
eden_nfs_utils STATIC
|
||||
"NfsUtils.cpp" "NfsUtils.h"
|
||||
)
|
||||
|
||||
|
||||
target_link_libraries(
|
||||
eden_nfs_utils
|
||||
PRIVATE
|
||||
eden_nfs_nfsd_rpc
|
||||
Folly::folly
|
||||
)
|
||||
|
||||
|
||||
add_library(
|
||||
eden_nfs_nfsd3 STATIC
|
||||
"Nfsd3.cpp" "Nfsd3.h" "NfsRequestContext.cpp" "NfsRequestContext.h"
|
||||
@ -55,6 +69,7 @@ target_link_libraries(
|
||||
eden_nfs_rpc_server
|
||||
PRIVATE
|
||||
eden_nfs_nfsd_rpc
|
||||
eden_nfs_utils
|
||||
Folly::folly
|
||||
)
|
||||
|
||||
|
54
eden/fs/nfs/NfsUtils.cpp
Normal file
54
eden/fs/nfs/NfsUtils.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This software may be used and distributed according to the terms of the
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include "eden/fs/nfs/NfsUtils.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace facebook::eden {
|
||||
uint32_t getEffectiveAccessRights(
|
||||
const struct stat& stat,
|
||||
uint32_t desiredAccess) {
|
||||
bool accessRead = (stat.st_mode & S_IRUSR) | (stat.st_mode & S_IRGRP) |
|
||||
(stat.st_mode & S_IROTH);
|
||||
bool accessWrite = (stat.st_mode & S_IWUSR) | (stat.st_mode & S_IWGRP) |
|
||||
(stat.st_mode & S_IWOTH);
|
||||
bool accessExecute = (stat.st_mode & S_IXUSR) | (stat.st_mode & S_IXGRP) |
|
||||
(stat.st_mode & S_IXOTH);
|
||||
|
||||
// The delete bit indicates whether entries can be deleted from a directory
|
||||
// or not. NOT whether this file can be deleted. So this bit is kinda useless
|
||||
// for files. The NFS spec suggests that NFS servers should return 0 for
|
||||
// files, so we only set this bit for directories.
|
||||
bool accessDelete = (stat.st_mode & S_IFDIR) && accessWrite;
|
||||
|
||||
uint32_t expandedAccessBits = 0;
|
||||
if (accessRead) {
|
||||
expandedAccessBits |= ACCESS3_READ;
|
||||
expandedAccessBits |= ACCESS3_LOOKUP;
|
||||
}
|
||||
|
||||
if (accessWrite) {
|
||||
expandedAccessBits |= ACCESS3_MODIFY;
|
||||
expandedAccessBits |= ACCESS3_EXTEND;
|
||||
}
|
||||
|
||||
if (accessDelete) {
|
||||
expandedAccessBits |= ACCESS3_DELETE;
|
||||
}
|
||||
|
||||
if (accessExecute) {
|
||||
expandedAccessBits |= ACCESS3_EXECUTE;
|
||||
}
|
||||
|
||||
return desiredAccess & expandedAccessBits;
|
||||
}
|
||||
|
||||
} // namespace facebook::eden
|
||||
#endif
|
@ -162,5 +162,31 @@ inline post_op_attr statToPostOpAttr(const folly::Try<struct stat>& stat) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which of the `desiredAccess`'s a client should be granted for a
|
||||
* certain file or directory based on the the `stat` of that file or directory.
|
||||
* This result is an advisory result for the access call. Clients use this call
|
||||
* to block IO that user's do not have access for, but procedures are still
|
||||
* welcome to refuse to perform an action due to access restrictions. Thus
|
||||
* this result should err on the side of being more permissive than restrictive.
|
||||
*
|
||||
* Really this should look at the uid & gid of the client issuing the request.
|
||||
* These credentials are sent as part of the RPC credentials. This gets
|
||||
* complicated because many of the authentication protocols in NFS v3 allow
|
||||
* clients to spoof their uid/gid very easily. We would need to use a
|
||||
* complicated authentication protocol like RPCSEC_GSS to be able to perform
|
||||
* proper access checks
|
||||
*
|
||||
* To simplify for now, we give user's the most permissive access they could
|
||||
* have as any user except root (we highly discourage acting as root inside an
|
||||
* EdenFS repo). This provides a little bit of access restriction, so that
|
||||
* access calls behave some what normally. However, long term we likely need to
|
||||
* implement full authentication and respond properly here. We also should
|
||||
* enforce permissions on each procedure call.
|
||||
*/
|
||||
uint32_t getEffectiveAccessRights(
|
||||
const struct stat& stat,
|
||||
uint32_t desiredAccess);
|
||||
|
||||
} // namespace facebook::eden
|
||||
#endif
|
||||
|
@ -465,66 +465,6 @@ ImmediateFuture<folly::Unit> Nfsd3ServerProcessor::lookup(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which of the `desiredAccess`'s a client should be granted for a
|
||||
* certain file or directory based on the the `stat` of that file or directory.
|
||||
* This result is an advisory result for the access call. Clients use this call
|
||||
* to block IO that user's do not have access for, but procedures are still
|
||||
* welcome to refuse to perform an action due to access restrictions. Thus
|
||||
* this result should err on the side of being more permissive than restrictive.
|
||||
*
|
||||
* Really this should look at the uid & gid of the client issuing the request.
|
||||
* These credentials are sent as part of the RPC credentials. This gets
|
||||
* complicated because many of the authentication protocols in NFS v3 allow
|
||||
* clients to spoof their uid/gid very easily. We would need to use a
|
||||
* complicated authentication protocol like RPCSEC_GSS to be able to perform
|
||||
* proper access checks
|
||||
*
|
||||
* To simplify for now, we give user's the most permissive access they could
|
||||
* have as any user except root (we highly discourage acting as root inside an
|
||||
* EdenFS repo). This provides a little bit of access restriction, so that
|
||||
* access calls behave some what normally. However, long term we likely need to
|
||||
* implement full authentication and respond properly here. We also should
|
||||
* enforce permissions on each procedure call.
|
||||
*/
|
||||
uint32_t getEffectiveAccessRights(
|
||||
const struct stat& stat,
|
||||
uint32_t desiredAccess) {
|
||||
bool accessRead = (stat.st_mode & S_IRUSR) | (stat.st_mode & S_IRGRP) |
|
||||
(stat.st_mode & S_IROTH);
|
||||
bool accessWrite = (stat.st_mode & S_IWUSR) | (stat.st_mode & S_IWGRP) |
|
||||
(stat.st_mode & S_IWOTH);
|
||||
bool accessExecute = (stat.st_mode & S_IXUSR) | (stat.st_mode & S_IXGRP) |
|
||||
(stat.st_mode & S_IXOTH);
|
||||
|
||||
// The delete bit indicates whether entries can be deleted from a directory
|
||||
// or not. NOT whether this file can be deleted. So this bit is kinda useless
|
||||
// for files. The NFS spec suggests that NFS servers should return 0 for
|
||||
// files, so we only set this bit for directories.
|
||||
bool accessDelete = (stat.st_mode & S_IFDIR) && accessWrite;
|
||||
|
||||
uint32_t expandedAccessBits = 0;
|
||||
if (accessRead) {
|
||||
expandedAccessBits |= ACCESS3_READ;
|
||||
expandedAccessBits |= ACCESS3_LOOKUP;
|
||||
}
|
||||
|
||||
if (accessWrite) {
|
||||
expandedAccessBits |= ACCESS3_MODIFY;
|
||||
expandedAccessBits |= ACCESS3_EXTEND;
|
||||
}
|
||||
|
||||
if (accessDelete) {
|
||||
expandedAccessBits |= ACCESS3_DELETE;
|
||||
}
|
||||
|
||||
if (accessExecute) {
|
||||
expandedAccessBits |= ACCESS3_EXECUTE;
|
||||
}
|
||||
|
||||
return desiredAccess & expandedAccessBits;
|
||||
}
|
||||
|
||||
ImmediateFuture<folly::Unit> Nfsd3ServerProcessor::access(
|
||||
folly::io::Cursor deser,
|
||||
folly::io::QueueAppender ser,
|
||||
|
100
eden/fs/nfs/test/AccessTest.cpp
Normal file
100
eden/fs/nfs/test/AccessTest.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This software may be used and distributed according to the terms of the
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <folly/portability/GTest.h>
|
||||
|
||||
#include "eden/fs/nfs/NfsUtils.h"
|
||||
#include "eden/fs/nfs/NfsdRpc.h"
|
||||
|
||||
namespace facebook::eden {
|
||||
|
||||
TEST(AccessTest, read) {
|
||||
struct stat st {};
|
||||
st.st_mode = S_IRUSR;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_READ), ACCESS3_READ);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_LOOKUP), ACCESS3_LOOKUP);
|
||||
|
||||
st.st_mode = S_IRGRP;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_READ), ACCESS3_READ);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_LOOKUP), ACCESS3_LOOKUP);
|
||||
|
||||
st.st_mode = S_IROTH;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_READ), ACCESS3_READ);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_LOOKUP), ACCESS3_LOOKUP);
|
||||
|
||||
st.st_mode = S_IRGRP | S_IROTH;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_READ), ACCESS3_READ);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_LOOKUP), ACCESS3_LOOKUP);
|
||||
|
||||
st.st_mode = S_IWGRP | S_IXOTH;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_READ), 0);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_LOOKUP), 0);
|
||||
}
|
||||
|
||||
TEST(AccessTest, write) {
|
||||
struct stat st {};
|
||||
st.st_mode = S_IWUSR;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_MODIFY), ACCESS3_MODIFY);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXTEND), ACCESS3_EXTEND);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_DELETE), 0);
|
||||
|
||||
st.st_mode = S_IWGRP;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_MODIFY), ACCESS3_MODIFY);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXTEND), ACCESS3_EXTEND);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_DELETE), 0);
|
||||
|
||||
st.st_mode = S_IWOTH;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_MODIFY), ACCESS3_MODIFY);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXTEND), ACCESS3_EXTEND);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_DELETE), 0);
|
||||
|
||||
st.st_mode = S_IWGRP | S_IWOTH;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_MODIFY), ACCESS3_MODIFY);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXTEND), ACCESS3_EXTEND);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_DELETE), 0);
|
||||
|
||||
st.st_mode = S_IRUSR | S_IRGRP;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_MODIFY), 0);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXTEND), 0);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_DELETE), 0);
|
||||
|
||||
st.st_mode = S_IWGRP | S_IWOTH | S_IFDIR;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_MODIFY), ACCESS3_MODIFY);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXTEND), ACCESS3_EXTEND);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_DELETE), ACCESS3_DELETE);
|
||||
|
||||
st.st_mode = S_IRUSR | S_IRGRP | S_IFDIR;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_MODIFY), 0);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXTEND), 0);
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_DELETE), 0);
|
||||
}
|
||||
|
||||
TEST(AccessTest, execute) {
|
||||
struct stat st {};
|
||||
st.st_mode = S_IXUSR;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXECUTE), ACCESS3_EXECUTE);
|
||||
|
||||
st.st_mode = S_IXGRP;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXECUTE), ACCESS3_EXECUTE);
|
||||
|
||||
st.st_mode = S_IXOTH;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXECUTE), ACCESS3_EXECUTE);
|
||||
|
||||
st.st_mode = S_IXGRP | S_IXOTH;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXECUTE), ACCESS3_EXECUTE);
|
||||
|
||||
st.st_mode = S_IRUSR | S_IWUSR;
|
||||
EXPECT_EQ(getEffectiveAccessRights(st, ACCESS3_EXECUTE), 0);
|
||||
}
|
||||
|
||||
} // namespace facebook::eden
|
||||
|
||||
#endif
|
@ -14,6 +14,7 @@ target_link_libraries(
|
||||
eden_nfs_test
|
||||
PUBLIC
|
||||
eden_nfs_nfsd_rpc
|
||||
eden_nfs_utils
|
||||
eden_nfs_testharness_xdr_test_utils
|
||||
Folly::folly_test_util
|
||||
${LIBGMOCK_LIBRARIES}
|
||||
|
Loading…
Reference in New Issue
Block a user