Skip to content

Commit afb17d9

Browse files
committed
> I've worked with the Pl/Python code in the past and will see about removing
> rexec and making it an untrusted language. Last time I looked, it didn't > look particularly difficult. I've set aside some time next week, so stay > tuned. Attached is a patch that removes all of the RExec code from plpython from the current PostgreSQL CVS. In addition, plpython needs to be changed to an untrusted language in createlang. Please let me know if there are any problems. Kevin Jacobs
1 parent b24a029 commit afb17d9

File tree

3 files changed

+14
-269
lines changed

3 files changed

+14
-269
lines changed

src/pl/plpython/plpython.c

Lines changed: 10 additions & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
3030
*
3131
* IDENTIFICATION
32-
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.33 2003/06/11 18:33:39 tgl Exp $
32+
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.34 2003/06/25 01:18:58 momjian Exp $
3333
*
3434
*********************************************************************
3535
*/
@@ -61,6 +61,8 @@
6161
#include "utils/syscache.h"
6262

6363
#include <Python.h>
64+
#include <compile.h>
65+
#include <eval.h>
6466
#include "plpython.h"
6567

6668
/* convert Postgresql Datum or tuple into a PyObject.
@@ -135,8 +137,6 @@ typedef struct PLyProcedure
135137
* tuple type */
136138
PLyTypeInfo args[FUNC_MAX_ARGS];
137139
int nargs;
138-
PyObject *interp; /* restricted interpreter instance */
139-
PyObject *reval; /* interpreter return */
140140
PyObject *code; /* compiled procedure code */
141141
PyObject *statics; /* data saved across calls, local scope */
142142
PyObject *globals; /* data saved across calls, global score */
@@ -186,13 +186,8 @@ PG_FUNCTION_INFO_V1(plpython_call_handler);
186186
*/
187187
static void PLy_init_all(void);
188188
static void PLy_init_interp(void);
189-
static void PLy_init_safe_interp(void);
190189
static void PLy_init_plpy(void);
191190

192-
/* Helper functions used during initialization */
193-
static int populate_methods(PyObject * klass, PyMethodDef * methods);
194-
static PyObject *build_tuple(char *string_list[], int len);
195-
196191
/* error handler. collects the current Python exception, if any,
197192
* and appends it to the error and sends it to elog
198193
*/
@@ -249,10 +244,6 @@ static void PLy_input_datum_func2(PLyDatumToOb *, Oid, Form_pg_type);
249244
static void PLy_output_tuple_funcs(PLyTypeInfo *, TupleDesc);
250245
static void PLy_input_tuple_funcs(PLyTypeInfo *, TupleDesc);
251246

252-
/* RExec methods
253-
*/
254-
static PyObject *PLy_r_open(PyObject * self, PyObject * args);
255-
256247
/* conversion functions
257248
*/
258249
static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc);
@@ -280,58 +271,9 @@ static PLyProcedure *PLy_last_procedure = NULL;
280271
static volatile int PLy_restart_in_progress = 0;
281272

282273
static PyObject *PLy_interp_globals = NULL;
283-
static PyObject *PLy_interp_safe = NULL;
284274
static PyObject *PLy_interp_safe_globals = NULL;
285-
static PyObject *PLy_importable_modules = NULL;
286-
static PyObject *PLy_ok_posix_names = NULL;
287-
static PyObject *PLy_ok_sys_names = NULL;
288275
static PyObject *PLy_procedure_cache = NULL;
289276

