mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
plpython security and error handling fixes, from
Kevin Jacobs and Brad McLean.
This commit is contained in:
parent
b0df7a60f2
commit
1ca717f377
@ -1,19 +1,36 @@
|
||||
SELECT invalid_type_uncaught('rick');
|
||||
ERROR: plpython: Call of function `__plpython_procedure_invalid_type_uncaught_1175341' failed.
|
||||
NOTICE: plpython: in function __plpython_procedure_invalid_type_uncaught_49801:
|
||||
plpy.SPIError: Cache lookup for type `test' failed.
|
||||
SELECT invalid_type_caught('rick');
|
||||
NOTICE: ("Cache lookup for type `test' failed.",)
|
||||
invalid_type_caught
|
||||
---------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
NOTICE: plpython: in function __plpython_procedure_invalid_type_caught_49802:
|
||||
plpy.SPIError: Cache lookup for type `test' failed.
|
||||
SELECT invalid_type_reraised('rick');
|
||||
ERROR: plpython: Call of function `__plpython_procedure_invalid_type_reraised_1175343' failed.
|
||||
plpy.Error: ("Cache lookup for type `test' failed.",)
|
||||
NOTICE: plpython: in function __plpython_procedure_invalid_type_reraised_49803:
|
||||
plpy.SPIError: Cache lookup for type `test' failed.
|
||||
SELECT valid_type('rick');
|
||||
valid_type
|
||||
------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT read_file('/etc/passwd');
|
||||
ERROR: plpython: Call of function `__plpython_procedure_read_file_49809' failed.
|
||||
exceptions.IOError: can't open files in restricted mode
|
||||
SELECT write_file('/tmp/plpython','This is very bad');
|
||||
ERROR: plpython: Call of function `__plpython_procedure_write_file_49810' failed.
|
||||
exceptions.IOError: can't open files in restricted mode
|
||||
SELECT getpid();
|
||||
ERROR: plpython: Call of function `__plpython_procedure_getpid_49811' failed.
|
||||
exceptions.AttributeError: getpid
|
||||
SELECT uname();
|
||||
ERROR: plpython: Call of function `__plpython_procedure_uname_49812' failed.
|
||||
exceptions.AttributeError: uname
|
||||
SELECT sys_exit();
|
||||
ERROR: plpython: Call of function `__plpython_procedure_sys_exit_49813' failed.
|
||||
exceptions.AttributeError: exit
|
||||
SELECT sys_argv();
|
||||
sys_argv
|
||||
----------------
|
||||
['RESTRICTED']
|
||||
(1 row)
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.12 2001/11/05 17:46:39 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.13 2001/11/16 18:04:31 tgl Exp $
|
||||
*
|
||||
*********************************************************************
|
||||
*/
|
||||
@ -188,6 +188,10 @@ static void PLy_init_interp(void);
|
||||
static void PLy_init_safe_interp(void);
|
||||
static void PLy_init_plpy(void);
|
||||
|
||||
/* Helper functions used during initialization */
|
||||
static int populate_methods(PyObject *klass, PyMethodDef *methods);
|
||||
static PyObject *build_tuple(char* string_list[], int len);
|
||||
|
||||
/* error handler. collects the current Python exception, if any,
|
||||
* and appends it to the error and sends it to elog
|
||||
*/
|
||||
@ -199,6 +203,10 @@ static void
|
||||
PLy_exception_set(PyObject *, const char *,...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
/* Get the innermost python procedure called from the backend.
|
||||
*/
|
||||
static char *PLy_procedure_name(PLyProcedure *);
|
||||
|
||||
/* some utility functions
|
||||
*/
|
||||
static void *PLy_malloc(size_t);
|
||||
@ -240,6 +248,10 @@ static void PLy_input_datum_func2(PLyDatumToOb *, Form_pg_type);
|
||||
static void PLy_output_tuple_funcs(PLyTypeInfo *, TupleDesc);
|
||||
static void PLy_input_tuple_funcs(PLyTypeInfo *, TupleDesc);
|
||||
|
||||
/* RExec methods
|
||||
*/
|
||||
static PyObject *PLy_r_open(PyObject *self, PyObject* args);
|
||||
|
||||
/* conversion functions
|
||||
*/
|
||||
static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc);
|
||||
@ -255,6 +267,11 @@ static PyObject *PLyString_FromString(const char *);
|
||||
static int PLy_first_call = 1;
|
||||
static volatile int PLy_call_level = 0;
|
||||
|
||||
/*
|
||||
* Last function called by postgres backend
|
||||
*/
|
||||
static PLyProcedure *PLy_last_procedure = NULL;
|
||||
|
||||
/* this gets modified in plpython_call_handler and PLy_elog.
|
||||
* test it any old where, but do NOT modify it anywhere except
|
||||
* those two functions
|
||||
@ -265,35 +282,60 @@ static PyObject *PLy_interp_globals = NULL;
|
||||
static PyObject *PLy_interp_safe = NULL;
|
||||
static PyObject *PLy_interp_safe_globals = NULL;
|
||||
static PyObject *PLy_importable_modules = NULL;
|
||||
static PyObject *PLy_ok_posix_names = NULL;
|
||||
static PyObject *PLy_ok_sys_names = NULL;
|
||||
static PyObject *PLy_procedure_cache = NULL;
|
||||
|
||||
char *PLy_importable_modules_list[] = {
|
||||
static char *PLy_importable_modules_list[] = {
|
||||
"array",
|
||||
"bisect",
|
||||
"binascii",
|
||||
"calendar",
|
||||
"cmath",
|
||||
"codecs",
|
||||
"errno",
|
||||
"marshal",
|
||||
"math",
|
||||
"md5",
|
||||
"mpz",
|
||||
"operator",
|
||||
"pcre",
|
||||
"pickle",
|
||||
"random",
|
||||
"re",
|
||||
"regex",
|
||||
"sre",
|
||||
"sha",
|
||||
"string",
|
||||
"StringIO",
|
||||
"struct",
|
||||
"time",
|
||||
"whrandom",
|
||||
"zlib"
|
||||
};
|
||||
|
||||
static char *PLy_ok_posix_names_list[] = {
|
||||
/* None for now */
|
||||
};
|
||||
|
||||
static char *PLy_ok_sys_names_list[] = {
|
||||
"byteeorder",
|
||||
"copyright",
|
||||
"getdefaultencoding",
|
||||
"getrefcount",
|
||||
"hexrevision",
|
||||
"maxint",
|
||||
"maxunicode",
|
||||
"platform",
|
||||
"version",
|
||||
"version_info"
|
||||
};
|
||||
|
||||
/* Python exceptions
|
||||
*/
|
||||
PyObject *PLy_exc_error = NULL;
|
||||
PyObject *PLy_exc_fatal = NULL;
|
||||
PyObject *PLy_exc_spi_error = NULL;
|
||||
static PyObject *PLy_exc_error = NULL;
|
||||
static PyObject *PLy_exc_fatal = NULL;
|
||||
static PyObject *PLy_exc_spi_error = NULL;
|
||||
|
||||
/* some globals for the python module
|
||||
*/
|
||||
@ -334,7 +376,6 @@ perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
|
||||
fmgr_info_cxt(functionId, finfo, TopMemoryContext);
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
plpython_call_handler(PG_FUNCTION_ARGS)
|
||||
{
|
||||
@ -366,8 +407,10 @@ plpython_call_handler(PG_FUNCTION_ARGS)
|
||||
}
|
||||
else
|
||||
PLy_restart_in_progress += 1;
|
||||
if (proc)
|
||||
if (proc)
|
||||
{
|
||||
Py_DECREF(proc->me);
|
||||
}
|
||||
RERAISE_EXC();
|
||||
}
|
||||
|
||||
@ -805,7 +848,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
|
||||
if (plrv == NULL)
|
||||
{
|
||||
elog(FATAL, "Aiieee, PLy_procedure_call returned NULL");
|
||||
#if 0
|
||||
#ifdef NOT_USED
|
||||
if (!PLy_restart_in_progress)
|
||||
PLy_elog(ERROR, "plpython: Function \"%s\" failed.", proc->proname);
|
||||
|
||||
@ -853,11 +896,15 @@ PyObject *
|
||||
PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs)
|
||||
{
|
||||
PyObject *rv;
|
||||
PLyProcedure *current;
|
||||
|
||||
enter();
|
||||
|
||||
current = PLy_last_procedure;
|
||||
PLy_last_procedure = proc;
|
||||
PyDict_SetItemString(proc->globals, kargs, vargs);
|
||||
rv = PyObject_CallFunction(proc->reval, "O", proc->code);
|
||||
PLy_last_procedure = current;
|
||||
|
||||
if ((rv == NULL) || (PyErr_Occurred()))
|
||||
{
|
||||
@ -1150,12 +1197,6 @@ PLy_procedure_compile(PLyProcedure * proc, const char *src)
|
||||
if ((proc->interp == NULL) || (PyErr_Occurred()))
|
||||
PLy_elog(ERROR, "Unable to create rexec.RExec instance");
|
||||
|
||||
/*
|
||||
* tweak the list of permitted modules
|
||||
*/
|
||||
PyObject_SetAttrString(proc->interp, "ok_builtin_modules",
|
||||
PLy_importable_modules);
|
||||
|
||||
proc->reval = PyObject_GetAttrString(proc->interp, "r_eval");
|
||||
if ((proc->reval == NULL) || (PyErr_Occurred()))
|
||||
PLy_elog(ERROR, "Unable to get method `r_eval' from rexec.RExec");
|
||||
@ -1632,9 +1673,12 @@ static PyObject *PLy_plan_status(PyObject *, PyObject *);
|
||||
static PyObject *PLy_result_new(void);
|
||||
static void PLy_result_dealloc(PyObject *);
|
||||
static PyObject *PLy_result_getattr(PyObject *, char *);
|
||||
#ifdef NOT_USED
|
||||
/* Appear to be unused */
|
||||
static PyObject *PLy_result_fetch(PyObject *, PyObject *);
|
||||
static PyObject *PLy_result_nrows(PyObject *, PyObject *);
|
||||
static PyObject *PLy_result_status(PyObject *, PyObject *);
|
||||
#endif
|
||||
static int PLy_result_length(PyObject *);
|
||||
static PyObject *PLy_result_item(PyObject *, int);
|
||||
static PyObject *PLy_result_slice(PyObject *, int, int);
|
||||
@ -1650,7 +1694,7 @@ static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, int);
|
||||
static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int);
|
||||
|
||||
|
||||
PyTypeObject PLy_PlanType = {
|
||||
static PyTypeObject PLy_PlanType = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0, /* ob_size */
|
||||
"PLyPlan", /* tp_name */
|
||||
@ -1679,13 +1723,13 @@ PyTypeObject PLy_PlanType = {
|
||||
PLy_plan_doc, /* tp_doc */
|
||||
};
|
||||
|
||||
PyMethodDef PLy_plan_methods[] = {
|
||||
static PyMethodDef PLy_plan_methods[] = {
|
||||
{"status", (PyCFunction) PLy_plan_status, METH_VARARGS, NULL},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
PySequenceMethods PLy_result_as_sequence = {
|
||||
static PySequenceMethods PLy_result_as_sequence = {
|
||||
(inquiry) PLy_result_length, /* sq_length */
|
||||
(binaryfunc) 0, /* sq_concat */
|
||||
(intargfunc) 0, /* sq_repeat */
|
||||
@ -1695,7 +1739,7 @@ PySequenceMethods PLy_result_as_sequence = {
|
||||
(intintobjargproc) PLy_result_ass_slice, /* sq_ass_slice */
|
||||
};
|
||||
|
||||
PyTypeObject PLy_ResultType = {
|
||||
static PyTypeObject PLy_ResultType = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0, /* ob_size */
|
||||
"PLyResult", /* tp_name */
|
||||
@ -1723,14 +1767,15 @@ PyTypeObject PLy_ResultType = {
|
||||
0, /* tp_xxx4 */
|
||||
PLy_result_doc, /* tp_doc */
|
||||
};
|
||||
|
||||
PyMethodDef PLy_result_methods[] = {
|
||||
#ifdef NOT_USED
|
||||
/* Appear to be unused */
|
||||
static PyMethodDef PLy_result_methods[] = {
|
||||
{"fetch", (PyCFunction) PLy_result_fetch, METH_VARARGS, NULL,},
|
||||
{"nrows", (PyCFunction) PLy_result_nrows, METH_VARARGS, NULL},
|
||||
{"status", (PyCFunction) PLy_result_status, METH_VARARGS, NULL},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static PyMethodDef PLy_methods[] = {
|
||||
/*
|
||||
@ -1833,7 +1878,7 @@ PLy_plan_status(PyObject * self, PyObject * args)
|
||||
/* result object methods
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
PyObject *
|
||||
PLy_result_new(void)
|
||||
{
|
||||
PLyResultObject *ob;
|
||||
@ -1853,7 +1898,7 @@ PLy_result_new(void)
|
||||
return (PyObject *) ob;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
PLy_result_dealloc(PyObject * arg)
|
||||
{
|
||||
PLyResultObject *ob = (PLyResultObject *) arg;
|
||||
@ -1867,19 +1912,20 @@ PLy_result_dealloc(PyObject * arg)
|
||||
PyMem_DEL(ob);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyObject *
|
||||
PLy_result_getattr(PyObject * self, char *attr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
#ifdef NOT_USED
|
||||
/* Appear to be unused */
|
||||
PyObject *
|
||||
PLy_result_fetch(PyObject * self, PyObject * args)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyObject *
|
||||
PLy_result_nrows(PyObject * self, PyObject * args)
|
||||
{
|
||||
PLyResultObject *ob = (PLyResultObject *) self;
|
||||
@ -1888,7 +1934,7 @@ PLy_result_nrows(PyObject * self, PyObject * args)
|
||||
return ob->nrows;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyObject *
|
||||
PLy_result_status(PyObject * self, PyObject * args)
|
||||
{
|
||||
PLyResultObject *ob = (PLyResultObject *) self;
|
||||
@ -1896,7 +1942,7 @@ PLy_result_status(PyObject * self, PyObject * args)
|
||||
Py_INCREF(ob->status);
|
||||
return ob->status;
|
||||
}
|
||||
|
||||
#endif
|
||||
int
|
||||
PLy_result_length(PyObject * arg)
|
||||
{
|
||||
@ -1991,7 +2037,8 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
|
||||
if (!PyErr_Occurred())
|
||||
PyErr_SetString(PLy_exc_spi_error,
|
||||
"Unknown error in PLy_spi_prepare.");
|
||||
return NULL;
|
||||
PLy_elog(NOTICE,"in function %s:",PLy_procedure_name(PLy_last_procedure));
|
||||
RERAISE_EXC();
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
@ -2097,7 +2144,7 @@ PLy_spi_execute(PyObject * self, PyObject * args)
|
||||
|
||||
enter();
|
||||
|
||||
#if 0
|
||||
#ifdef NOT_USED
|
||||
|
||||
/*
|
||||
* there should - hahaha - be an python exception set so just return
|
||||
@ -2187,7 +2234,8 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit)
|
||||
if (!PyErr_Occurred())
|
||||
PyErr_SetString(PLy_exc_error,
|
||||
"Unknown error in PLy_spi_execute_plan");
|
||||
return NULL;
|
||||
PLy_elog(NOTICE,"in function %s:",PLy_procedure_name(PLy_last_procedure));
|
||||
RERAISE_EXC();
|
||||
}
|
||||
|
||||
if (nargs)
|
||||
@ -2249,16 +2297,15 @@ PLy_spi_execute_query(char *query, int limit)
|
||||
if (TRAP_EXC())
|
||||
{
|
||||
RESTORE_EXC();
|
||||
|
||||
if ((!PLy_restart_in_progress) && (!PyErr_Occurred()))
|
||||
PyErr_SetString(PLy_exc_spi_error,
|
||||
"Unknown error in PLy_spi_execute_query.");
|
||||
return NULL;
|
||||
PLy_elog(NOTICE,"in function %s:",PLy_procedure_name(PLy_last_procedure));
|
||||
RERAISE_EXC();
|
||||
}
|
||||
|
||||
rv = SPI_exec(query, limit);
|
||||
RESTORE_EXC();
|
||||
|
||||
if (rv < 0)
|
||||
{
|
||||
PLy_exception_set(PLy_exc_spi_error,
|
||||
@ -2311,7 +2358,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
|
||||
"Unknown error in PLy_spi_execute_fetch_result");
|
||||
Py_DECREF(result);
|
||||
PLy_typeinfo_dealloc(&args);
|
||||
return NULL;
|
||||
RERAISE_EXC();
|
||||
}
|
||||
|
||||
if (rows)
|
||||
@ -2450,13 +2497,33 @@ PLy_init_plpy(void)
|
||||
elog(ERROR, "Unable to init plpy.");
|
||||
}
|
||||
|
||||
/*
|
||||
* New RExec methods
|
||||
*/
|
||||
|
||||
PyObject*
|
||||
PLy_r_open(PyObject *self, PyObject* args)
|
||||
{
|
||||
PyErr_SetString(PyExc_IOError, "can't open files in restricted mode");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef PLy_r_exec_methods[] = {
|
||||
{"r_open", (PyCFunction)PLy_r_open, METH_VARARGS, NULL},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* Init new RExec
|
||||
*/
|
||||
|
||||
void
|
||||
PLy_init_safe_interp(void)
|
||||
{
|
||||
PyObject *rmod;
|
||||
PyObject *rmod, *rexec, *rexec_dict;
|
||||
char *rname = "rexec";
|
||||
int i,
|
||||
imax;
|
||||
int len;
|
||||
|
||||
enter();
|
||||
|
||||
@ -2467,19 +2534,93 @@ PLy_init_safe_interp(void)
|
||||
PyDict_SetItemString(PLy_interp_globals, rname, rmod);
|
||||
PLy_interp_safe = rmod;
|
||||
|
||||
imax = sizeof(PLy_importable_modules_list) / sizeof(char *);
|
||||
PLy_importable_modules = PyTuple_New(imax);
|
||||
for (i = 0; i < imax; i++)
|
||||
{
|
||||
PyObject *m = PyString_FromString(PLy_importable_modules_list[i]);
|
||||
len = sizeof(PLy_importable_modules_list) / sizeof(char *);
|
||||
PLy_importable_modules = build_tuple(PLy_importable_modules_list, len);
|
||||
|
||||
PyTuple_SetItem(PLy_importable_modules, i, m);
|
||||
}
|
||||
len = sizeof(PLy_ok_posix_names_list) / sizeof(char *);
|
||||
PLy_ok_posix_names = build_tuple(PLy_ok_posix_names_list, len);
|
||||
|
||||
len = sizeof(PLy_ok_sys_names_list) / sizeof(char *);
|
||||
PLy_ok_sys_names = build_tuple(PLy_ok_sys_names_list, len);
|
||||
|
||||
PLy_interp_safe_globals = PyDict_New();
|
||||
if (PLy_interp_safe_globals == NULL)
|
||||
PLy_elog(ERROR, "Unable to create shared global dictionary.");
|
||||
|
||||
/*
|
||||
* get an rexec.RExec class
|
||||
*/
|
||||
rexec = PyDict_GetItemString(PyModule_GetDict(rmod), "RExec");
|
||||
|
||||
if (rexec == NULL || !PyClass_Check(rexec))
|
||||
PLy_elog(ERROR, "Unable to get RExec object.");
|
||||
|
||||
|
||||
rexec_dict = ((PyClassObject*)rexec)->cl_dict;
|
||||
|
||||
/*
|
||||
* tweak the list of permitted modules, posix and sys functions
|
||||
*/
|
||||
PyDict_SetItemString(rexec_dict, "ok_builtin_modules", PLy_importable_modules);
|
||||
PyDict_SetItemString(rexec_dict, "ok_posix_names", PLy_ok_posix_names);
|
||||
PyDict_SetItemString(rexec_dict, "ok_sys_names", PLy_ok_sys_names);
|
||||
|
||||
/*
|
||||
* change the r_open behavior
|
||||
*/
|
||||
if( populate_methods(rexec, PLy_r_exec_methods) )
|
||||
PLy_elog(ERROR, "Failed to update RExec methods.");
|
||||
}
|
||||
|
||||
/* Helper function to build tuples from string lists */
|
||||
static
|
||||
PyObject *build_tuple(char* string_list[], int len)
|
||||
{
|
||||
PyObject *tup = PyTuple_New(len);
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
PyObject *m = PyString_FromString(string_list[i]);
|
||||
|
||||
PyTuple_SetItem(tup, i, m);
|
||||
}
|
||||
return tup;
|
||||
}
|
||||
|
||||
/* Helper function for populating a class with method wrappers. */
|
||||
static int
|
||||
populate_methods(PyObject *klass, PyMethodDef *methods)
|
||||
{
|
||||
if (!klass || !methods)
|
||||
return 0;
|
||||
|
||||
for ( ; methods->ml_name; ++methods) {
|
||||
|
||||
/* get a wrapper for the built-in function */
|
||||
PyObject *func = PyCFunction_New(methods, NULL);
|
||||
PyObject *meth;
|
||||
int status;
|
||||
|
||||
if (!func)
|
||||
return -1;
|
||||
|
||||
/* turn the function into an unbound method */
|
||||
if (!(meth = PyMethod_New(func, NULL, klass))) {
|
||||
Py_DECREF(func);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add method to dictionary */
|
||||
status = PyDict_SetItemString( ((PyClassObject*)klass)->cl_dict,
|
||||
methods->ml_name, meth);
|
||||
Py_DECREF(meth);
|
||||
Py_DECREF(func);
|
||||
|
||||
/* stop now if an error occurred, otherwise do the next method */
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2566,7 +2707,7 @@ PLy_log(volatile int level, PyObject * self, PyObject * args)
|
||||
* hideously.
|
||||
*/
|
||||
elog(FATAL, "plpython: Aiieee, elog threw an unknown exception!");
|
||||
return NULL;
|
||||
RERAISE_EXC();
|
||||
}
|
||||
|
||||
elog(level, sv);
|
||||
@ -2584,6 +2725,18 @@ PLy_log(volatile int level, PyObject * self, PyObject * args)
|
||||
}
|
||||
|
||||
|
||||
/* Get the last procedure name called by the backend ( the innermost,
|
||||
* If a plpython procedure call calls the backend and the backend calls
|
||||
* another plpython procedure )
|
||||
*/
|
||||
|
||||
char *PLy_procedure_name(PLyProcedure *proc)
|
||||
{
|
||||
if ( proc == NULL )
|
||||
return "<unknown procedure>";
|
||||
return proc->proname;
|
||||
}
|
||||
|
||||
/* output a python traceback/exception via the postgresql elog
|
||||
* function. not pretty.
|
||||
*/
|
||||
|
@ -7,3 +7,11 @@ SELECT invalid_type_uncaught('rick');
|
||||
SELECT invalid_type_caught('rick');
|
||||
SELECT invalid_type_reraised('rick');
|
||||
SELECT valid_type('rick');
|
||||
|
||||
-- Security sandbox tests
|
||||
SELECT read_file('/etc/passwd');
|
||||
SELECT write_file('/tmp/plpython','This is very bad');
|
||||
SELECT getpid();
|
||||
SELECT uname();
|
||||
SELECT sys_exit();
|
||||
SELECT sys_argv();
|
||||
|
@ -257,6 +257,12 @@ if len(rv):
|
||||
return None
|
||||
'
|
||||
LANGUAGE 'plpython';
|
||||
/* Flat out syntax error
|
||||
*/
|
||||
CREATE FUNCTION sql_syntax_error() RETURNS text
|
||||
AS
|
||||
'plpy.execute("syntax error")'
|
||||
LANGUAGE 'plpython';
|
||||
|
||||
/* check the handling of uncaught python exceptions
|
||||
*/
|
||||
@ -287,5 +293,36 @@ return seq
|
||||
'
|
||||
LANGUAGE 'plpython';
|
||||
|
||||
CREATE OR REPLACE FUNCTION read_file(text) RETURNS text AS '
|
||||
return open(args[0]).read()
|
||||
' LANGUAGE 'plpython';
|
||||
|
||||
CREATE OR REPLACE FUNCTION write_file(text,text) RETURNS text AS '
|
||||
open(args[0],"w").write(args[1])
|
||||
' LANGUAGE 'plpython';
|
||||
|
||||
CREATE OR REPLACE FUNCTION getpid() RETURNS int4 AS '
|
||||
import os
|
||||
return os.getpid()
|
||||
' LANGUAGE 'plpython';
|
||||
|
||||
CREATE OR REPLACE FUNCTION uname() RETURNS int4 AS '
|
||||
import os
|
||||
return os.uname()
|
||||
' LANGUAGE 'plpython';
|
||||
|
||||
CREATE OR REPLACE FUNCTION sys_exit() RETURNS text AS '
|
||||
import sys
|
||||
return sys.exit()
|
||||
' LANGUAGE 'plpython';
|
||||
|
||||
CREATE OR REPLACE FUNCTION sys_argv() RETURNS text AS '
|
||||
import sys
|
||||
return str(sys.argv)
|
||||
' LANGUAGE 'plpython';
|
||||
|
||||
CREATE OR REPLACE FUNCTION sys_version() RETURNS text AS '
|
||||
import sys
|
||||
return str(sys.version)
|
||||
' LANGUAGE 'plpython';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user