From 963a5e658a898f898f8c07c56d8f29a31d01b82a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 20 Jun 2012 17:05:25 +0200 Subject: [PATCH] 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. --- .../kernel/file_systems/nfs4/Filehandle.h | 22 +++++++++ .../kernel/file_systems/nfs4/Filesystem.cpp | 14 ++++++ .../kernel/file_systems/nfs4/Filesystem.h | 46 +++++++++++-------- .../kernel/file_systems/nfs4/Inode.cpp | 42 +++++++++++++---- .../file_systems/nfs4/ReplyInterpreter.cpp | 12 +++++ 5 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h index 3fae5ef2d1..f8a64d3d76 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 339558ab05..a67600fea6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -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(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; diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index 7000f4bd59..3ddc2ef575 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -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() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1a50bb6834..4149599b0b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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(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(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(buffer + pos); + // FATTR4_FSID is mandatory + void* data = dirents[i].fAttrs[0].fData.fPointer; + FilesystemId* fsid = reinterpret_cast(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()); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index cd9378f523..5a1fb56977 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -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();