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:
Pawel Dziepak
2012-06-29 02:14:57 +02:00
parent 8b908ae4e8
commit 963a5e658a
5 changed files with 108 additions and 28 deletions
@@ -44,6 +44,14 @@ struct FileInfo {
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
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
@@ -63,6 +63,9 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
req.GetFH();
req.Access();
Attribute attr[] = { FATTR4_FSID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
if (result != B_OK)
return result;
@@ -92,11 +95,22 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
!= (ACCESS4_READ | ACCESS4_LOOKUP))
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;
fs->fPath = strdup(fsPath);
memcpy(&fs->fRootFH, &fh, sizeof(Filehandle));
fs->fServer = serv;
fs->fDevId = id;
fs->fFsId = *fsid;
*pfs = fs;
@@ -33,6 +33,8 @@ public:
inline RPC::Server* Server();
inline NFS4Server* NFSServer();
inline const FilesystemId& FsId() const;
inline uint64 AllocFileId();
inline dev_t DevId() const;
@@ -41,6 +43,7 @@ private:
Filesystem();
const char* fPath;
FilesystemId fFsId;
Filehandle fRootFH;
@@ -67,6 +70,13 @@ Filesystem::NFSServer()
}
inline const FilesystemId&
Filesystem::FsId() const
{
return fFsId;
}
inline uint64
Filesystem::AllocFileId()
{
+32 -10
View File
@@ -42,7 +42,7 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode)
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));
status_t result = request.Send();
@@ -64,20 +64,28 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode)
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK || count < 1)
if (result != B_OK || count < 2)
return result;
if (fi.fFileId == 0) {
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
if (count < 3 || values[2].fAttribute != FATTR4_FILEID)
inode->fFileId = fs->AllocFileId();
else
inode->fFileId = values[1].fData.fValue64;
inode->fFileId = values[2].fData.fValue64;
} else
inode->fFileId = fi.fFileId;
// FATTR4_TYPE is mandatory
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;
*_inode = inode;
@@ -117,7 +125,7 @@ Inode::LookUp(const char* name, ino_t* id)
req.GetFH();
Attribute attr[] = { FATTR4_FILEID };
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
@@ -154,11 +162,19 @@ Inode::LookUp(const char* name, ino_t* id)
if (result != B_OK)
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;
if (count < 1 || values[0].fAttribute != FATTR4_FILEID)
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
fileId = fFilesystem->AllocFileId();
else
fileId = values[0].fData.fValue64;
fileId = values[1].fData.fValue64;
delete[] values;
*id = _FileIdToInoT(fileId);
@@ -646,7 +662,7 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
req.PutFH(fHandle);
Attribute attr[] = { FATTR4_FILEID };
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute));
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++) {
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;
if (dirents[i].fAttrCount == 1)
id = _FileIdToInoT(dirents[i].fAttrs[0].fData.fValue64);
if (dirents[i].fAttrCount == 2)
id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
else
id = _FileIdToInoT(fFilesystem->AllocFileId());
@@ -337,6 +337,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
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)) {
values[current].fAttribute = FATTR4_LEASE_TIME;
values[current].fData.fValue32 = stream.GetUInt();