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.GetFH();
|
||||||
req.Access();
|
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));
|
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||||
|
|
||||||
status_t result = request.Send();
|
status_t result = request.Send();
|
||||||
@@ -119,22 +120,28 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
|||||||
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;
|
||||||
|
|
||||||
|
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
|
// FATTR4_FSID is mandatory
|
||||||
FilesystemId* fsid =
|
FilesystemId* fsid =
|
||||||
reinterpret_cast<FilesystemId*>(values[0].fData.fPointer);
|
reinterpret_cast<FilesystemId*>(values[2].fData.fPointer);
|
||||||
|
|
||||||
Filesystem* fs = new(std::nothrow) Filesystem;
|
if (count == 4 && values[3].fAttribute == FATTR4_FS_LOCATIONS) {
|
||||||
|
|
||||||
if (count == 2 && values[1].fAttribute == FATTR4_FS_LOCATIONS) {
|
|
||||||
FSLocations* locs =
|
FSLocations* locs =
|
||||||
reinterpret_cast<FSLocations*>(values[1].fData.fLocations);
|
reinterpret_cast<FSLocations*>(values[3].fData.fLocations);
|
||||||
|
|
||||||
fs->fPath = strdup(locs->fRootPath);
|
fs->fPath = strdup(locs->fRootPath);
|
||||||
|
|
||||||
delete locs;
|
|
||||||
} else
|
} else
|
||||||
fs->fPath = NULL;
|
fs->fPath = NULL;
|
||||||
|
|
||||||
@@ -162,6 +169,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
|||||||
|
|
||||||
*pfs = fs;
|
*pfs = fs;
|
||||||
|
|
||||||
|
delete[] values;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +272,8 @@ Filesystem::ReadInfo(struct fs_info* info)
|
|||||||
info->flags = B_FS_IS_READONLY;
|
info->flags = B_FS_IS_READONLY;
|
||||||
strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH);
|
strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH);
|
||||||
|
|
||||||
|
delete[] values;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +320,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv)
|
|||||||
reinterpret_cast<module_info**>(&dns));
|
reinterpret_cast<module_info**>(&dns));
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
mutex_unlock(&fMigrationLock);
|
mutex_unlock(&fMigrationLock);
|
||||||
|
delete[] values;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +348,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
put_module(DNS_RESOLVER_MODULE_NAME);
|
put_module(DNS_RESOLVER_MODULE_NAME);
|
||||||
delete locs;
|
delete[] values;
|
||||||
|
|
||||||
if (server == fServer) {
|
if (server == fServer) {
|
||||||
mutex_unlock(&fMigrationLock);
|
mutex_unlock(&fMigrationLock);
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ public:
|
|||||||
status_t Migrate(const Filehandle& fh,
|
status_t Migrate(const Filehandle& fh,
|
||||||
const RPC::Server* serv);
|
const RPC::Server* serv);
|
||||||
|
|
||||||
|
inline bool IsAttrSupported(Attribute attr) const;
|
||||||
|
inline uint32 ExpireType() const;
|
||||||
|
|
||||||
inline RPC::Server* Server();
|
inline RPC::Server* Server();
|
||||||
inline NFS4Server* NFSServer();
|
inline NFS4Server* NFSServer();
|
||||||
|
|
||||||
@@ -46,6 +49,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
Filesystem();
|
Filesystem();
|
||||||
|
|
||||||
|
uint32 fExpireType;
|
||||||
|
uint32 fSupAttrs[2];
|
||||||
|
|
||||||
FilesystemId fFsId;
|
FilesystemId fFsId;
|
||||||
const char* fPath;
|
const char* fPath;
|
||||||
mutex fMigrationLock;
|
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*
|
inline RPC::Server*
|
||||||
Filesystem::Server()
|
Filesystem::Server()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -819,8 +819,28 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
|||||||
|
|
||||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
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) {
|
if ((mode & O_TRUNC) == O_TRUNC) {
|
||||||
AttrValue attr;
|
AttrValue attr;
|
||||||
attr.fAttribute = FATTR4_SIZE;
|
attr.fAttribute = FATTR4_SIZE;
|
||||||
@@ -844,6 +864,21 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
|||||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||||
continue;
|
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();
|
reply.PutFH();
|
||||||
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
@@ -1191,6 +1226,8 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
|
|||||||
} else
|
} else
|
||||||
fileId = values[0].fData.fValue64;
|
fileId = values[0].fData.fValue64;
|
||||||
|
|
||||||
|
delete[] values;
|
||||||
|
|
||||||
return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
|
return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,17 @@ enum Attribute {
|
|||||||
FATTR4_MAXIMUM_ATTR_ID
|
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 {
|
enum FileType {
|
||||||
NF4REG = 1, /* Regular File */
|
NF4REG = 1, /* Regular File */
|
||||||
NF4DIR = 2, /* Directory */
|
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
|
status_t
|
||||||
ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
||||||
{
|
{
|
||||||
@@ -513,6 +504,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
|
|||||||
|
|
||||||
uint32 current = 0;
|
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)) {
|
if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) {
|
||||||
values[current].fAttribute = FATTR4_TYPE;
|
values[current].fAttribute = FATTR4_TYPE;
|
||||||
values[current].fData.fValue32 = stream.GetInt();
|
values[current].fData.fValue32 = stream.GetInt();
|
||||||
|
|||||||
@@ -716,6 +716,17 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr,
|
|||||||
i++;
|
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) {
|
if (i < count && attr[i].fAttribute == FATTR4_MODE) {
|
||||||
str.AddUInt(attr[i].fData.fValue32);
|
str.AddUInt(attr[i].fData.fValue32);
|
||||||
i++;
|
i++;
|
||||||
|
|||||||
Reference in New Issue
Block a user