summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorNoam Cohen <noam@noam.me>2022-10-20 09:08:54 (GMT)
committerGitHub <noreply@github.com>2022-10-20 09:08:54 (GMT)
commita371a7e03e43e08cae70235a71904989c0f57a5e (patch)
tree40b9d4b13ec579ae370760e2dafd888e32f2b06f /Modules
parentc1e02d4e4e09dfc9d57c4d36eca1bbf312d4162d (diff)
downloadcpython-a371a7e03e43e08cae70235a71904989c0f57a5e.zip
cpython-a371a7e03e43e08cae70235a71904989c0f57a5e.tar.gz
cpython-a371a7e03e43e08cae70235a71904989c0f57a5e.tar.bz2
gh-95023: Added os.setns and os.unshare functions (#95046)
Added os.setns and os.unshare to easily switch between namespaces on Linux. Co-authored-by: Christian Heimes <christian@python.org> Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM> Co-authored-by: Victor Stinner <vstinner@python.org>
Diffstat (limited to 'Modules')
-rw-r--r--Modules/clinic/posixmodule.c.h151
-rw-r--r--Modules/posixmodule.c107
2 files changed, 257 insertions, 1 deletions
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index 31bd01d..1ad96ea 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -5211,6 +5211,147 @@ exit:
#endif /* (defined(__linux__) && defined(__NR_pidfd_open)) */
+#if defined(HAVE_SETNS)
+
+PyDoc_STRVAR(os_setns__doc__,
+"setns($module, /, fd, nstype=0)\n"
+"--\n"
+"\n"
+"Move the calling thread into different namespaces.\n"
+"\n"
+" fd\n"
+" A file descriptor to a namespace.\n"
+" nstype\n"
+" Type of namespace.");
+
+#define OS_SETNS_METHODDEF \
+ {"setns", _PyCFunction_CAST(os_setns), METH_FASTCALL|METH_KEYWORDS, os_setns__doc__},
+
+static PyObject *
+os_setns_impl(PyObject *module, int fd, int nstype);
+
+static PyObject *
+os_setns(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 2
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_item = { &_Py_ID(fd), &_Py_ID(nstype), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"fd", "nstype", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "setns",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
+ int fd;
+ int nstype = 0;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (!_PyLong_FileDescriptor_Converter(args[0], &fd)) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ nstype = _PyLong_AsInt(args[1]);
+ if (nstype == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+skip_optional_pos:
+ return_value = os_setns_impl(module, fd, nstype);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(HAVE_SETNS) */
+
+#if defined(HAVE_UNSHARE)
+
+PyDoc_STRVAR(os_unshare__doc__,
+"unshare($module, /, flags)\n"
+"--\n"
+"\n"
+"Disassociate parts of a process (or thread) execution context.\n"
+"\n"
+" flags\n"
+" Namespaces to be unshared.");
+
+#define OS_UNSHARE_METHODDEF \
+ {"unshare", _PyCFunction_CAST(os_unshare), METH_FASTCALL|METH_KEYWORDS, os_unshare__doc__},
+
+static PyObject *
+os_unshare_impl(PyObject *module, int flags);
+
+static PyObject *
+os_unshare(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_item = { &_Py_ID(flags), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"flags", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "unshare",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ int flags;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ flags = _PyLong_AsInt(args[0]);
+ if (flags == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = os_unshare_impl(module, flags);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(HAVE_UNSHARE) */
+
#if (defined(HAVE_READLINK) || defined(MS_WINDOWS))
PyDoc_STRVAR(os_readlink__doc__,
@@ -11085,6 +11226,14 @@ exit:
#define OS_PIDFD_OPEN_METHODDEF
#endif /* !defined(OS_PIDFD_OPEN_METHODDEF) */
+#ifndef OS_SETNS_METHODDEF
+ #define OS_SETNS_METHODDEF
+#endif /* !defined(OS_SETNS_METHODDEF) */
+
+#ifndef OS_UNSHARE_METHODDEF
+ #define OS_UNSHARE_METHODDEF
+#endif /* !defined(OS_UNSHARE_METHODDEF) */
+
#ifndef OS_READLINK_METHODDEF
#define OS_READLINK_METHODDEF
#endif /* !defined(OS_READLINK_METHODDEF) */
@@ -11368,4 +11517,4 @@ exit:
#ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF
#define OS_WAITSTATUS_TO_EXITCODE_METHODDEF
#endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */
-/*[clinic end generated code: output=471ab8f2ad3d46b0 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=90f5e6995114e5ca input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 39198cb..56ea319 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -8581,6 +8581,64 @@ os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
#endif
+#ifdef HAVE_SETNS
+/*[clinic input]
+os.setns
+ fd: fildes
+ A file descriptor to a namespace.
+ nstype: int = 0
+ Type of namespace.
+
+Move the calling thread into different namespaces.
+[clinic start generated code]*/
+
+static PyObject *
+os_setns_impl(PyObject *module, int fd, int nstype)
+/*[clinic end generated code: output=5dbd055bfb66ecd0 input=42787871226bf3ee]*/
+{
+ int res;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = setns(fd, nstype);
+ Py_END_ALLOW_THREADS
+
+ if (res != 0) {
+ return posix_error();
+ }
+
+ Py_RETURN_NONE;
+}
+#endif
+
+
+#ifdef HAVE_UNSHARE
+/*[clinic input]
+os.unshare
+ flags: int
+ Namespaces to be unshared.
+
+Disassociate parts of a process (or thread) execution context.
+[clinic start generated code]*/
+
+static PyObject *
+os_unshare_impl(PyObject *module, int flags)
+/*[clinic end generated code: output=1b3177906dd237ee input=9e065db3232b8b1b]*/
+{
+ int res;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = unshare(flags);
+ Py_END_ALLOW_THREADS
+
+ if (res != 0) {
+ return posix_error();
+ }
+
+ Py_RETURN_NONE;
+}
+#endif
+
+
#if defined(HAVE_READLINK) || defined(MS_WINDOWS)
/*[clinic input]
os.readlink
@@ -14945,6 +15003,8 @@ static PyMethodDef posix_methods[] = {
OS__ADD_DLL_DIRECTORY_METHODDEF
OS__REMOVE_DLL_DIRECTORY_METHODDEF
OS_WAITSTATUS_TO_EXITCODE_METHODDEF
+ OS_SETNS_METHODDEF
+ OS_UNSHARE_METHODDEF
{NULL, NULL} /* Sentinel */
};
@@ -15390,6 +15450,53 @@ all_ins(PyObject *m)
#ifdef SCHED_FX
if (PyModule_AddIntConstant(m, "SCHED_FX", SCHED_FSS)) return -1;
#endif
+
+/* constants for namespaces */
+#if defined(HAVE_SETNS) || defined(HAVE_UNSHARE)
+#ifdef CLONE_FS
+ if (PyModule_AddIntMacro(m, CLONE_FS)) return -1;
+#endif
+#ifdef CLONE_FILES
+ if (PyModule_AddIntMacro(m, CLONE_FILES)) return -1;
+#endif
+#ifdef CLONE_NEWNS
+ if (PyModule_AddIntMacro(m, CLONE_NEWNS)) return -1;
+#endif
+#ifdef CLONE_NEWCGROUP
+ if (PyModule_AddIntMacro(m, CLONE_NEWCGROUP)) return -1;
+#endif
+#ifdef CLONE_NEWUTS
+ if (PyModule_AddIntMacro(m, CLONE_NEWUTS)) return -1;
+#endif
+#ifdef CLONE_NEWIPC
+ if (PyModule_AddIntMacro(m, CLONE_NEWIPC)) return -1;
+#endif
+#ifdef CLONE_NEWUSER
+ if (PyModule_AddIntMacro(m, CLONE_NEWUSER)) return -1;
+#endif
+#ifdef CLONE_NEWPID
+ if (PyModule_AddIntMacro(m, CLONE_NEWPID)) return -1;
+#endif
+#ifdef CLONE_NEWNET
+ if (PyModule_AddIntMacro(m, CLONE_NEWNET)) return -1;
+#endif
+#ifdef CLONE_NEWTIME
+ if (PyModule_AddIntMacro(m, CLONE_NEWTIME)) return -1;
+#endif
+#ifdef CLONE_SYSVSEM
+ if (PyModule_AddIntMacro(m, CLONE_SYSVSEM)) return -1;
+#endif
+#ifdef CLONE_THREAD
+ if (PyModule_AddIntMacro(m, CLONE_THREAD)) return -1;
+#endif
+#ifdef CLONE_SIGHAND
+ if (PyModule_AddIntMacro(m, CLONE_SIGHAND)) return -1;
+#endif
+#ifdef CLONE_VM
+ if (PyModule_AddIntMacro(m, CLONE_VM)) return -1;
+#endif
+#endif
+
#endif
#ifdef USE_XATTRS