290-
static char *PLy_importable_modules_list[] = {
291-
"array",
292-
"bisect",
293-
"binascii",
294-
"calendar",
295-
"cmath",
296-
"codecs",
297-
"errno",
298-
"marshal",
299-
"math",
300-
"md5",
301-
"mpz",
302-
"operator",
303-
"pcre",
304-
"pickle",
305-
"random",
306-
"re",
307-
"regex",
308-
"sre",
309-
"sha",
310-
"string",
311-
"StringIO",
312-
"struct",
313-
"time",
314-
"whrandom",
315-
"zlib"
316-
};
317-
318-
static char *PLy_ok_posix_names_list[] = {
319-
/* None for now */
320-
};
321-
322-
static char *PLy_ok_sys_names_list[] = {
323-
"byteeorder",
324-
"copyright",
325-
"getdefaultencoding",
326-
"getrefcount",
327-
"hexrevision",
328-
"maxint",
329-
"maxunicode",
330-
"platform",
331-
"version",
332-
"version_info"
333-
};
334-
335277
/* Python exceptions
336278
*/
337279
static PyObject *PLy_exc_error = NULL;
@@ -904,7 +846,7 @@ PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs)
904846
current = PLy_last_procedure;
905847
PLy_last_procedure = proc;
906848
PyDict_SetItemString(proc->globals, kargs, vargs);
907-
rv = PyObject_CallFunction(proc->reval, "O", proc->code);
849+
rv = PyEval_EvalCode( (PyCodeObject*)proc->code, proc->globals, proc->globals);
908850
PLy_last_procedure = current;
909851

910852
if ((rv == NULL) || (PyErr_Occurred()))
@@ -1084,7 +1026,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
10841026
for (i = 0; i < FUNC_MAX_ARGS; i++)
10851027
PLy_typeinfo_init(&proc->args[i]);
10861028
proc->nargs = 0;
1087-
proc->code = proc->interp = proc->reval = proc->statics = NULL;
1029+
proc->code = proc->statics = NULL;
10881030
proc->globals = proc->me = NULL;
10891031

10901032
SAVE_EXC();
@@ -1189,59 +1131,25 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
11891131
void
11901132
PLy_procedure_compile(PLyProcedure * proc, const char *src)
11911133
{
1192-
PyObject *module,
1193-
*crv = NULL;
1134+
PyObject *crv = NULL;
11941135
char *msrc;
11951136

11961137
enter();
11971138

1198-
/*
1199-
* get an instance of rexec.RExec for the function
1200-
*/
1201-
proc->interp = PyObject_CallMethod(PLy_interp_safe, "RExec", NULL);
1202-
if ((proc->interp == NULL) || (PyErr_Occurred()))
1203-
PLy_elog(ERROR, "Unable to create rexec.RExec instance");
1204-
1205-
proc->reval = PyObject_GetAttrString(proc->interp, "r_eval");
1206-
if ((proc->reval == NULL) || (PyErr_Occurred()))
1207-
PLy_elog(ERROR, "Unable to get method `r_eval' from rexec.RExec");
1208-
1209-
/*
1210-
* add a __main__ module to the function's interpreter
1211-
*/
1212-
module = PyObject_CallMethod(proc->interp, "add_module", "s", "__main__");
1213-
if ((module == NULL) || (PyErr_Occurred()))
1214-
PLy_elog(ERROR, "Unable to get module `__main__' from rexec.RExec");
1215-
1216-
/*
1217-
* add plpy module to the interpreters main dictionary
1218-
*/
1219-
proc->globals = PyModule_GetDict(module);
1220-
if ((proc->globals == NULL) || (PyErr_Occurred()))
1221-
PLy_elog(ERROR, "Unable to get `__main__.__dict__' from rexec.RExec");
1222-
1223-
/*
1224-
* why the hell won't r_import or r_exec('import plpy') work?
1225-
*/
1226-
module = PyDict_GetItemString(PLy_interp_globals, "plpy");
1227-
if ((module == NULL) || (PyErr_Occurred()))
1228-
PLy_elog(ERROR, "Unable to get `plpy'");
1229-
Py_INCREF(module);
1230-
PyDict_SetItemString(proc->globals, "plpy", module);
1139+
proc->globals = PyDict_Copy(PLy_interp_globals);
12311140

12321141
/*
12331142
* SD is private preserved data between calls GD is global data shared
12341143
* by all functions
12351144
*/
12361145
proc->statics = PyDict_New();
12371146
PyDict_SetItemString(proc->globals, "SD", proc->statics);
1238-
PyDict_SetItemString(proc->globals, "GD", PLy_interp_safe_globals);
12391147

12401148
/*
12411149
* insert the function code into the interpreter
12421150
*/
12431151
msrc = PLy_procedure_munge_source(proc->pyname, src);
1244-
crv = PyObject_CallMethod(proc->interp, "r_exec", "s", msrc);
1152+
crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL);
12451153
free(msrc);
12461154

