packagefs: Fix deadbeef when using a file after package removal
When closing a file whose package had been removed, PackageFile::VFSUninit() would crash due to calling Package::Close() on an already destroyed Package object. PackageNode does now hold a reference to the package between VFSInit() and VFSUninit().
This commit is contained in:
@@ -9,6 +9,8 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
#include <fs_cache.h>
|
#include <fs_cache.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
@@ -153,6 +155,12 @@ PackageFile::~PackageFile()
|
|||||||
status_t
|
status_t
|
||||||
PackageFile::VFSInit(dev_t deviceID, ino_t nodeID)
|
PackageFile::VFSInit(dev_t deviceID, ino_t nodeID)
|
||||||
{
|
{
|
||||||
|
status_t error = PackageNode::VFSInit(deviceID, nodeID);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
MethodDeleter<PackageNode> baseClassUninit(this,
|
||||||
|
&PackageNode::NonVirtualVFSUninit);
|
||||||
|
|
||||||
// open the package
|
// open the package
|
||||||
int fd = fPackage->Open();
|
int fd = fPackage->Open();
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
@@ -164,7 +172,7 @@ PackageFile::VFSInit(dev_t deviceID, ino_t nodeID)
|
|||||||
if (fDataAccessor == NULL)
|
if (fDataAccessor == NULL)
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
status_t error = fDataAccessor->Init(deviceID, nodeID, fd);
|
error = fDataAccessor->Init(deviceID, nodeID, fd);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
delete fDataAccessor;
|
delete fDataAccessor;
|
||||||
fDataAccessor = NULL;
|
fDataAccessor = NULL;
|
||||||
@@ -172,6 +180,7 @@ PackageFile::VFSInit(dev_t deviceID, ino_t nodeID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
packageCloser.Detach();
|
packageCloser.Detach();
|
||||||
|
baseClassUninit.Detach();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +193,8 @@ PackageFile::VFSUninit()
|
|||||||
delete fDataAccessor;
|
delete fDataAccessor;
|
||||||
fDataAccessor = NULL;
|
fDataAccessor = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PackageNode::VFSUninit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "DebugSupport.h"
|
#include "DebugSupport.h"
|
||||||
|
#include "Package.h"
|
||||||
|
|
||||||
|
|
||||||
PackageNode::PackageNode(Package* package, mode_t mode)
|
PackageNode::PackageNode(Package* package, mode_t mode)
|
||||||
@@ -48,6 +49,7 @@ PackageNode::Init(PackageDirectory* parent, const char* name)
|
|||||||
status_t
|
status_t
|
||||||
PackageNode::VFSInit(dev_t deviceID, ino_t nodeID)
|
PackageNode::VFSInit(dev_t deviceID, ino_t nodeID)
|
||||||
{
|
{
|
||||||
|
fPackage->AcquireReference();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +57,7 @@ PackageNode::VFSInit(dev_t deviceID, ino_t nodeID)
|
|||||||
void
|
void
|
||||||
PackageNode::VFSUninit()
|
PackageNode::VFSUninit()
|
||||||
{
|
{
|
||||||
|
fPackage->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ public:
|
|||||||
virtual ~PackageNode();
|
virtual ~PackageNode();
|
||||||
|
|
||||||
Package* GetPackage() const { return fPackage; }
|
Package* GetPackage() const { return fPackage; }
|
||||||
|
// Since PackageNode does only hold a
|
||||||
|
// reference to the package between
|
||||||
|
// VFSInit() and VFSUninit(), the caller
|
||||||
|
// must otherwise make sure the package
|
||||||
|
// still exists.
|
||||||
PackageDirectory* Parent() const { return fParent; }
|
PackageDirectory* Parent() const { return fParent; }
|
||||||
const char* Name() const { return fName; }
|
const char* Name() const { return fName; }
|
||||||
|
|
||||||
@@ -36,6 +41,7 @@ public:
|
|||||||
|
|
||||||
virtual status_t VFSInit(dev_t deviceID, ino_t nodeID);
|
virtual status_t VFSInit(dev_t deviceID, ino_t nodeID);
|
||||||
virtual void VFSUninit();
|
virtual void VFSUninit();
|
||||||
|
// base class versions must be called
|
||||||
|
|
||||||
mode_t Mode() const { return fMode; }
|
mode_t Mode() const { return fMode; }
|
||||||
|
|
||||||
@@ -65,6 +71,12 @@ public:
|
|||||||
|
|
||||||
inline void* IndexCookieForAttribute(const char* name) const;
|
inline void* IndexCookieForAttribute(const char* name) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void NonVirtualVFSUninit()
|
||||||
|
{ PackageNode::VFSUninit(); }
|
||||||
|
// service for derived classes, e.g. for use
|
||||||
|
// with MethodDeleter
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Package* fPackage;
|
Package* fPackage;
|
||||||
PackageDirectory* fParent;
|
PackageDirectory* fParent;
|
||||||
|
|||||||
Reference in New Issue
Block a user