Commit afb17d91 authored by Bruce Momjian's avatar Bruce Momjian

> 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
parent b24a0293
......@@ -29,7 +29,7 @@
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.33 2003/06/11 18:33:39 tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.34 2003/06/25 01:18:58 momjian Exp $
*
*********************************************************************
*/
......@@ -61,6 +61,8 @@
#include "utils/syscache.h"
#include <Python.h>
#include <compile.h>
#include <eval.h>
#include "plpython.h"
/* convert Postgresql Datum or tuple into a PyObject.
......@@ -135,8 +137,6 @@ typedef struct PLyProcedure
* tuple type */
PLyTypeInfo args[FUNC_MAX_ARGS];
int nargs;
PyObject *interp; /* restricted interpreter instance */
PyObject *reval; /* interpreter return */
PyObject *code; /* compiled procedure code */
PyObject *statics; /* data saved across calls, local scope */
PyObject *globals; /* data saved across calls, global score */
......@@ -186,13 +186,8 @@ PG_FUNCTION_INFO_V1(plpython_call_handler);
*/
static void PLy_init_all(void);
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
*/
......@@ -249,10 +244,6 @@ static void PLy_input_datum_func2(PLyDatumToOb *, Oid, 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);
......@@ -280,58 +271,9 @@ static PLyProcedure *PLy_last_procedure = NULL;
static volatile int PLy_restart_in_progress = 0;
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;
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
*/
static PyObject *PLy_exc_error = NULL;
......@@ -904,7 +846,7 @@ PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs)
current = PLy_last_procedure;
PLy_last_procedure = proc;
PyDict_SetItemString(proc->globals, kargs, vargs);
rv = PyObject_CallFunction(proc->reval, "O", proc->code);
rv = PyEval_EvalCode( (PyCodeObject*)proc->code, proc->globals, proc->globals);
PLy_last_procedure = current;
if ((rv == NULL) || (PyErr_Occurred()))
......@@ -1084,7 +1026,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
for (i = 0; i < FUNC_MAX_ARGS; i++)
PLy_typeinfo_init(&proc->args[i]);
proc->nargs = 0;
proc->code = proc->interp = proc->reval = proc->statics = NULL;
proc->code = proc->statics = NULL;
proc->globals = proc->me = NULL;
SAVE_EXC();
......@@ -1189,45 +1131,12 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
void
PLy_procedure_compile(PLyProcedure * proc, const char *src)
{
PyObject *module,
*crv = NULL;
PyObject *crv = NULL;
char *msrc;
enter();
/*
* get an instance of rexec.RExec for the function
*/
proc->interp = PyObject_CallMethod(PLy_interp_safe, "RExec", NULL);
if ((proc->interp == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to create rexec.RExec instance");
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");
/*
* add a __main__ module to the function's interpreter
*/
module = PyObject_CallMethod(proc->interp, "add_module", "s", "__main__");
if ((module == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to get module `__main__' from rexec.RExec");
/*
* add plpy module to the interpreters main dictionary
*/
proc->globals = PyModule_GetDict(module);
if ((proc->globals == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to get `__main__.__dict__' from rexec.RExec");
/*
* why the hell won't r_import or r_exec('import plpy') work?
*/
module = PyDict_GetItemString(PLy_interp_globals, "plpy");
if ((module == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to get `plpy'");
Py_INCREF(module);
PyDict_SetItemString(proc->globals, "plpy", module);
proc->globals = PyDict_Copy(PLy_interp_globals);
/*
* SD is private preserved data between calls GD is global data shared
......@@ -1235,13 +1144,12 @@ PLy_procedure_compile(PLyProcedure * proc, const char *src)
*/
proc->statics = PyDict_New();
PyDict_SetItemString(proc->globals, "SD", proc->statics);
PyDict_SetItemString(proc->globals, "GD", PLy_interp_safe_globals);
/*
* insert the function code into the interpreter
*/
msrc = PLy_procedure_munge_source(proc->pyname, src);
crv = PyObject_CallMethod(proc->interp, "r_exec", "s", msrc);
crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL);
free(msrc);
if ((crv != NULL) && (!PyErr_Occurred()))
......@@ -1319,8 +1227,6 @@ PLy_procedure_delete(PLyProcedure * proc)
enter();
Py_XDECREF(proc->code);
Py_XDECREF(proc->interp);
Py_XDECREF(proc->reval);
Py_XDECREF(proc->statics);
Py_XDECREF(proc->globals);
Py_XDECREF(proc->me);
......@@ -2418,7 +2324,6 @@ PLy_init_all(void)
Py_Initialize();
PLy_init_interp();
PLy_init_plpy();
PLy_init_safe_interp();
if (PyErr_Occurred())
PLy_elog(FATAL, "Untrapped error in initialization.");
PLy_procedure_cache = PyDict_New();
......@@ -2442,6 +2347,8 @@ PLy_init_interp(void)
PLy_elog(ERROR, "Unable to import '__main__' module.");
Py_INCREF(mainmod);
PLy_interp_globals = PyModule_GetDict(mainmod);
PLy_interp_safe_globals = PyDict_New();
PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
Py_DECREF(mainmod);
if ((PLy_interp_globals == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to initialize globals.");
......@@ -2485,139 +2392,6 @@ 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,
*rexec,
*rexec_dict;
char *rname = "rexec";
int len;
enter();
rmod = PyImport_ImportModuleEx(rname, PLy_interp_globals,
PLy_interp_globals, Py_None);
if ((rmod == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to import %s.", rname);
PyDict_SetItemString(PLy_interp_globals, rname, rmod);
PLy_interp_safe = rmod;
len = sizeof(PLy_importable_modules_list) / sizeof(char *);
PLy_importable_modules = build_tuple(PLy_importable_modules_list, len);
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;
}
/* the python interface to the elog function
* don't confuse these with PLy_elog
*/
......
......@@ -9,9 +9,5 @@ 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();
SELECT write_file('/tmp/plpython','Only trusted users should be able to do this!');
SELECT read_file('/tmp/plpython');
......@@ -34,7 +34,7 @@ return SD["call"]
CREATE FUNCTION import_fail() returns text
AS
'try:
import socket
import foosocket
except Exception, ex:
plpy.notice("import socket failed -- %s" % str(ex))
return "failed as expected"
......@@ -304,30 +304,5 @@ CREATE OR REPLACE FUNCTION read_file(text) RETURNS text AS '
CREATE OR REPLACE FUNCTION write_file(text,text) RETURNS text AS '
open(args[0],"w").write(args[1])
return "Wrote to file: %s" % args[0]
' 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';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment