nfs4: Forbid accessing multiple NFS4 filesystems from one local mount
Haiku assumes that a pair dev_t:ino_t uniquely identifies a file. That may not be the case if we allow multiple filesystems share one dev_t.
This commit is contained in:
@@ -44,6 +44,14 @@ struct FileInfo {
|
|||||||
inline FileInfo& operator=(const FileInfo& fi);
|
inline FileInfo& operator=(const FileInfo& fi);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FilesystemId {
|
||||||
|
uint64 fMajor;
|
||||||
|
uint64 fMinor;
|
||||||
|
|
||||||
|
inline bool operator==(const FilesystemId& fsid) const;
|
||||||
|
inline bool operator!=(const FilesystemId& fsid) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
Filehandle::Filehandle()
|
Filehandle::Filehandle()
|
||||||
@@ -118,5 +126,19 @@ FileInfo::operator=(const FileInfo& fi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
FilesystemId::operator==(const FilesystemId& fsid) const
|
||||||
|
{
|
||||||
|
return fMajor == fsid.fMajor && fMinor == fsid.fMinor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
FilesystemId::operator!=(const FilesystemId& fsid) const
|
||||||
|
{
|
||||||
|
return !operator==(fsid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // FILEHANDLE_H
|
#endif // FILEHANDLE_H
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
|||||||
req.GetFH();
|
req.GetFH();
|
||||||
req.Access();
|
req.Access();
|
||||||
|
|
||||||
|
Attribute attr[] = { FATTR4_FSID };
|
||||||
|
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||||
|
|
||||||
status_t result = request.Send();
|
status_t result = request.Send();
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
@@ -92,11 +95,22 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
|||||||
!= (ACCESS4_READ | ACCESS4_LOOKUP))
|
!= (ACCESS4_READ | ACCESS4_LOOKUP))
|
||||||
return B_PERMISSION_DENIED;
|
return B_PERMISSION_DENIED;
|
||||||
|
|
||||||
|
AttrValue* values;
|
||||||
|
uint32 count;
|
||||||
|
result = reply.GetAttr(&values, &count);
|
||||||
|
if (result != B_OK || count < 1)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// FATTR4_FSID is mandatory
|
||||||
|
FilesystemId* fsid =
|
||||||
|
reinterpret_cast<FilesystemId*>(values[0].fData.fPointer);
|
||||||
|
|
||||||
Filesystem* fs = new(std::nothrow) Filesystem;
|
Filesystem* fs = new(std::nothrow) Filesystem;
|
||||||
fs->fPath = strdup(fsPath);
|
fs->fPath = strdup(fsPath);
|
||||||
memcpy(&fs->fRootFH, &fh, sizeof(Filehandle));
|
memcpy(&fs->fRootFH, &fh, sizeof(Filehandle));
|
||||||
fs->fServer = serv;
|
fs->fServer = serv;
|
||||||
fs->fDevId = id;
|
fs->fDevId = id;
|
||||||
|
fs->fFsId = *fsid;
|
||||||
|
|
||||||
*pfs = fs;
|
*pfs = fs;
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ public:
|
|||||||
inline RPC::Server* Server();
|
inline RPC::Server* Server();
|
||||||
inline NFS4Server* NFSServer();
|
inline NFS4Server* NFSServer();
|
||||||
|
|
||||||
|
inline const FilesystemId& FsId() const;
|
||||||
|
|
||||||
inline uint64 AllocFileId();
|
inline uint64 AllocFileId();
|
||||||
|
|
||||||
inline dev_t DevId() const;
|
inline dev_t DevId() const;
|
||||||
@@ -41,6 +43,7 @@ private:
|
|||||||
Filesystem();
|
Filesystem();
|
||||||
|
|
||||||
const char* fPath;
|
const char* fPath;
|
||||||
|
FilesystemId fFsId;
|
||||||
|
|
||||||
Filehandle fRootFH;
|
Filehandle fRootFH;
|
||||||
|
|
||||||
@@ -67,6 +70,13 @@ Filesystem::NFSServer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const FilesystemId&
|
||||||
|
Filesystem::FsId() const
|
||||||
|
{
|
||||||
|
return fFsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline uint64
|
inline uint64
|
||||||
Filesystem::AllocFileId()
|
Filesystem::AllocFileId()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode)
|
|||||||
|
|
||||||
req.PutFH(inode->fHandle);
|
req.PutFH(inode->fHandle);
|
||||||
|
|
||||||
Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID };
|
Attribute attr[] = { FATTR4_TYPE, FATTR4_FSID, FATTR4_FILEID };
|
||||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||||
|
|
||||||
status_t result = request.Send();
|
status_t result = request.Send();
|
||||||
@@ -64,20 +64,28 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode)
|
|||||||
AttrValue* values;
|
AttrValue* values;
|
||||||
uint32 count;
|
uint32 count;
|
||||||
result = reply.GetAttr(&values, &count);
|
result = reply.GetAttr(&values, &count);
|
||||||
if (result != B_OK || count < 1)
|
if (result != B_OK || count < 2)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (fi.fFileId == 0) {
|
if (fi.fFileId == 0) {
|
||||||
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
|
if (count < 3 || values[2].fAttribute != FATTR4_FILEID)
|
||||||
inode->fFileId = fs->AllocFileId();
|
inode->fFileId = fs->AllocFileId();
|
||||||
else
|
else
|
||||||
inode->fFileId = values[1].fData.fValue64;
|
inode->fFileId = values[2].fData.fValue64;
|
||||||
} else
|
} else
|
||||||
inode->fFileId = fi.fFileId;
|
inode->fFileId = fi.fFileId;
|
||||||
|
|
||||||
// FATTR4_TYPE is mandatory
|
// FATTR4_TYPE is mandatory
|
||||||
inode->fType = values[0].fData.fValue32;
|
inode->fType = values[0].fData.fValue32;
|
||||||
|
|
||||||
|
// FATTR4_FSID is mandatory
|
||||||
|
FilesystemId* fsid =
|
||||||
|
reinterpret_cast<FilesystemId*>(values[1].fData.fPointer);
|
||||||
|
if (*fsid != fs->FsId()) {
|
||||||
|
delete[] values;
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
|
||||||
*_inode = inode;
|
*_inode = inode;
|
||||||
@@ -117,7 +125,7 @@ Inode::LookUp(const char* name, ino_t* id)
|
|||||||
|
|
||||||
req.GetFH();
|
req.GetFH();
|
||||||
|
|
||||||
Attribute attr[] = { FATTR4_FILEID };
|
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
|
||||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||||
|
|
||||||
status_t result = request.Send();
|
status_t result = request.Send();
|
||||||
@@ -154,11 +162,19 @@ Inode::LookUp(const char* name, ino_t* id)
|
|||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
// FATTR4_FSID is mandatory
|
||||||
|
FilesystemId* fsid =
|
||||||
|
reinterpret_cast<FilesystemId*>(values[0].fData.fPointer);
|
||||||
|
if (*fsid != fFilesystem->FsId()) {
|
||||||
|
delete[] values;
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
uint64 fileId;
|
uint64 fileId;
|
||||||
if (count < 1 || values[0].fAttribute != FATTR4_FILEID)
|
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
|
||||||
fileId = fFilesystem->AllocFileId();
|
fileId = fFilesystem->AllocFileId();
|
||||||
else
|
else
|
||||||
fileId = values[0].fData.fValue64;
|
fileId = values[1].fData.fValue64;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
|
||||||
*id = _FileIdToInoT(fileId);
|
*id = _FileIdToInoT(fileId);
|
||||||
@@ -646,7 +662,7 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
|
|||||||
|
|
||||||
req.PutFH(fHandle);
|
req.PutFH(fHandle);
|
||||||
|
|
||||||
Attribute attr[] = { FATTR4_FILEID };
|
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
|
||||||
req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute));
|
req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute));
|
||||||
|
|
||||||
status_t result = request.Send();
|
status_t result = request.Send();
|
||||||
@@ -797,9 +813,15 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie)
|
|||||||
for (i = 0; i < min_c(this_count, *_count - count); i++) {
|
for (i = 0; i < min_c(this_count, *_count - count); i++) {
|
||||||
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||||
|
|
||||||
|
// FATTR4_FSID is mandatory
|
||||||
|
void* data = dirents[i].fAttrs[0].fData.fPointer;
|
||||||
|
FilesystemId* fsid = reinterpret_cast<FilesystemId*>(data);
|
||||||
|
if (*fsid != fFilesystem->FsId())
|
||||||
|
continue;
|
||||||
|
|
||||||
ino_t id;
|
ino_t id;
|
||||||
if (dirents[i].fAttrCount == 1)
|
if (dirents[i].fAttrCount == 2)
|
||||||
id = _FileIdToInoT(dirents[i].fAttrs[0].fData.fValue64);
|
id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
|
||||||
else
|
else
|
||||||
id = _FileIdToInoT(fFilesystem->AllocFileId());
|
id = _FileIdToInoT(fFilesystem->AllocFileId());
|
||||||
|
|
||||||
|
|||||||
@@ -337,6 +337,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
|
|||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sIsAttrSet(FATTR4_FSID, bitmap, bcount)) {
|
||||||
|
values[current].fAttribute = FATTR4_FSID;
|
||||||
|
values[current].fFreePointer = true;
|
||||||
|
|
||||||
|
FilesystemId fsid;
|
||||||
|
fsid.fMajor = stream.GetUHyper();
|
||||||
|
fsid.fMinor = stream.GetUHyper();
|
||||||
|
|
||||||
|
values[current].fData.fPointer = new FilesystemId(fsid);
|
||||||
|
current++;
|
||||||
|
}
|
||||||
|
|
||||||
if (sIsAttrSet(FATTR4_LEASE_TIME, bitmap, bcount)) {
|
if (sIsAttrSet(FATTR4_LEASE_TIME, bitmap, bcount)) {
|
||||||
values[current].fAttribute = FATTR4_LEASE_TIME;
|
values[current].fAttribute = FATTR4_LEASE_TIME;
|
||||||
values[current].fData.fValue32 = stream.GetUInt();
|
values[current].fData.fValue32 = stream.GetUInt();
|
||||||
|
|||||||
Reference in New Issue
Block a user