aur/0001-python-venv-stuff.patch
Jan Alexander Steffens (heftig) e76f43c982 Initial commit
2017-01-06 12:46:52 +01:00

302 lines
11 KiB
Diff

From b709d18d6a4585fde234fedd7c72970276cc41a2 Mon Sep 17 00:00:00 2001
From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com>
Date: Fri, 6 Jan 2017 12:11:35 +0100
Subject: [PATCH] python venv stuff
---
runtime/Server.cpp | 225 ++++++++++++-----------------------------------------
runtime/Server.h | 6 +-
2 files changed, 55 insertions(+), 176 deletions(-)
diff --git a/runtime/Server.cpp b/runtime/Server.cpp
index e5be20569faaf6c4..430ea32e8c7c55f3 100644
--- a/runtime/Server.cpp
+++ b/runtime/Server.cpp
@@ -22,183 +22,80 @@
// App headers
#include "Server.h"
-static void add_to_path(QString &python_path, QString path, bool prepend=false)
-{
- if (!python_path.contains(path))
- {
- if (!prepend)
- {
- if (!python_path.isEmpty() && !python_path.endsWith(";"))
- python_path.append(";");
-
- python_path.append(path);
- }
- else
- {
- if (!python_path.isEmpty() && !python_path.startsWith(";"))
- python_path.prepend(";");
-
- python_path.prepend(path);
- }
- }
-}
-
Server::Server(quint16 port)
{
// Appserver port
m_port = port;
- m_wcAppName = NULL;
// Initialise Python
- Py_NoSiteFlag=1;
- Py_DontWriteBytecodeFlag=1;
+ Py_DontWriteBytecodeFlag = 1;
+
+ // Get the application directory
+ QString app_dir = qApp->applicationDirPath();
+ QByteArray path_env = qgetenv("PATH");
+
+ // Build (and canonicalise) the virtual environment path
+#ifdef Q_OS_MAC
+ QFileInfo venvBinPath(app_dir + "/../Resources/venv/bin");
+#elif defined(Q_OS_WIN)
+ QFileInfo venvBinPath(app_dir + "/../venv");
+#else
+ QFileInfo venvBinPath(app_dir + "/../venv/bin");
+#endif
+ QString bin_path = venvBinPath.canonicalFilePath();
+
+ // Prepend the bin directory to the path
+ if (!path_env.isEmpty() && !path_env.startsWith(";"))
+ path_env.prepend(";");
+ path_env.prepend(bin_path.toLocal8Bit());
+
+ qputenv("PATH", path_env);
+
+ // Ensure the python symlink is not resolved
+ bin_path.append("/python");
// Python3 requires conversion of char * to wchar_t *, so...
#ifdef PYTHON2
- Py_SetProgramName(PGA_APP_NAME.toUtf8().data());
+ QByteArray appName = bin_path.toLocal8Bit();
+ m_pyAppName = new char[strlen(appName.data()) + 1];
+ strcpy(m_pyAppName, appName.data());
+ qDebug() << "Python interpreter: " << QString::fromLocal8Bit(m_pyAppName);
#else
- char *appName = PGA_APP_NAME.toUtf8().data();
- const size_t cSize = strlen(appName)+1;
- m_wcAppName = new wchar_t[cSize];
- mbstowcs (m_wcAppName, appName, cSize);
- Py_SetProgramName(m_wcAppName);
+ std::wstring appName = bin_path.toStdWString();
+ m_pyAppName = new wchar_t[wcslen(appName.c_str()) + 1];
+ wcscpy(m_pyAppName, appName.c_str());
+ qDebug() << "Python interpreter: " << QString::fromWCharArray(m_pyAppName);
#endif
-
- // Setup the search path
- QSettings settings;
- QString python_path = settings.value("PythonPath").toString();
-
- // Get the application directory
- QString app_dir = qApp->applicationDirPath(),
- path_env = qgetenv("PATH"),
- pythonHome;
- QStringList path_list;
- int i;
-
-#ifdef Q_OS_MAC
- // In the case we're running in a release appbundle, we need to ensure the
- // bundled virtual env is included in the Python path. We include it at the
- // end, so expert users can override the path, but we do not save it, because
- // if users move the app bundle, we'll end up with dead entries
-
- // Build (and canonicalise) the virtual environment path
- QFileInfo venvBinPath(app_dir + "/../Resources/venv/bin");
- QFileInfo venvLibPath(app_dir + "/../Resources/venv/lib/python");
- QFileInfo venvDynLibPath(app_dir + "/../Resources/venv/lib/python/lib-dynload");
- QFileInfo venvSitePackagesPath(app_dir + "/../Resources/venv/lib/python/site-packages");
- QFileInfo venvPath(app_dir + "/../Resources/venv");
-
- // Prepend the bin directory to the path
- add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
- // Append the path, if it's not already there
- add_to_path(python_path, venvLibPath.canonicalFilePath());
- add_to_path(python_path, venvDynLibPath.canonicalFilePath());
- add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
- add_to_path(pythonHome, venvPath.canonicalFilePath());
-#elif defined(Q_OS_WIN)
-
- // In the case we're running in a release application, we need to ensure the
- // bundled virtual env is included in the Python path. We include it at the
- // end, so expert users can override the path, but we do not save it.
-
- // Build (and canonicalise) the virtual environment path
- QFileInfo venvBinPath(app_dir + "/../venv");
- QFileInfo venvLibPath(app_dir + "/../venv/Lib");
- QFileInfo venvDLLsPath(app_dir + "/../venv/DLLs");
- QFileInfo venvSitePackagesPath(app_dir + "/../venv/Lib/site-packages");
- QFileInfo venvPath(app_dir + "/../venv");
-
- // Prepend the bin directory to the path
- add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
- // Append paths, if they're not already there
- add_to_path(python_path, venvLibPath.canonicalFilePath());
- add_to_path(python_path, venvDLLsPath.canonicalFilePath());
- add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
- add_to_path(pythonHome, venvPath.canonicalFilePath());
-#else
- // Build (and canonicalise) the virtual environment path
- QFileInfo venvBinPath(app_dir + "/../venv/bin");
- QFileInfo venvLibPath(app_dir + "/../venv/lib/python");
- QFileInfo venvDynLibPath(app_dir + "/../venv/lib/python/lib-dynload");
- QFileInfo venvSitePackagesPath(app_dir + "/../venv/lib/python/site-packages");
- QFileInfo venvPath(app_dir + "/../venv");
-
- // Prepend the bin directory to the path
- add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
- // Append the path, if it's not already there
- add_to_path(python_path, venvLibPath.canonicalFilePath());
- add_to_path(python_path, venvDynLibPath.canonicalFilePath());
- add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
- add_to_path(pythonHome, venvPath.canonicalFilePath());
-#endif
-
- qputenv("PATH", path_env.toUtf8().data());
-
- if (python_path.length() > 0)
- {
- // Split the path setting into individual entries
- path_list = python_path.split(";", QString::SkipEmptyParts);
- python_path = QString();
-
- // Add new additional path elements
- for (i = path_list.size() - 1; i >= 0 ; --i)
- {
- python_path.append(path_list.at(i));
- if (i > 0)
- {
-#if defined(Q_OS_WIN)
- python_path.append(";");
-#else
- python_path.append(":");
-#endif
- }
- }
- qputenv("PYTHONPATH", python_path.toUtf8().data());
- }
-
- qDebug() << "Python path: " << python_path
- << "\nPython Home: " << pythonHome;
- if (!pythonHome.isEmpty())
- {
-#ifdef PYTHON2
- Py_SetPythonHome(pythonHome.toUtf8().data());
-#else
- char *python_home = pythonHome.toUtf8().data();
- const size_t cSize = strlen(python_home) + 1;
- wchar_t* wcPythonHome = new wchar_t[cSize];
- mbstowcs (wcPythonHome, python_home, cSize);
-
- Py_SetPythonHome(wcPythonHome);
-#endif
- }
+ Py_SetProgramName(m_pyAppName);
Py_Initialize();
- // Get the current path
- PyObject* sysPath = PySys_GetObject((char*)"path");
+ /*
+ * Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
+ * versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
+ * which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
+ * Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
+ */
+ PySys_SetArgvEx(1, &m_pyAppName, 0);
- // Add new additional path elements
- for (i = path_list.size() - 1; i >= 0 ; --i)
- {
+ PyObject *sys_path = PyObject_Repr(PySys_GetObject("path"));
#ifdef PYTHON2
- PyList_Append(sysPath, PyString_FromString(path_list.at(i).toUtf8().data()));
+ qDebug() << "Python path: " << QString::fromLocal8Bit(PyString_AsString(sys_path));
#else
-#if PY_MINOR_VERSION > 2
- PyList_Append(sysPath, PyUnicode_DecodeFSDefault(path_list.at(i).toUtf8().data()));
-#else
- PyList_Append(sysPath, PyBytes_FromString(path_list.at(i).toUtf8().data()));
+ PyObject *sys_path_bytes = PyUnicode_AsEncodedString(sys_path, "utf8", "replace");
+ qDebug() << "Python path: " << QString::fromUtf8(PyBytes_AsString(sys_path_bytes));
+ Py_DECREF(sys_path_bytes);
#endif
-#endif
- }
+ Py_DECREF(sys_path);
}
Server::~Server()
{
- if (m_wcAppName)
- delete m_wcAppName;
-
// Shutdown Python
Py_Finalize();
+
+ if (m_pyAppName)
+ delete [] m_pyAppName;
}
bool Server::Init()
@@ -258,33 +155,11 @@ void Server::run()
// Run the app!
#ifdef PYTHON2
- /*
- * Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
- * versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
- * which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
- * Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
- */
- char* n_argv[] = { m_appfile.toUtf8().data() };
- PySys_SetArgv(1, n_argv);
-
PyObject* PyFileObject = PyFile_FromString(m_appfile.toUtf8().data(), (char *)"r");
int ret = PyRun_SimpleFile(PyFile_AsFile(PyFileObject), m_appfile.toUtf8().data());
if (ret != 0)
setError(tr("Failed to launch the application server, server thread exiting."));
#else
- /*
- * Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
- * versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
- * which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
- * Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
- */
- char *appName = m_appfile.toUtf8().data();
- const size_t cSize = strlen(appName)+1;
- wchar_t* wcAppName = new wchar_t[cSize];
- mbstowcs (wcAppName, appName, cSize);
- wchar_t* n_argv[] = { wcAppName };
- PySys_SetArgv(1, n_argv);
-
int fd = fileno(cp);
PyObject* PyFileObject = PyFile_FromFd(fd, m_appfile.toUtf8().data(), (char *)"r", -1, NULL, NULL,NULL,1);
if (PyRun_SimpleFile(fdopen(PyObject_AsFileDescriptor(PyFileObject),"r"), m_appfile.toUtf8().data()) != 0)
diff --git a/runtime/Server.h b/runtime/Server.h
index 8df8503bb553eca4..5cc51f3d8b3e1f9b 100644
--- a/runtime/Server.h
+++ b/runtime/Server.h
@@ -39,7 +39,11 @@ private:
QString m_error;
quint16 m_port;
- wchar_t *m_wcAppName;
+#ifdef PYTHON2
+ char *m_pyAppName;
+#else
+ wchar_t *m_pyAppName;
+#endif
};
#endif // SERVER_H
--
2.11.0