1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-06-08 11:16:54 +03:00

python-lvm: Ensure library handle is correct after python gc() call

In a previous commit we added the ability for the library to do garbage
collection, to free all the memory used by the library handle buffer by closing
and re-opening the library handle.  When we introduced this functionality we
also opened up the opportunity that the user of the python bindings to have
an object that references the old library handle.  In this case if the user
tried to use the old object a segmentation fault could occur because the
memory had been previously freed.

This patch tries to mitigate this by storing a copy of the library handle that
was used when the object was created so that it can compare the current in
use pointer with what existed when the object was created.  In the case where
they match the operation is permitted to continue, otherwise an exception is
throw, thus avoiding a segmentation fault.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
This commit is contained in:
Tony Asleson 2013-07-31 15:16:01 -05:00
parent 1f744733a1
commit 20ffb0f721

View File

@ -30,11 +30,13 @@ static lvm_t _libh;
typedef struct {
PyObject_HEAD
vg_t vg; /* vg handle */
lvm_t libh_copy;
} vgobject;
typedef struct {
PyObject_HEAD
struct dm_list *pvslist;
lvm_t libh_copy;
} pvslistobject;
typedef struct {
@ -71,9 +73,14 @@ static PyTypeObject _LibLVMpvsegType;
static PyObject *_LibLVMError;
#define LVM_VALID() \
#define LVM_VALID(ptr) \
do { \
if (!_libh) { \
if (ptr && _libh) { \
if (ptr != _libh) { \
PyErr_SetString(PyExc_UnboundLocalError, "LVM handle reference stale"); \
return NULL; \
} \
} else if (!_libh) { \
PyErr_SetString(PyExc_UnboundLocalError, "LVM handle invalid"); \
return NULL; \
} \
@ -99,17 +106,42 @@ static vgobject *_create_py_vg(void)
{
vgobject *vgobj = PyObject_New(vgobject, &_LibLVMvgType);
if (vgobj)
if (vgobj) {
vgobj->vg = NULL;
vgobj->libh_copy = _libh;
}
return vgobj;
}
static pvslistobject *_create_py_pvlist(void)
{
pvslistobject *pvlistobj = PyObject_New(pvslistobject, &_LibLVMpvlistType);
if (pvlistobj) {
pvlistobj->pvslist = NULL;
pvlistobj->libh_copy = _libh;
}
return pvlistobj;
}
static lvobject *_create_py_lv(vgobject *parent, lv_t lv)
{
lvobject * lvobj = PyObject_New(lvobject, &_LibLVMlvType);
if (lvobj) {
lvobj->parent_vgobj = parent;
Py_INCREF(lvobj->parent_vgobj);
lvobj->lv = lv;
}
return lvobj;
}
static PyObject *_liblvm_get_last_error(void)
{
PyObject *info;
LVM_VALID();
LVM_VALID(NULL);
if (!(info = PyTuple_New(2)))
return NULL;
@ -122,7 +154,7 @@ static PyObject *_liblvm_get_last_error(void)
static PyObject *_liblvm_library_get_version(void)
{
LVM_VALID();
LVM_VALID(NULL);
return Py_BuildValue("s", lvm_library_get_version());
}
@ -131,7 +163,7 @@ static const char _gc_doc[] = "Garbage collect the C library";
static PyObject *_liblvm_lvm_gc(void)
{
LVM_VALID();
LVM_VALID(NULL);
lvm_quit(_libh);
@ -152,7 +184,7 @@ static PyObject *_liblvm_lvm_list_vg_names(void)
PyObject * pytuple;
int i = 0;
LVM_VALID();
LVM_VALID(NULL);
if (!(vgnames = lvm_list_vg_names(_libh))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
@ -177,7 +209,7 @@ static PyObject *_liblvm_lvm_list_vg_uuids(void)
PyObject * pytuple;
int i = 0;
LVM_VALID();
LVM_VALID(NULL);
if (!(uuids = lvm_list_vg_uuids(_libh))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
@ -261,23 +293,16 @@ static PyObject *_liblvm_pvlist_dealloc(pvslistobject *self)
static PyObject *_liblvm_lvm_list_pvs(void)
{
pvslistobject *pvslistobj;
LVM_VALID(NULL);
LVM_VALID();
if (!(pvslistobj = PyObject_New(pvslistobject, &_LibLVMpvlistType)))
return NULL;
pvslistobj->pvslist = NULL;
return (PyObject *)pvslistobj;
return (PyObject *)_create_py_pvlist();
}
static PyObject *_liblvm_lvm_pv_remove(PyObject *self, PyObject *arg)
{
const char *pv_name;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(arg, "s", &pv_name))
return NULL;
@ -297,7 +322,7 @@ static PyObject *_liblvm_lvm_pv_create(PyObject *self, PyObject *arg)
const char *pv_name;
unsigned long long size;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(arg, "sK", &pv_name, &size))
return NULL;
@ -317,7 +342,7 @@ static PyObject *_liblvm_lvm_percent_to_float(PyObject *self, PyObject *arg)
double converted;
int percent;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(arg, "i", &percent))
return NULL;
@ -332,7 +357,7 @@ static PyObject *_liblvm_lvm_vgname_from_pvid(PyObject *self, PyObject *arg)
const char *pvid;
const char *vgname;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(arg, "s", &pvid))
return NULL;
@ -350,7 +375,7 @@ static PyObject *_liblvm_lvm_vgname_from_device(PyObject *self, PyObject *arg)
const char *device;
const char *vgname;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(arg, "s", &device))
return NULL;
@ -370,7 +395,7 @@ static PyObject *_liblvm_lvm_config_find_bool(PyObject *self, PyObject *arg)
int rval;
PyObject *rc;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(arg, "s", &config))
return NULL;
@ -390,7 +415,7 @@ static PyObject *_liblvm_lvm_config_find_bool(PyObject *self, PyObject *arg)
static PyObject *_liblvm_lvm_config_reload(void)
{
LVM_VALID();
LVM_VALID(NULL);
if (lvm_config_reload(_libh) == -1) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
@ -405,7 +430,7 @@ static PyObject *_liblvm_lvm_config_reload(void)
static PyObject *_liblvm_lvm_scan(void)
{
LVM_VALID();
LVM_VALID(NULL);
if (lvm_scan(_libh) == -1) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
@ -421,7 +446,7 @@ static PyObject *_liblvm_lvm_config_override(PyObject *self, PyObject *arg)
{
const char *config;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(arg, "s", &config))
return NULL;
@ -447,7 +472,7 @@ static PyObject *_liblvm_lvm_vg_open(PyObject *self, PyObject *args)
vgobject *vgobj;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(args, "s|s", &vgname, &mode))
return NULL;
@ -472,7 +497,7 @@ static PyObject *_liblvm_lvm_vg_create(PyObject *self, PyObject *args)
const char *vgname;
vgobject *vgobj;
LVM_VALID();
LVM_VALID(NULL);
if (!PyArg_ParseTuple(args, "s", &vgname))
return NULL;
@ -495,6 +520,7 @@ static void liblvm_vg_dealloc(vgobject *self)
if (self->vg != NULL) {
lvm_vg_close(self->vg);
self->vg = NULL;
self->libh_copy = NULL;
}
PyObject_Del(self);
@ -504,20 +530,20 @@ static void liblvm_vg_dealloc(vgobject *self)
#define VG_VALID(vgobject) \
do { \
LVM_VALID(); \
if (!vgobject->vg) { \
if (!vgobject || !vgobject->vg) { \
PyErr_SetString(PyExc_UnboundLocalError, "VG object invalid"); \
return NULL; \
} \
LVM_VALID(vgobject->libh_copy); \
} while (0)
#define PVSLIST_VALID(pvslistobject) \
do { \
LVM_VALID(); \
if (!pvslistobject->pvslist) { \
if (!pvslistobject || !pvslistobject->pvslist) { \
PyErr_SetString(PyExc_UnboundLocalError, "PVS object invalid"); \
return NULL; \
} \
LVM_VALID(pvslistobject->libh_copy); \
} while (0)
static PyObject *_liblvm_lvm_vg_close(vgobject *self)
@ -526,6 +552,7 @@ static PyObject *_liblvm_lvm_vg_close(vgobject *self)
if (self->vg) {
lvm_vg_close(self->vg);
self->vg = NULL;
self->libh_copy = NULL;
}
Py_INCREF(Py_None);
@ -941,15 +968,11 @@ static PyObject *_liblvm_lvm_vg_list_lvs(vgobject *self)
dm_list_iterate_items(lvl, lvs) {
/* Create and initialize the object */
if (!(lvobj = PyObject_New(lvobject, &_LibLVMlvType))) {
if (!(lvobj = _create_py_lv(self, lvl->lv))) {
Py_DECREF(pytuple);
return NULL;
}
lvobj->parent_vgobj = self;
Py_INCREF(lvobj->parent_vgobj);
lvobj->lv = lvl->lv;
PyTuple_SET_ITEM(pytuple, i, (PyObject *) lvobj);
i++;
}
@ -986,29 +1009,19 @@ static PyObject *_liblvm_lvm_vg_create_lv_linear(vgobject *self, PyObject *args)
{
const char *vgname;
unsigned long long size;
lvobject *lvobj;
lv_t lv;
VG_VALID(self);
if (!PyArg_ParseTuple(args, "sK", &vgname, &size))
return NULL;
if (!(lvobj = PyObject_New(lvobject, &_LibLVMlvType)))
return NULL;
/* Initialize the parent ptr in case lv create fails and we dealloc lvobj */
lvobj->parent_vgobj = NULL;
if (!(lvobj->lv = lvm_vg_create_lv_linear(self->vg, vgname, size))) {
if (!(lv = lvm_vg_create_lv_linear(self->vg, vgname, size))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
lvobj->parent_vgobj = self;
Py_INCREF(lvobj->parent_vgobj);
return (PyObject *)lvobj;
return (PyObject *)_create_py_lv(self, lv);
}
static PyObject *_liblvm_lvm_vg_create_lv_thinpool(vgobject *self, PyObject *args)
@ -1019,7 +1032,7 @@ static PyObject *_liblvm_lvm_vg_create_lv_thinpool(vgobject *self, PyObject *arg
unsigned long chunk_size = 0;
int skip_zero = 0;
lvm_thin_discards_t discard = LVM_THIN_DISCARDS_PASSDOWN;
lvobject *lvobj;
lv_t lv;
lv_create_params_t lvp = NULL;
struct lvm_property_value prop_value;
@ -1029,17 +1042,10 @@ static PyObject *_liblvm_lvm_vg_create_lv_thinpool(vgobject *self, PyObject *arg
&meta_size, &discard, &skip_zero))
return NULL;
if (!(lvobj = PyObject_New(lvobject, &_LibLVMlvType)))
return NULL;
/* Initialize the parent ptr in case lv create fails and we dealloc lvobj */
lvobj->parent_vgobj = NULL;
if (!(lvp = lvm_lv_params_create_thin_pool(self->vg, pool_name, size, chunk_size,
meta_size, discard))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
@ -1051,23 +1057,20 @@ static PyObject *_liblvm_lvm_vg_create_lv_thinpool(vgobject *self, PyObject *arg
if (lvm_lv_params_set_property(lvp, "skip_zero",
&prop_value) == -1) {
goto error;
}
}
}
if (!(lv = lvm_lv_create(lvp))) {
goto error;
}
return (PyObject *)_create_py_lv(self, lv);
error:
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
}
}
if (!(lvobj->lv = lvm_lv_create(lvp))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
lvobj->parent_vgobj = self;
Py_INCREF(lvobj->parent_vgobj);
return (PyObject *)lvobj;
}
static PyObject *_liblvm_lvm_vg_create_lv_thin(vgobject *self, PyObject *args)
@ -1075,7 +1078,7 @@ static PyObject *_liblvm_lvm_vg_create_lv_thin(vgobject *self, PyObject *args)
const char *pool_name;
const char *lv_name;
unsigned long long size = 0;
lvobject *lvobj;
lv_t lv;
lv_create_params_t lvp = NULL;
VG_VALID(self);
@ -1083,28 +1086,17 @@ static PyObject *_liblvm_lvm_vg_create_lv_thin(vgobject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "ssK", &pool_name, &lv_name, &size))
return NULL;
if (!(lvobj = PyObject_New(lvobject, &_LibLVMlvType)))
return NULL;
/* Initialize the parent ptr in case lv create fails and we dealloc lvobj */
lvobj->parent_vgobj = NULL;
if (!(lvp = lvm_lv_params_create_thin(self->vg, pool_name, lv_name,size))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
if (!(lvobj->lv = lvm_lv_create(lvp))) {
if (!(lv = lvm_lv_create(lvp))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
lvobj->parent_vgobj = self;
Py_INCREF(lvobj->parent_vgobj);
return (PyObject *)lvobj;
return (PyObject *)_create_py_lv(self, lv);
}
static void liblvm_lv_dealloc(lvobject *self)
@ -1157,7 +1149,6 @@ typedef pv_t (*pv_fetch_by_N)(vg_t vg, const char *id);
static PyObject *_liblvm_lvm_lv_from_N(vgobject *self, PyObject *arg, lv_fetch_by_N method)
{
const char *id;
lvobject *lvobj;
lv_t lv = NULL;
VG_VALID(self);
@ -1170,15 +1161,7 @@ static PyObject *_liblvm_lvm_lv_from_N(vgobject *self, PyObject *arg, lv_fetch_b
return NULL;
}
if (!(lvobj = PyObject_New(lvobject, &_LibLVMlvType)))
return NULL;
lvobj->parent_vgobj = self;
Py_INCREF(lvobj->parent_vgobj);
lvobj->lv = lv;
return (PyObject *)lvobj;
return (PyObject *)_create_py_lv(self, lv);
}
static PyObject *_liblvm_lvm_lv_from_name(vgobject *self, PyObject *arg)
@ -1243,11 +1226,11 @@ static void _liblvm_pv_dealloc(pvobject *self)
#define LV_VALID(lvobject) \
do { \
VG_VALID(lvobject->parent_vgobj); \
if (!lvobject->lv) { \
if (!lvobject || !lvobject->lv) { \
PyErr_SetString(PyExc_UnboundLocalError, "LV object invalid"); \
return NULL; \
} \
}\
VG_VALID(lvobject->parent_vgobj); \
} while (0)
static PyObject *_liblvm_lvm_lv_get_attr(lvobject *self)
@ -1510,7 +1493,7 @@ static PyObject *_liblvm_lvm_lv_snapshot(lvobject *self, PyObject *args)
{
const char *snap_name;
unsigned long long size = 0;
lvobject *lvobj;
lv_t lv;
lv_create_params_t lvp = NULL;
LV_VALID(self);
@ -1518,43 +1501,33 @@ static PyObject *_liblvm_lvm_lv_snapshot(lvobject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s|K", &snap_name, &size))
return NULL;
if (!(lvobj = PyObject_New(lvobject, &_LibLVMlvType)))
return NULL;
lvobj->parent_vgobj = NULL;
if (!(lvp = lvm_lv_params_create_snapshot(self->lv, snap_name, size))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
if (!(lvobj->lv = lvm_lv_create(lvp))) {
if (!(lv = lvm_lv_create(lvp))) {
PyErr_SetObject(_LibLVMError, _liblvm_get_last_error());
Py_DECREF(lvobj);
return NULL;
}
lvobj->parent_vgobj = self->parent_vgobj;
Py_INCREF(lvobj->parent_vgobj);
return (PyObject *)lvobj;
return (PyObject *)_create_py_lv(self->parent_vgobj, lv);
}
/* PV Methods */
#define PV_VALID(pvobject) \
do { \
if (!pvobject || !pvobject->pv) { \
PyErr_SetString(PyExc_UnboundLocalError, "PV object invalid"); \
return NULL; \
} \
if (pvobject->parent_vgobj) { \
VG_VALID(pvobject->parent_vgobj); \
} \
if (pvobject->parent_pvslistobj) { \
PVSLIST_VALID(pvobject->parent_pvslistobj); \
} \
if (!pvobject->pv) { \
PyErr_SetString(PyExc_UnboundLocalError, "PV object invalid"); \
return NULL; \
} \
} while (0)
static PyObject *_liblvm_lvm_pv_get_name(pvobject *self)
@ -1673,7 +1646,14 @@ static PyObject *_liblvm_lvm_pv_list_pvsegs(pvobject *self)
* No way to close/destroy an lvseg, just need to make sure parents are
* still good
*/
#define LVSEG_VALID(lvsegobject) LV_VALID(lvsegobject->parent_lvobj)
#define LVSEG_VALID(lvsegobject) \
do { \
if ( !lvsegobject || !lvsegobject->parent_lvobj ) { \
PyErr_SetString(PyExc_UnboundLocalError, "LV segment object invalid"); \
return NULL; \
} \
LV_VALID(lvsegobject->parent_lvobj); \
} while(0)
static void _liblvm_lvseg_dealloc(lvsegobject *self)
{
@ -1702,7 +1682,14 @@ static PyObject *_liblvm_lvm_lvseg_get_property(lvsegobject *self, PyObject *arg
* No way to close/destroy a pvseg, just need to make sure parents are
* still good
*/
#define PVSEG_VALID(pvsegobject) PV_VALID(pvsegobject->parent_pvobj)
#define PVSEG_VALID(pvsegobject) \
do { \
if (!pvsegobject || !pvsegobject->parent_pvobj) { \
PyErr_SetString(PyExc_UnboundLocalError, "PV segment object invalid"); \
return NULL; \
} \
PV_VALID(pvsegobject->parent_pvobj); \
} while(0)
static void _liblvm_pvseg_dealloc(pvsegobject *self)
{