On Wed, Nov 12, 2008 at 12:34:16PM +0100, Bram Moolenaar wrote: > > James - > > > Vim's python interface calls PySys_SetArgv with an argv[0] that doesn't > > resolve to a filename. This causes Python to prepend sys.path with an > > empty string which, due to Python's use of relative imports, allows the > > possibility to run arbitrary code on the user's system if a file in > > Vim's working directory matches the name of a python module a > > Python-using vim script tries to import. > > > > This should be fixed by Python 2.6 as it uses absolute imports by > > default, but I have not been able to test it. The attached patch fixes > > the problem in Vim by removing any empty strings from sys.path. > > I have now applied and tried this patch. It does not really work as > expected for me. Apparently the empty string in argv[0] is interpreted > as the current directory.
argv[0] is used to seed the value that is prepended to sys.path. You can take a look at what PySys_SetArgv does at http://svn.python.org/view/python/branches/release25-maint/Python/sysmodule.c?rev=54836&view=markup What it boils down to in the simple case is checking for the existence of a path separator in argv0. If that doesn't exist, then a PyString is created from argv0 with size 0 and sys.path is prepended with that -- empty string used for the first element of sys.path. > My first entry in sys.path is then the directory above the current > directory. The filter you added in the patch doesn't change anything. This is incorrect. In Vim's current code, PySys_SetArgv is called with an argv that is simply an empty string (and a terminating NULL sentinel). This causes sys.path's first element to be the empty string, thus causing any Python import statements to use Vim's current working directory as the first location to check for the requested module. The filter specifically removes any elements in sys.path that evaluate to false (i.e., the empty string). Using the attached print_sys.path.diff, the following is printed when I start Vim (the sys.path before and after my suggested filter() command): ['', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages'] ['/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages'] You can also test it with the simple pytest.c that I've attached by specifying different arguments as the first element of the argv passed to PySys_SetArgv. $ gcc -o pytest $(python-config --cflags) $(python-config --ldflags) pytest.c $ ./pytest '' ['', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages'] ['/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages'] $ ./pytest '/must>not&exist/bogusbinary' ['/must>not&exist', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages'] ['/must>not&exist', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages'] > For me it does work if I use: > > static char *(argv[2]) = {"/must>not&exist/ls", NULL}; > > The first entry in path is then "/must>not&exist", which we can filter > out with: > > PyRun_SimpleString("import sys; sys.path = filter(lambda x: x != > '/must>not&exist', sys.path)"); This is just extra work for no gain. -- James GPG Key: 1024D/61326D40 2003-09-02 James Vega <[EMAIL PROTECTED]>
#include <Python.h> #include <stdio.h> int main(int argc, char **argv) { int newargc = 1; char *newargv[2] = {"", NULL}; if (2 != argc) { fprintf(stderr, "Usage: %s <argv path>\n", argv[0]); return 1; } newargv[0] = argv[1]; Py_Initialize(); PySys_SetArgv(newargc, newargv); PyRun_SimpleString("import sys; print sys.path"); PyRun_SimpleString("sys.path = filter(None, sys.path)"); PyRun_SimpleString("print sys.path"); return 0; }
--- a/src/if_python.c +++ b/src/if_python.c @@ -530,6 +530,9 @@ if (PythonMod_Init()) goto fail; + PyRun_SimpleString("import sys; print sys.path"); + PyRun_SimpleString("sys.path = filter(None, sys.path)"); + PyRun_SimpleString("print sys.path"); /* the first python thread is vim's, release the lock */ Python_SaveThread();
signature.asc
Description: Digital signature