12471155
if ((crv != NULL) && (!PyErr_Occurred()))
@@ -1319,8 +1227,6 @@ PLy_procedure_delete(PLyProcedure * proc)
13191227
enter();
13201228

13211229
Py_XDECREF(proc->code);
1322-
Py_XDECREF(proc->interp);
1323-
Py_XDECREF(proc->reval);
13241230
Py_XDECREF(proc->statics);
13251231
Py_XDECREF(proc->globals);
13261232
Py_XDECREF(proc->me);
@@ -2418,7 +2324,6 @@ PLy_init_all(void)
24182324
Py_Initialize();
24192325
PLy_init_interp();
24202326
PLy_init_plpy();
2421-
PLy_init_safe_interp();
24222327
if (PyErr_Occurred())
24232328
PLy_elog(FATAL, "Untrapped error in initialization.");
24242329
PLy_procedure_cache = PyDict_New();
@@ -2442,6 +2347,8 @@ PLy_init_interp(void)
24422347
PLy_elog(ERROR, "Unable to import '__main__' module.");
24432348
Py_INCREF(mainmod);
24442349
PLy_interp_globals = PyModule_GetDict(mainmod);
2350+
PLy_interp_safe_globals = PyDict_New();
2351+
PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
24452352
Py_DECREF(mainmod);
24462353
if ((PLy_interp_globals == NULL) || (PyErr_Occurred()))
24472354
PLy_elog(ERROR, "Unable to initialize globals.");
@@ -2485,139 +2392,6 @@ PLy_init_plpy(void)
24852392
elog(ERROR, "Unable to init plpy.");
24862393
}
24872394

