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:
Ingo Weinhold 2013-04-28 14:39:58 +02:00
parent 4521d4c6c7
commit 212cb7333a
3 changed files with 27 additions and 1 deletions

View File

@ -9,6 +9,8 @@
#include <algorithm>
#include <new>
#include <AutoDeleter.h>
#include <fs_cache.h>
#include <util/AutoLock.h>
@ -153,6 +155,12 @@ PackageFile::~PackageFile()
status_t
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
int fd = fPackage->Open();
if (fd < 0)
@ -164,7 +172,7 @@ PackageFile::VFSInit(dev_t deviceID, ino_t nodeID)
if (fDataAccessor == NULL)
RETURN_ERROR(B_NO_MEMORY);
status_t error = fDataAccessor->Init(deviceID, nodeID, fd);
error = fDataAccessor->Init(deviceID, nodeID, fd);
if (error != B_OK) {
delete fDataAccessor;
fDataAccessor = NULL;
@ -172,6 +180,7 @@ PackageFile::VFSInit(dev_t deviceID, ino_t nodeID)
}
packageCloser.Detach();
baseClassUninit.Detach();
return B_OK;
}
@ -184,6 +193,8 @@ PackageFile::VFSUninit()
delete fDataAccessor;
fDataAccessor = NULL;
}
PackageNode::VFSUninit();
}

View File

@ -10,6 +10,7 @@
#include <string.h>
#include "DebugSupport.h"
#include "Package.h"
PackageNode::PackageNode(Package* package, mode_t mode)
@ -48,6 +49,7 @@ PackageNode::Init(PackageDirectory* parent, const char* name)
status_t
PackageNode::VFSInit(dev_t deviceID, ino_t nodeID)
{
fPackage->AcquireReference();
return B_OK;
}
@ -55,6 +57,7 @@ PackageNode::VFSInit(dev_t deviceID, ino_t nodeID)
void
PackageNode::VFSUninit()
{
fPackage->ReleaseReference();
}

View File

@ -28,6 +28,11 @@ public:
virtual ~PackageNode();
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; }
const char* Name() const { return fName; }
@ -36,6 +41,7 @@ public:
virtual status_t VFSInit(dev_t deviceID, ino_t nodeID);
virtual void VFSUninit();
// base class versions must be called
mode_t Mode() const { return fMode; }
@ -65,6 +71,12 @@ public:
inline void* IndexCookieForAttribute(const char* name) const;
protected:
void NonVirtualVFSUninit()
{ PackageNode::VFSUninit(); }
// service for derived classes, e.g. for use
// with MethodDeleter
protected:
Package* fPackage;
PackageDirectory* fParent;