]> granicus.if.org Git - postgresql/commitdiff
> I've worked with the Pl/Python code in the past and will see about removing
authorBruce Momjian <bruce@momjian.us>
Wed, 25 Jun 2003 01:18:58 +0000 (01:18 +0000)
committerBruce Momjian <bruce@momjian.us>
Wed, 25 Jun 2003 01:18:58 +0000 (01:18 +0000)
> 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

src/pl/plpython/plpython.c
src/pl/plpython/plpython_error.sql
src/pl/plpython/plpython_function.sql

index 47f85852781993097fe9c655b4e378f4422793a6..3bc5d73b33060c4be4a4448d4200ae7ea749a762 100644 (file)
@@ -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
  */
index 0cde4df9967f84e297f504f06544858aa9c2bc41..f1939eb8ffba46faeafa50113077b1f3f681b37b 100644 (file)
@@ -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');
index 2769e9de36feb08cfc029213146c2bbcd1cdd142..82a3c0c9598ef9af002ef06434bff49c472a4192 100644 (file)
@@ -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';
-