2488-
/*
2489-
* New RExec methods
2490-
*/
2491-
2492-
PyObject *
2493-
PLy_r_open(PyObject * self, PyObject * args)
2494-
{
2495-
PyErr_SetString(PyExc_IOError, "can't open files in restricted mode");
2496-
return NULL;
2497-
}
2498-
2499-
2500-
static PyMethodDef PLy_r_exec_methods[] = {
2501-
{"r_open", (PyCFunction) PLy_r_open, METH_VARARGS, NULL},
2502-
{NULL, NULL, 0, NULL}
2503-
};
2504-
2505-
/*
2506-
* Init new RExec
2507-
*/
2508-
2509-
void
2510-
PLy_init_safe_interp(void)
2511-
{
2512-
PyObject *rmod,
2513-
*rexec,
2514-
*rexec_dict;
2515-
char *rname = "rexec";
2516-
int len;
2517-
2518-
enter();
2519-
2520-
rmod = PyImport_ImportModuleEx(rname, PLy_interp_globals,
2521-
PLy_interp_globals, Py_None);
2522-
if ((rmod == NULL) || (PyErr_Occurred()))
2523-
PLy_elog(ERROR, "Unable to import %s.", rname);
2524-
PyDict_SetItemString(PLy_interp_globals, rname, rmod);
2525-
PLy_interp_safe = rmod;
2526-
2527-
len = sizeof(PLy_importable_modules_list) / sizeof(char *);
2528-
PLy_importable_modules = build_tuple(PLy_importable_modules_list, len);
2529-
2530-
len = sizeof(PLy_ok_posix_names_list) / sizeof(char *);
2531-
PLy_ok_posix_names = build_tuple(PLy_ok_posix_names_list, len);
2532-
2533-
len = sizeof(PLy_ok_sys_names_list) / sizeof(char *);
2534-
PLy_ok_sys_names = build_tuple(PLy_ok_sys_names_list, len);
2535-
2536-
PLy_interp_safe_globals = PyDict_New();
2537-
if (PLy_interp_safe_globals == NULL)
2538-
PLy_elog(ERROR, "Unable to create shared global dictionary.");
2539-
2540-
/*
2541-
* get an rexec.RExec class
2542-
*/
2543-
rexec = PyDict_GetItemString(PyModule_GetDict(rmod), "RExec");
2544-
2545-
if (rexec == NULL || !PyClass_Check(rexec))
2546-
PLy_elog(ERROR, "Unable to get RExec object.");
2547-
2548-
2549-
rexec_dict = ((PyClassObject *) rexec)->cl_dict;
2550-
2551-
/*
2552-
* tweak the list of permitted modules, posix and sys functions
2553-
*/
2554-
PyDict_SetItemString(rexec_dict, "ok_builtin_modules", PLy_importable_modules);
2555-
PyDict_SetItemString(rexec_dict, "ok_posix_names", PLy_ok_posix_names);
2556-
PyDict_SetItemString(rexec_dict, "ok_sys_names", PLy_ok_sys_names);
2557-
2558-
/*
2559-
* change the r_open behavior
2560-
*/
2561-
if (populate_methods(rexec, PLy_r_exec_methods))
2562-
PLy_elog(ERROR, "Failed to update RExec methods.");
2563-
}
2564-
2565-
/* Helper function to build tuples from string lists */
2566-
static
2567-
PyObject *
2568-
build_tuple(char *string_list[], int len)
2569-
{
2570-
PyObject *tup = PyTuple_New(len);
2571-
int i;
2572-
2573-
for (i = 0; i < len; i++)
2574-
{
2575-
PyObject *m = PyString_FromString(string_list[i]);
2576-
2577-
PyTuple_SetItem(tup, i, m);
2578-
}
2579-
return tup;
2580-
}
2581-
2582-
/* Helper function for populating a class with method wrappers. */
2583-
static int
2584-
populate_methods(PyObject * klass, PyMethodDef * methods)
2585-
{
2586-
if (!klass || !methods)
2587-
return 0;
2588-
2589-
for (; methods->ml_name; ++methods)
2590-
{
2591-
2592-
/* get a wrapper for the built-in function */
2593-
PyObject *func = PyCFunction_New(methods, NULL);
2594-
PyObject *meth;
2595-
int status;
2596-
2597-
if (!func)
2598-
return -1;
2599-
2600-
/* turn the function into an unbound method */
2601-
if (!(meth = PyMethod_New(func, NULL, klass)))
2602-
{
2603-
Py_DECREF(func);
2604-
return -1;
2605-
}
2606-
2607-
/* add method to dictionary */
2608-
status = PyDict_SetItemString(((PyClassObject *) klass)->cl_dict,
2609-
methods->ml_name, meth);
2610-
Py_DECREF(meth);
2611-
Py_DECREF(func);
2612-
2613-
/* stop now if an error occurred, otherwise do the next method */
2614-
if (status)
2615-
return status;
2616-
}
2617-
return 0;
2618-
}
2619-
2620-
26212395
/* the python interface to the elog function
26222396
* don't confuse these with PLy_elog
26232397
*/

src/pl/plpython/plpython_error.sql

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,5 @@ SELECT invalid_type_reraised('rick');
99
SELECT valid_type('rick');
1010

1111
-- Security sandbox tests
12-
SELECT read_file('/etc/passwd');
13-
SELECT write_file('/tmp/plpython','This is very bad');
14-
SELECT getpid();
15-
SELECT uname();
16-
SELECT sys_exit();
17-
SELECT sys_argv();
12+
SELECT write_file('/tmp/plpython','Only trusted users should be able to do this!');
13+
SELECT read_file('/tmp/plpython');

0 commit comments

Comments
 (0)