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);
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -21,35 +21,38 @@ class InodeIdMap;
|
||||
|
||||
class Filesystem {
|
||||
public:
|
||||
static status_t Mount(Filesystem** pfs, RPC::Server* serv,
|
||||
const char* path, dev_t id);
|
||||
~Filesystem();
|
||||
static status_t Mount(Filesystem** pfs, RPC::Server* serv,
|
||||
const char* path, dev_t id);
|
||||
~Filesystem();
|
||||
|
||||
status_t GetInode(ino_t id, Inode** inode);
|
||||
Inode* CreateRootInode();
|
||||
status_t GetInode(ino_t id, Inode** inode);
|
||||
Inode* CreateRootInode();
|
||||
|
||||
status_t ReadInfo(struct fs_info* info);
|
||||
status_t ReadInfo(struct fs_info* info);
|
||||
|
||||
inline RPC::Server* Server();
|
||||
inline NFS4Server* NFSServer();
|
||||
inline RPC::Server* Server();
|
||||
inline NFS4Server* NFSServer();
|
||||
|
||||
inline uint64 AllocFileId();
|
||||
inline const FilesystemId& FsId() const;
|
||||
|
||||
inline dev_t DevId() const;
|
||||
inline InodeIdMap* InoIdMap();
|
||||
inline uint64 AllocFileId();
|
||||
|
||||
inline dev_t DevId() const;
|
||||
inline InodeIdMap* InoIdMap();
|
||||
private:
|
||||
Filesystem();
|
||||
Filesystem();
|
||||
|
||||
const char* fPath;
|
||||
const char* fPath;
|
||||
FilesystemId fFsId;
|
||||
|
||||
Filehandle fRootFH;
|
||||
Filehandle fRootFH;
|
||||
|
||||
RPC::Server* fServer;
|
||||
RPC::Server* fServer;
|
||||
|
||||
vint64 fId;
|
||||
dev_t fDevId;
|
||||
vint64 fId;
|
||||
dev_t fDevId;
|
||||
|
||||
InodeIdMap fInoIdMap;
|
||||
InodeIdMap fInoIdMap;
|
||||
};
|
||||
|
||||
|
||||
@@ -67,6 +70,13 @@ Filesystem::NFSServer()
|
||||
}
|
||||
|
||||
|
||||
inline const FilesystemId&
|
||||
Filesystem::FsId() const
|
||||
{
|
||||
return fFsId;
|
||||
}
|
||||
|
||||
|
||||
inline uint64
|
||||
Filesystem::AllocFileId()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user