nfs4: Verify inode number before opening a file
This commit is contained in:
@@ -91,7 +91,8 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
||||
req.GetFH();
|
||||
req.Access();
|
||||
|
||||
Attribute attr[] = { FATTR4_FSID, FATTR4_FS_LOCATIONS };
|
||||
Attribute attr[] = { FATTR4_SUPPORTED_ATTRS, FATTR4_FH_EXPIRE_TYPE,
|
||||
FATTR4_FSID, FATTR4_FS_LOCATIONS };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
|
||||
status_t result = request.Send();
|
||||
@@ -119,22 +120,28 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK || count < 1)
|
||||
if (result != B_OK || count < 2)
|
||||
return result;
|
||||
|
||||
Filesystem* fs = new(std::nothrow) Filesystem;
|
||||
if (fs == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// FATTR4_SUPPORTED_ATTRS is mandatory
|
||||
memcpy(fs->fSupAttrs, &values[0].fData.fValue64, sizeof(fs->fSupAttrs));
|
||||
|
||||
// FATTR4_FH_EXPIRE_TYPE is mandatory
|
||||
fs->fExpireType = values[1].fData.fValue32;
|
||||
|
||||
// FATTR4_FSID is mandatory
|
||||
FilesystemId* fsid =
|
||||
reinterpret_cast<FilesystemId*>(values[0].fData.fPointer);
|
||||
reinterpret_cast<FilesystemId*>(values[2].fData.fPointer);
|
||||
|
||||
Filesystem* fs = new(std::nothrow) Filesystem;
|
||||
|
||||
if (count == 2 && values[1].fAttribute == FATTR4_FS_LOCATIONS) {
|
||||
if (count == 4 && values[3].fAttribute == FATTR4_FS_LOCATIONS) {
|
||||
FSLocations* locs =
|
||||
reinterpret_cast<FSLocations*>(values[1].fData.fLocations);
|
||||
reinterpret_cast<FSLocations*>(values[3].fData.fLocations);
|
||||
|
||||
fs->fPath = strdup(locs->fRootPath);
|
||||
|
||||
delete locs;
|
||||
} else
|
||||
fs->fPath = NULL;
|
||||
|
||||
@@ -162,6 +169,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
||||
|
||||
*pfs = fs;
|
||||
|
||||
delete[] values;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -264,6 +272,8 @@ Filesystem::ReadInfo(struct fs_info* info)
|
||||
info->flags = B_FS_IS_READONLY;
|
||||
strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH);
|
||||
|
||||
delete[] values;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -310,6 +320,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv)
|
||||
reinterpret_cast<module_info**>(&dns));
|
||||
if (result != B_OK) {
|
||||
mutex_unlock(&fMigrationLock);
|
||||
delete[] values;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -337,7 +348,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv)
|
||||
}
|
||||
|
||||
put_module(DNS_RESOLVER_MODULE_NAME);
|
||||
delete locs;
|
||||
delete[] values;
|
||||
|
||||
if (server == fServer) {
|
||||
mutex_unlock(&fMigrationLock);
|
||||
|
||||
@@ -33,6 +33,9 @@ public:
|
||||
status_t Migrate(const Filehandle& fh,
|
||||
const RPC::Server* serv);
|
||||
|
||||
inline bool IsAttrSupported(Attribute attr) const;
|
||||
inline uint32 ExpireType() const;
|
||||
|
||||
inline RPC::Server* Server();
|
||||
inline NFS4Server* NFSServer();
|
||||
|
||||
@@ -46,6 +49,9 @@ public:
|
||||
private:
|
||||
Filesystem();
|
||||
|
||||
uint32 fExpireType;
|
||||
uint32 fSupAttrs[2];
|
||||
|
||||
FilesystemId fFsId;
|
||||
const char* fPath;
|
||||
mutex fMigrationLock;
|
||||
@@ -63,6 +69,20 @@ private:
|
||||
};
|
||||
|
||||
|
||||
inline bool
|
||||
Filesystem::IsAttrSupported(Attribute attr) const
|
||||
{
|
||||
return sIsAttrSet(attr, fSupAttrs, 2);
|
||||
}
|
||||
|
||||
|
||||
inline uint32
|
||||
Filesystem::ExpireType() const
|
||||
{
|
||||
return fExpireType;
|
||||
}
|
||||
|
||||
|
||||
inline RPC::Server*
|
||||
Filesystem::Server()
|
||||
{
|
||||
|
||||
@@ -819,8 +819,28 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
|
||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
||||
|
||||
req.PutFH(fParentFH);
|
||||
// Since we are opening the file using a pair (parentFH, name) we
|
||||
// need to check for race conditions.
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
req.PutFH(fParentFH);
|
||||
req.LookUp(fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEID;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = fFileId;
|
||||
req.Verify(&attr, 1);
|
||||
} else if (fFilesystem->ExpireType() == FH4_PERSISTENT) {
|
||||
req.PutFH(fParentFH);
|
||||
req.LookUp(fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEHANDLE;
|
||||
attr.fFreePointer = true;
|
||||
attr.fData.fPointer = malloc(sizeof(fHandle));
|
||||
memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle));
|
||||
req.Verify(&attr, 1);
|
||||
}
|
||||
|
||||
req.PutFH(fParentFH);
|
||||
if ((mode & O_TRUNC) == O_TRUNC) {
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_SIZE;
|
||||
@@ -844,6 +864,21 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
// Verify if the file we want to open is the file this Inode
|
||||
// represents.
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID) ||
|
||||
fFilesystem->ExpireType() == FH4_PERSISTENT) {
|
||||
reply.PutFH();
|
||||
result = reply.LookUp();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
result = reply.Verify();
|
||||
if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
else if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
||||
if (result != B_OK)
|
||||
@@ -1191,6 +1226,8 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
|
||||
} else
|
||||
fileId = values[0].fData.fValue64;
|
||||
|
||||
delete[] values;
|
||||
|
||||
return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -124,6 +124,17 @@ enum Attribute {
|
||||
FATTR4_MAXIMUM_ATTR_ID
|
||||
};
|
||||
|
||||
|
||||
static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap,
|
||||
uint32 count)
|
||||
{
|
||||
if ((uint32)attr / 32 >= count)
|
||||
return false;
|
||||
|
||||
return (bitmap[attr / 32] & 1 << attr % 32) != 0;
|
||||
}
|
||||
|
||||
|
||||
enum FileType {
|
||||
NF4REG = 1, /* Regular File */
|
||||
NF4DIR = 2, /* Directory */
|
||||
|
||||
@@ -154,15 +154,6 @@ static inline uint32 sCountBits(uint32 v)
|
||||
}
|
||||
|
||||
|
||||
static inline bool sIsAttrSet(Attribute attr, uint32* bitmap, uint32 count)
|
||||
{
|
||||
if ((uint32)attr / 32 >= count)
|
||||
return false;
|
||||
|
||||
return (bitmap[attr / 32] & 1 << attr % 32) != 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
||||
{
|
||||
@@ -513,6 +504,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
|
||||
|
||||
uint32 current = 0;
|
||||
|
||||
if (sIsAttrSet(FATTR4_SUPPORTED_ATTRS, bitmap, bcount)) {
|
||||
values[current].fAttribute = FATTR4_SUPPORTED_ATTRS;
|
||||
uint32 count = stream.GetInt();
|
||||
uint32 i;
|
||||
// two uint32 are enough for NFS4, not for NFS4.1
|
||||
for (i = 0; i < min_c(count, 2); i++)
|
||||
((uint32*)&values[current].fData.fValue64)[i] = stream.GetUInt();
|
||||
for (; i < count; i++)
|
||||
stream.GetUInt();
|
||||
current++;
|
||||
}
|
||||
|
||||
if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) {
|
||||
values[current].fAttribute = FATTR4_TYPE;
|
||||
values[current].fData.fValue32 = stream.GetInt();
|
||||
|
||||
@@ -716,6 +716,17 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr,
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < count && attr[i].fAttribute == FATTR4_FILEHANDLE) {
|
||||
Filehandle* fh = reinterpret_cast<Filehandle*>(attr[i].fData.fPointer);
|
||||
str.AddOpaque(fh->fFH, fh->fSize);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < count && attr[i].fAttribute == FATTR4_FILEID) {
|
||||
str.AddUHyper(attr[i].fData.fValue64);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < count && attr[i].fAttribute == FATTR4_MODE) {
|
||||
str.AddUInt(attr[i].fData.fValue32);
|
||||
i++;
|
||||
|
||||
Reference in New Issue
Block a user