nfs4: Make uid and gid consistent for async IO

* Allow the client of the Request constructor to specify the uid and
  gid to apply to a Request, regardless of the euid and egid that are
  in effect for the thread.
* For write and delegation recall requests, apply the IDs that were
  captured earlier by the OpenState or Delegation constructor,
  respectively.
* This prevents the server from denying requests sent by the WorkQueue
  thread based on the uid and gid in the RPC header.
* Fixes #19657.

The Linux server I use for testing never seems to grant the client a
delegation, so I wasn't able to test whether the server actually cares
about the uid and gid when a delegation is recalled.

Change-Id: I6e3b31cc7767d80fa06c33c9b3eee6078d98fe53
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9501
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Jim906
2025-07-24 15:09:08 +00:00
committed by waddlesplash
parent 49c0104805
commit 59b0415f24
18 changed files with 71 additions and 59 deletions
@@ -19,7 +19,9 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
fClientID(clientID),
fData(data),
fInode(inode),
fAttribute(attribute)
fAttribute(attribute),
fUid(geteuid()),
fGid(getegid())
{
ASSERT(inode != NULL);
}
@@ -43,7 +45,7 @@ Delegation::ReturnDelegation()
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, fUid, fGid);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -37,6 +37,8 @@ private:
OpenDelegationData fData;
Inode* fInode;
bool fAttribute;
uid_t fUid;
gid_t fGid;
};
@@ -173,7 +173,7 @@ FileInfo::UpdateFileHandles(FileSystem* fs)
{
ASSERT(fs != NULL);
Request request(fs->Server(), fs);
Request request(fs->Server(), fs, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutRootFH();
@@ -146,7 +146,7 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* serverName, c
return B_NO_MEMORY;
ObjectDeleter<FileSystem> fsDeleter(fs);
Request request(serv, fs);
Request request(serv, fs, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutRootFH();
@@ -65,7 +65,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo& fi, Inode** _inode)
uint64 size;
do {
RPC::Server* serv = fs->Server();
Request request(serv, fs);
Request request(serv, fs, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(inode->fInfo.fHandle);
@@ -147,7 +147,7 @@ Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -23,7 +23,7 @@ NFS4Inode::GetChangeInfo(uint64* change, bool attrDir)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
if (attrDir)
@@ -66,7 +66,7 @@ NFS4Inode::CommitWrites()
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -95,7 +95,7 @@ NFS4Inode::Access(uint32* allowed)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -126,7 +126,7 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
(void)parent; // TODO: add support for named attributes
@@ -216,7 +216,7 @@ NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -252,7 +252,7 @@ NFS4Inode::ReadLink(void* buffer, size_t* length)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -287,7 +287,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
if (cookie != NULL)
@@ -325,7 +325,7 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
if (state != NULL) {
@@ -371,7 +371,7 @@ NFS4Inode::RenameNode(Inode* from, Inode* to, const char* fromName,
uint32 attempt = 0;
do {
RPC::Server* server = from->fFileSystem->Server();
Request request(server, from->fFileSystem);
Request request(server, from->fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
if (attribute)
@@ -460,7 +460,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state,
state->fClientID = fFileSystem->NFSServer()->ClientId();
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -558,7 +558,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
state->fClientID = fFileSystem->NFSServer()->ClientId();
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
// Since we are opening the file using a pair (parentFH, name) we
@@ -667,7 +667,7 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
state->fClientID = fFileSystem->NFSServer()->ClientId();
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fAttrDir);
@@ -728,7 +728,7 @@ NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(state->fInfo.fHandle);
@@ -764,7 +764,7 @@ NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, state->fUid, state->fGid);
RequestBuilder& req = request.Builder();
req.PutFH(state->fInfo.fHandle);
@@ -804,7 +804,7 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
(void)parent; // TODO: support named attributes
@@ -884,7 +884,7 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -965,7 +965,7 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
if (attribute)
@@ -1037,7 +1037,7 @@ NFS4Inode::OpenAttrDir(FileHandle* handle)
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -1075,7 +1075,7 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -1118,7 +1118,7 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait)
MutexLocker ownerLocker(lockInfo->fOwner->fLock);
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -1167,7 +1167,7 @@ NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo)
MutexLocker ownerLocker(lockInfo->fOwner->fLock);
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -200,7 +200,7 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state,
uint32 attempt = 0;
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
@@ -111,7 +111,7 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew)
if ((fUseCount == 0 && fClientIdLastUse + (time_t)LeaseTime() < time(NULL))
|| (forceNew && fClientId == prevId)) {
Request request(fServer, NULL);
Request request(fServer, NULL, geteuid(), getegid());
request.Builder().SetClientID(fServer);
status_t result = request.Send();
@@ -123,7 +123,7 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew)
if (result != B_OK)
return fClientId;
request.Reset();
request.Reset(geteuid(), getegid());
request.Builder().SetClientIDConfirm(fClientId, ver);
result = request.Send();
@@ -158,7 +158,7 @@ NFS4Server::FileSystemMigrated()
status_t
NFS4Server::_GetLeaseTime()
{
Request request(fServer, NULL);
Request request(fServer, NULL, geteuid(), getegid());
request.Builder().PutRootFH();
Attribute attr[] = { FATTR4_LEASE_TIME };
request.Builder().GetAttr(attr, sizeof(attr) / sizeof(Attribute));
@@ -244,7 +244,7 @@ NFS4Server::_Renewal()
}
}
Request request(fServer, NULL);
Request request(fServer, NULL, geteuid(), getegid());
request.Builder().Renew(clientId);
result = request.Send();
if (result != B_OK)
@@ -21,7 +21,9 @@ OpenState::OpenState()
fOpened(false),
fDelegation(NULL),
fLocks(NULL),
fLockOwners(NULL)
fLockOwners(NULL),
fUid(geteuid()),
fGid(getegid())
{
mutex_init(&fLock, NULL);
@@ -117,7 +119,7 @@ OpenState::_ReleaseLockOwner(LockOwner* owner)
uint32 attempt = 0;
do {
RPC::Server* server = fFileSystem->Server();
Request request(server, fFileSystem);
Request request(server, fFileSystem, fUid, fGid);
RequestBuilder& req = request.Builder();
req.ReleaseLockOwner(this, owner);
@@ -170,7 +172,7 @@ OpenState::_ReclaimOpen(uint64 newClientID)
uint32 attempt = 0;
do {
RPC::Server* server = fFileSystem->Server();
Request request(server, fFileSystem);
Request request(server, fFileSystem, fUid, fGid);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -240,7 +242,7 @@ OpenState::_ReclaimLocks(uint64 newClientID)
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
RPC::Server* server = fFileSystem->Server();
Request request(server, fFileSystem);
Request request(server, fFileSystem, fUid, fGid);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -292,7 +294,7 @@ OpenState::Close()
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv, fFileSystem);
Request request(serv, fFileSystem, fUid, fGid);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -39,6 +39,9 @@ struct OpenState : public NFS4Object, public KernelReferenceable,
LockOwner* fLockOwners;
mutex fOwnerLock;
uid_t fUid;
gid_t fGid;
LockOwner* GetLockOwner(uint32 owner);
void AddLock(LockInfo* lock);
@@ -47,7 +47,7 @@ Auth::CreateNone()
const Auth*
Auth::CreateSys()
Auth::CreateSys(uid_t uid, gid_t gid)
{
Auth* auth = new(std::nothrow) Auth;
if (auth == NULL)
@@ -62,8 +62,8 @@ Auth::CreateSys()
strcpy(hostname, "unknown");
xdr.AddString(hostname, 255);
xdr.AddUInt(getuid());
xdr.AddUInt(getgid());
xdr.AddUInt(uid);
xdr.AddUInt(gid);
int count = getgroups(0, NULL);
if (count < B_OK)
@@ -19,7 +19,7 @@ public:
inline const XDR::WriteStream& Stream() const;
static const Auth* CreateNone();
static const Auth* CreateSys();
static const Auth* CreateSys(uid_t uid, gid_t gid);
private:
Auth();
@@ -151,9 +151,9 @@ Request::_SendTCP(Cookie* cookie)
void
Request::Reset()
Request::Reset(uid_t uid, gid_t gid)
{
fBuilder.Reset();
fBuilder.Reset(uid, gid);
fReply.Reset();
}
@@ -20,13 +20,14 @@ class FileSystem;
class Request {
public:
inline Request(RPC::Server* server,
FileSystem* fileSystem);
FileSystem* fileSystem,
uid_t uid, gid_t gid);
inline RequestBuilder& Builder();
inline ReplyInterpreter& Reply();
status_t Send(Cookie* cookie = NULL);
void Reset();
void Reset(uid_t uid, gid_t gid);
private:
status_t _SendUDP(Cookie* cookie);
@@ -41,10 +42,11 @@ private:
inline
Request::Request(RPC::Server* server, FileSystem* fileSystem)
Request::Request(RPC::Server* server, FileSystem* fileSystem, uid_t uid, gid_t gid)
:
fServer(server),
fFileSystem(fileSystem)
fFileSystem(fileSystem),
fBuilder(uid, gid)
{
ASSERT(server != NULL);
}
@@ -20,13 +20,13 @@
#include "RPCCallbackServer.h"
RequestBuilder::RequestBuilder(Procedure proc)
RequestBuilder::RequestBuilder(uid_t uid, gid_t gid, Procedure proc)
:
fOpCount(0),
fProcedure(proc),
fRequest(NULL)
{
_InitHeader();
_InitHeader(uid, gid);
}
@@ -37,9 +37,9 @@ RequestBuilder::~RequestBuilder()
void
RequestBuilder::_InitHeader()
RequestBuilder::_InitHeader(uid_t uid, gid_t gid)
{
fRequest = RPC::Call::Create(fProcedure, RPC::Auth::CreateSys(),
fRequest = RPC::Call::Create(fProcedure, RPC::Auth::CreateSys(uid, gid),
RPC::Auth::CreateNone());
if (fRequest == NULL)
@@ -25,10 +25,11 @@ struct LockOwner;
class RequestBuilder {
public:
RequestBuilder(Procedure p = ProcCompound);
RequestBuilder(uid_t uid, gid_t gid,
Procedure p = ProcCompound);
~RequestBuilder();
inline void Reset(Procedure proc = ProcCompound);
inline void Reset(uid_t uid, gid_t gid, Procedure proc = ProcCompound);
status_t Access();
status_t Close(uint32 seq, const uint32* id,
@@ -84,7 +85,7 @@ public:
RPC::Call* Request();
private:
void _InitHeader();
void _InitHeader(uid_t uid, gid_t gid);
void _GenerateLockOwner(XDR::WriteStream& stream,
OpenState* state, LockOwner* owner);
@@ -106,14 +107,14 @@ private:
inline void
RequestBuilder::Reset(Procedure proc)
RequestBuilder::Reset(uid_t uid, gid_t gid, Procedure proc)
{
fRequest->Stream().Clear();
fOpCount = 0;
fProcedure = proc;
delete fRequest;
_InitHeader();
_InitHeader(uid, gid);
}
@@ -61,7 +61,7 @@ RootInode::_UpdateInfo(bool force)
uint32 attempt = 0;
do {
RPC::Server* server = fFileSystem->Server();
Request request(server, fFileSystem);
Request request(server, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -152,7 +152,7 @@ RootInode::ProbeMigration()
uint32 attempt = 0;
do {
RPC::Server* server = fFileSystem->Server();
Request request(server, fFileSystem);
Request request(server, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
@@ -183,7 +183,7 @@ RootInode::GetLocations(AttrValue** attrv)
uint32 attempt = 0;
do {
RPC::Server* server = fFileSystem->Server();
Request request(server, fFileSystem);
Request request(server, fFileSystem, geteuid(), getegid());
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);