Restricting access to sensitive APIs with a permission model like Deno
Hello all, Supply chain attacks are becoming a pressing concern in software development due to the large number of dependencies and multiple attack vectors. Using third party modules (libraries, packages etc) is always a risk but the true potential of these attacks is now being weaponized. One way to deal with the risk is by limiting access to sensitive APIs like filesystem, shell, network and ffi so that packages which aren't explicitly granted permissions cannot use them, reducing their ability to do damage. For example, a yaml parser should not need to use ffi, network nor shell. A command line argument parser library should not use network, ffi nor filesystem. Deno, a runtime for Typescript contains an interesting implementation of a permissions model for APIs. I strongly think Python could benefit from such functionality and hacked together a quick experiment here: https://github.com/R9295/cpython Currently, it only prevents module imports in a very elementary manner but perhaps it can be of use to spark a discussion for an implementation. Looking forward to your thoughts, Aarnav
On Mon, 27 Feb 2023 at 02:32, python--- via Python-ideas <python-ideas@python.org> wrote:
Currently, it only prevents module imports in a very elementary manner but perhaps it can be of use to spark a discussion for an implementation.
It only restricts module imports? Then it's almost completely useless. Python code can easily bypass that sort of restriction. But I *really* don't feel like going through your code, over a thousand commits ahead of the main branch, to figure out what changes you've made. For a "quick experiment" this sure looks like an awful lot of changes. ChrisA
Could you elaborate on how Python code can easily bypass that sort of restriction? From my understanding, you can only do so with importlib by reading the raw source and evaluating it. In that case, I can just restrict importlib? Same with the open function which is from the io module which can also be restricted (and removed from builtins in that case). Here's a diff of my implementation and upstream's 3.11.0 tag. It's 17 commits with most being README changes. I hope this makes it more clear. https://github.com/python/cpython/compare/3.11...R9295:cpython:policy Regards, Aarnav
I think python's import system is modularized and extensible. You can write restrictions in your program to limit how modules access external code. I've also been using the RestrictedPython project from Zope foundation. It overs a way of creating a sandbox environment for python quite easily by leveraging python's extensible nature. On Sun, Feb 26, 2023, 8:58 PM python--- via Python-ideas < python-ideas@python.org> wrote:
Could you elaborate on how Python code can easily bypass that sort of restriction?
From my understanding, you can only do so with importlib by reading the raw source and evaluating it. In that case, I can just restrict importlib? Same with the open function which is from the io module which can also be restricted (and removed from builtins in that case).
Here's a diff of my implementation and upstream's 3.11.0 tag. It's 17 commits with most being README changes. I hope this makes it more clear. https://github.com/python/cpython/compare/3.11...R9295:cpython:policy
Regards, Aarnav _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NWQCBF... Code of Conduct: http://python.org/psf/codeofconduct/
On Mon, 27 Feb 2023 at 04:56, python--- via Python-ideas <python-ideas@python.org> wrote:
Could you elaborate on how Python code can easily bypass that sort of restriction?
From my understanding, you can only do so with importlib by reading the raw source and evaluating it. In that case, I can just restrict importlib? Same with the open function which is from the io module which can also be restricted (and removed from builtins in that case).
Here's a diff of my implementation and upstream's 3.11.0 tag. It's 17 commits with most being README changes. I hope this makes it more clear. https://github.com/python/cpython/compare/3.11...R9295:cpython:policy
Do you block access to the __import__ function? To sys.modules and the cache of already-imported modules? What about eval() and various ways of executing arbitrary code? How about object.__subclasses__()? ChrisA
I override the import mechanism in cpython, so yes, the __import__ function is also accounted for. The sys.modules was something I had not considered, that's a good point. I will have to look into it. I am not sure how arbitrary code execution will be able to use native APIs without importing them.
On Mon, 27 Feb 2023 at 06:02, python--- via Python-ideas <python-ideas@python.org> wrote:
I override the import mechanism in cpython, so yes, the __import__ function is also accounted for.
Okay, cool. (Like I said, I didn't feel like wading through >1000 commits to find out exactly what you'd changed.)
The sys.modules was something I had not considered, that's a good point. I will have to look into it.
Once something's been imported, it becomes VERY easy to access. Blocking sys.modules would make it a bit harder, but thanks to tricks like object.__subclasses__, it'll be a massive game of whack-a-mole.
I am not sure how arbitrary code execution will be able to use native APIs without importing them.
The question is whether there's a way for something to cause some other subsystem to import a module, thus bypassing the restrictions and making it available via tricks like I mentioned above. I don't know of any way off-hand, but I also know that there are a *lot* of ways to cause code to be called upon from elsewhere, so it would depend heavily on exactly what your boundaries are. Even if the boundary is something like "if this module is in the call stack, importing is disallowed", it would be possible to bypass it, for instance by spinning off a new thread to do the import. ChrisA
Thank you for the insight. I have some more work to do! I will share on this thread again when I've made further changes. If you have some time, I would be grateful if you could share a few test cases such as "bypass it by spinning off a new thread", or. object.__subclasses__. code is not necessary but just pointers. Thanks and regards, Aarnav
On Mon, 27 Feb 2023 at 08:33, python--- via Python-ideas <python-ideas@python.org> wrote:
Thank you for the insight. I have some more work to do! I will share on this thread again when I've made further changes.
If you have some time, I would be grateful if you could share a few test cases such as "bypass it by spinning off a new thread", or. object.__subclasses__. code is not necessary but just pointers.
The trouble with that is, I don't really want to build and run your Python just for the test, so all I can really do is talk theoretically. But if you can name any module that IS permitted to import code, I can attempt (on a vanilla Python) to trigger it to import something of my choice. It's worth noting, for instance, that sys.path and its friends can be manipulated to control what would be imported; a trusted module could potentially be tricked into importing anything at all. Python simply isn't designed for security boundaries. ChrisA
Have you looked at the diff? It's not "1000+" commits as you claim. It's 17 commits with most being README changes. The base is not the master branch but the 3.11.0 release. https://github.com/python/cpython/compare/3.11...R9295:cpython:policy I do not see why you cannot audit and run this (or atleast read the code) since it's required to have a meaningful discussion, the overriding happens before the module resolution itself so sys.path is irrelevant.
On Mon, 27 Feb 2023 at 20:58, python--- via Python-ideas <python-ideas@python.org> wrote:
Have you looked at the diff? It's not "1000+" commits as you claim. It's 17 commits with most being README changes. The base is not the master branch but the 3.11.0 release.
https://github.com/python/cpython/compare/3.11...R9295:cpython:policy
I do not see why you cannot audit and run this (or atleast read the code) since it's required to have a meaningful discussion, the overriding happens before the module resolution itself so sys.path is irrelevant.
Hmm, maybe it was showing up oddly on GitHub, but I wasn't able to see it as 17 commits - I was just seeing that you were some thousand-odd commits ahead of the main branch. Thanks for pointing this out; and while I do stand by my earlier assessment that a thousand commits *is* too much to audit, I may get a chance to review these actual changes at some point. ChrisA
On Mon, 27 Feb 2023 at 20:58, python--- via Python-ideas
The base is not the master branch but the 3.11.0 release.
Maybe you should rebase it on main? That will need to happen if it's to be usable, anyway, and it makes it far easier to review/discuss if you follow the normal process for (proposed) PRs. Paul
On Sun, Feb 26, 2023, 5:42 PM Chris Angelico <rosuav@gmail.com> wrote:
On Mon, 27 Feb 2023 at 08:33, python--- via Python-ideas <python-ideas@python.org> wrote:
Thank you for the insight. I have some more work to do! I will share on
this thread again when I've made further changes.
If you have some time, I would be grateful if you could share a few
test cases such as "bypass it by spinning off a new thread", or.
object.__subclasses__. code is not necessary but just pointers.
The trouble with that is, I don't really want to build and run your Python just for the test, so all I can really do is talk theoretically. But if you can name any module that IS permitted to import code, I can attempt (on a vanilla Python) to trigger it to import something of my choice.
It's worth noting, for instance, that sys.path and its friends can be manipulated to control what would be imported; a trusted module could potentially be tricked into importing anything at all.
Python simply isn't designed for security boundaries.
Trying to just application sandbox Python again? Python is not (and possibly cannot be) made a sufficient sandbox; and neither can other languages solve without breaking changes, too Things you can do, things you can't: - setcap a (virtualenv) bin/python - differentiate between code and data using the NX bit, *when a c extension (with nested functions,) is imported [1][2]. The NX bit doesn't work if you import a C extension. - Work with the ctypes module: import ctypes ctypes.cast(1, ctypes.py_object) - strip modules out of stdlib (and patch importlib) before compiling - "PEP 594 – Removing dead batteries from the standard library" https://peps.python.org/pep-0594/ - there were mailing list and probably also discourse discussions of how to allow customized builds of CPython with modules excluded. I'll keep looking for the link [1] https://groups.google.com/g/dev-python/c/67Et2KtpzG4 [2] https://en.wikipedia.org/wiki/Nested_function#No-execute_stacks (E.g. BinderHub and Dask will run [Python, conda-forge,] code in k8s and containers to sandbox / process-isolate it.) Is it possible to grant a WASM runtime - in a browser application sandbox (with IPC APIs (all running under one user)) - access to syscalls (WASI,) and have provide sufficient security assurances, even? Python does not yet (?) have browser-like sandboxing features. There have been various efforts and pycon presentations on sandboxing Python with Python; most of them retrospectives just.
On Mon, Feb 27, 2023, 8:12 AM Wes Turner <wes.turner@gmail.com> wrote:
On Sun, Feb 26, 2023, 5:42 PM Chris Angelico <rosuav@gmail.com> wrote:
On Mon, 27 Feb 2023 at 08:33, python--- via Python-ideas <python-ideas@python.org> wrote:
Thank you for the insight. I have some more work to do! I will share on
this thread again when I've made further changes.
If you have some time, I would be grateful if you could share a few
test cases such as "bypass it by spinning off a new thread", or.
object.__subclasses__. code is not necessary but just pointers.
The trouble with that is, I don't really want to build and run your Python just for the test, so all I can really do is talk theoretically. But if you can name any module that IS permitted to import code, I can attempt (on a vanilla Python) to trigger it to import something of my choice.
It's worth noting, for instance, that sys.path and its friends can be manipulated to control what would be imported; a trusted module could potentially be tricked into importing anything at all.
Python simply isn't designed for security boundaries.
Trying to just application sandbox Python again? Python is not (and possibly cannot be) made a sufficient sandbox; and neither can other languages solve without breaking changes, too
- https://www.google.com/search?q=python+sandbox+bypass+escape - https://www.google.com/search?q=container+sandbox+escape - https://hn.algolia.com/?q=python+sandbox - [Bypassing a Python sandbox by abusing code objects / Hacker News]( https://news.ycombinator.com/item?id=8280053 )
Things you can do, things you can't:
- setcap a (virtualenv) bin/python
- differentiate between code and data using the NX bit, *when a c extension (with nested functions,) is imported [1][2]. The NX bit doesn't work if you import a C extension.
- Work with the ctypes module: import ctypes ctypes.cast(1, ctypes.py_object)
- strip modules out of stdlib (and patch importlib) before compiling
- "PEP 594 – Removing dead batteries from the standard library" https://peps.python.org/pep-0594/
- there were mailing list and probably also discourse discussions of how to allow customized builds of CPython with modules excluded. I'll keep looking for the link
[1] https://groups.google.com/g/dev-python/c/67Et2KtpzG4
[2] https://en.wikipedia.org/wiki/Nested_function#No-execute_stacks
(E.g. BinderHub and Dask will run [Python, conda-forge,] code in k8s and containers to sandbox / process-isolate it.)
Is it possible to grant a WASM runtime - in a browser application sandbox (with IPC APIs (all running under one user)) - access to syscalls (WASI,) and have provide sufficient security assurances, even?
That is why opcodes have a cost with smart contracts; because of the Halting Problem and arbitrary code execution and no sockets and which other modules? Python does not yet (?) have browser-like sandboxing features.
- https://github.com/utoni/potd/blob/master/src/jail.c#L296 - https://www.google.com/search?q=wasm+sandbox+site%3Agithub.com +python - https://wiki.mozilla.org/Security/Sandbox - https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox.md - W3C IPC APIs: [Web Workers, Service Workers, ] - CSP Content Security Policy https://en.wikipedia.org/wiki/Content_Security_Policy#Complementary_measures - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-P... - "PEP 554 – Multiple Interpreters in the Stdlib / peps.python.org" https://peps.python.org/pep-0554/#interpreter-isolation - "PyPy’s sandboxing features — PyPy documentation" https://doc.pypy.org/en/latest/sandbox.html - https://github.com/vstinner/pysandbox - https://foss.heptapod.net/pypy/sandboxlib/-/blob/branch/default/sandboxlib/v...
There have been various efforts and pycon presentations on sandboxing Python with Python; most of them retrospectives just.
- HN search link above lists many sandboxing articles. - ( OT: [container-selinux, OpenShift SELinux MCS contexts and types, Kata containers / gVisor / Firecracker · Issue #6 · kai5263499/awesome-container-security · GitHub]( https://github.com/kai5263499/awesome-container-security/issues/6 ))
For such a thing to be useful, it will ultimately need to percolate up to users to understand what they are getting themselves into by using some application. Would this be correct in your view? Would permissions be attached to individual modules? Packages? Would they be declarative ahead of time, or be more of the more modern Android model of asking for permission as code executes? On Sun, 2023-02-26 at 01:21 +0000, python--- via Python-ideas wrote:
Hello all,
Supply chain attacks are becoming a pressing concern in software development due to the large number of dependencies and multiple attack vectors. Using third party modules (libraries, packages etc) is always a risk but the true potential of these attacks is now being weaponized. One way to deal with the risk is by limiting access to sensitive APIs like filesystem, shell, network and ffi so that packages which aren't explicitly granted permissions cannot use them, reducing their ability to do damage.
For example, a yaml parser should not need to use ffi, network nor shell. A command line argument parser library should not use network, ffi nor filesystem. Deno, a runtime for Typescript contains an interesting implementation of a permissions model for APIs.
I strongly think Python could benefit from such functionality and hacked together a quick experiment here: https://github.com/R9295/cpython Currently, it only prevents module imports in a very elementary manner but perhaps it can be of use to spark a discussion for an implementation.
Looking forward to your thoughts, Aarnav _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MZNP5Z... Code of Conduct: http://python.org/psf/codeofconduct/
With Python being a language heavily utilized in server and end-user applications, I would take a different approach for both. I have to admit I haven't thought much about the "normal user" in this case and focused primarily on developers. Perhaps developers shipping an application ship the code with a module policy? The way I imagine the implementation is that module restriction is recursive, so I only have to look at my top-level dependencies and not their sub-dependencies when wanting to restrict a module. Regarding the second part, I think restricting it to modules would be ideal. I also think the permissions should be like the Android model where an application can prompt you. Deno does it in an interesting manner where you can choose to be prompted, which makes sense when running an end-user application or you could reject any prompting and accept or deny the request automatically which makes sense in a server-side application. I hope this answers your questions. I am happy to elaborate if not.
On Mon, 27 Feb 2023 at 02:32, python--- via Python-ideas <python-ideas@python.org> wrote:
Supply chain attacks are becoming a pressing concern in software development due to the large number of dependencies and multiple attack vectors. Using third party modules (libraries, packages etc) is always a risk but the true potential of these attacks is now being weaponized. One way to deal with the risk is by limiting access to sensitive APIs like filesystem, shell, network and ffi so that packages which aren't explicitly granted permissions cannot use them, reducing their ability to do damage.
For example, a yaml parser should not need to use ffi, network nor shell. A command line argument parser library should not use network, ffi nor filesystem. Deno, a runtime for Typescript contains an interesting implementation of a permissions model for APIs.
Okay, so, looking at this freshly now that I can actually review and run the code (thanks for pointing out that I was using the wrong comparison base). Here's a basic POC using the example from your readme: ---- policy.json ---- { "socket": ["requests"] } ---- restricted.py ---- # I should be restricted and not allowed to import socket try: import socket except ImportError as e: print("Importing of socket blocked:", e) import sys socket = sys.modules["socket"] print("Hey look, sockets!", socket.socket()) ---- runme.py ---- # import sockets # do you have this? # import requests # or this? import restricted This correctly errors out. So, now to demonstrate how easy this is to break. The first and most obvious form of breakage is that, if the requests module is EVER imported (or sockets directly, which can be done inside runme), the module will exist inside sys.modules and can be used from anywhere. (And if you break that, then all kinds of things will break, including identity checks of sentinel objects, exception hierarchies, etc. We NEED that imported module commonality.) But here's the thing: if you stop ANY other module from importing sockets, that means that your code will break any time anything in the standard library calls on it. So this is basically going to be good ONLY for small and tightly controlled projects where you know exactly what's importing what - and if you already know that, you don't really need a policy. In fact, if your system works, so would something that just blocks the entire *process* from using sockets, because there's actually no viable boundary here. In general, that's the way to sandbox Python code. Do it at the process level, not the module level. You're doomed to fail otherwise. ChrisA ChrisA
I hope you are at least aware that over the years various multi-year attempts to create Python sandboxes ultimately failed to the point of being altogether abandoned. Python and Javascript differ fundamentally that Python runtime is intrinsically bound to I/O, like filesystem access - which is a thing that is isolated and "plugged-in by the environment" in Javascript. Besides that, the object model allows one to - sometimes not so easily, but always consistently - bypass any write-restrictions to variables and other memory states that would be used to restrict any access. Ultimately any sandboxing in Python has to be accomplished at OS level (like running everything in a container), at which point there is no granularity to restrict individual Python packages or modules anyway. On Sun, Feb 26, 2023 at 12:32 PM python--- via Python-ideas < python-ideas@python.org> wrote:
Hello all,
Supply chain attacks are becoming a pressing concern in software development due to the large number of dependencies and multiple attack vectors. Using third party modules (libraries, packages etc) is always a risk but the true potential of these attacks is now being weaponized. One way to deal with the risk is by limiting access to sensitive APIs like filesystem, shell, network and ffi so that packages which aren't explicitly granted permissions cannot use them, reducing their ability to do damage.
For example, a yaml parser should not need to use ffi, network nor shell. A command line argument parser library should not use network, ffi nor filesystem. Deno, a runtime for Typescript contains an interesting implementation of a permissions model for APIs.
I strongly think Python could benefit from such functionality and hacked together a quick experiment here: https://github.com/R9295/cpython Currently, it only prevents module imports in a very elementary manner but perhaps it can be of use to spark a discussion for an implementation.
Looking forward to your thoughts, Aarnav _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MZNP5Z... Code of Conduct: http://python.org/psf/codeofconduct/
Thank you for your insight.
I hope you are at least aware that over the years various multi-year attempts to create Python sandboxes ultimately failed to the point of being altogether abandoned.
Yes I am, I have looked at pysandbox and RestrictedPython and I believe my approach, albeit very early stage, differs from theirs.
Besides that, the object model allows one to - sometimes not so easily, but always consistently - bypass any write-restrictions to variables and other memory states that would be used to restrict any access.
If you have some time, could you provide me with an example or two? If I understand it correctly, only FFI would be able to do so, am I right? Regards, Aarnav
Hi Aarnav, You are right that supply chain attacks are a growing concern in software development, and limiting access to sensitive APIs can be a useful mitigation strategy. Python is no exception to this and could benefit from such functionality. Your experiment with cpython is interesting, and it is great that you are thinking about this issue and contributing to the conversation. I suggest that you continue to explore this idea and potentially reach out to the Python community to get feedback and suggestions. Implementing a permissions model for Python's APIs would require careful consideration and testing to ensure that it does not break existing code or introduce new vulnerabilities. It would also need to be well-documented and communicated to the community to ensure that developers are aware of the risks and how to use the new functionality properly. Overall, I think that your work on this issue is valuable, and I encourage you to continue exploring it and engaging with the Python community.
On Sun, Feb 26, 2023 at 7:31 AM python--- via Python-ideas < python-ideas@python.org> wrote:
Supply chain attacks are becoming a pressing concern in software development due to the large number of dependencies and multiple attack vectors. Using third party modules (libraries, packages etc) is always a risk but the true potential of these attacks is now being weaponized. One way to deal with the risk is by limiting access to sensitive APIs like filesystem, shell, network and ffi so that packages which aren't explicitly granted permissions cannot use them, reducing their ability to do damage.
I agree with the other commenters that creating a sandbox within a particular python process is going to be extremely difficult or impossible. But I commend you in trying to do work in this area. One way this could be implemented is by providing some primitives for sandboxing subprocesses. E.g. in the requirements file add an optional section for sandbox directives that will cause the import to be executed in a subprocess with a restricted set of OS-level permissions (e.g. no writing to the filesystem other than a particular socket for communicating with the parent process). An incremental and independently useful place to start on that might be adding sandboxing primitives to the subprocess and/or multiprocessing module. I have tried to do this manually on a linux web service using calls to Imagemagick and didn't see a way to do it aside from calling a `docker run` command. Is there a cross-platform way of doing this? I did a bit of googling and found some "experimental" libraries for the purpose, though nothing that wanted to call itself production-ready. (Gaol https://github.com/servo/gaol and Boxfort https://github.com/Snaipe/BoxFort) Presumably web browsers like Chrome have some prior art as well. Best wishes, Lucas Wiman
On Thu, 2 Mar 2023 at 06:30, Lucas Wiman <lucas.wiman@gmail.com> wrote:
One way this could be implemented is by providing some primitives for sandboxing subprocesses. E.g. in the requirements file add an optional section for sandbox directives that will cause the import to be executed in a subprocess with a restricted set of OS-level permissions (e.g. no writing to the filesystem other than a particular socket for communicating with the parent process).
That wouldn't be an import, though. It would be a subprocess. Trying to make it work transparently would be basically impossible, and if programmers are going to have to be aware that it's a subprocess, may as well treat it as one rather than trying to fake it as an import.
An incremental and independently useful place to start on that might be adding sandboxing primitives to the subprocess and/or multiprocessing module. I have tried to do this manually on a linux web service using calls to Imagemagick and didn't see a way to do it aside from calling a `docker run` command. Is there a cross-platform way of doing this? I did a bit of googling and found some "experimental" libraries for the purpose, though nothing that wanted to call itself production-ready. (Gaol https://github.com/servo/gaol and Boxfort https://github.com/Snaipe/BoxFort) Presumably web browsers like Chrome have some prior art as well.
Adding sandboxing primitives would be good for the subprocess module, definitely. That way they're not tied to running other Python packages, so you can restrict any subprocess at all (as in your example of ImageMagick). ChrisA
I'm of the opinion that trying to sandbox an otherwise unaltered runtime and standard library will run into the same walls as previous attempts. My sense of this is if the Python community had the appetite for effective fine-grained access control policies, it would require embedding enforcement into the stdlib modules themselves. Pretty much a refactor across the board.
The OCI currently contains three specifications: the Runtime Specification (runtime-spec), the Image Specification (image-spec) and the Distribution Specification (distribution-spec). The Runtime Specification outlines how to run a “filesystem bundle” that is unpacked on disk. At a high-level an OCI implementation would download an OCI Image then unpack
Extensions need permissions to access more powerful WebExtension APIs. They can ask for permissions at install time, by including the permissions
There must be capabilities/permissions specified in wheel package manifests: OCI Open Container Interface specs are implemented in e.g. Podman and buildah but not yet in Docker (moby engine) or BuildKit, fwiu. Like Docker, Podman works on Linux//Mac/Windows. The OCI specs do not specify how or whether to AppArmor and/or SELinux within the container and/or on the host; but they do specify setcap and dropcap capabilities that The OCI specs: https://opencontainers.org/about/overview/ : that image into an OCI Runtime filesystem bundle. At this point the OCI Runtime Bundle would be run by an OCI Runtime. https://github.com/opencontainers/image-spec/blob/main/spec.md - https://github.com/opencontainers/image-spec/blob/main/config.md#example For example: - AppArmor https://wiki.archlinux.org/title/AppArmor#Understanding_profiles - SELinux Policies https://wiki.archlinux.org/title/SELinux#Concepts:_Mandatory_Access_Controls https://github.com/fedora-selinux/selinux-policy/blob/rawhide/policy/modules... https://github.com/fedora-selinux/selinux-policy/blob/rawhide/policy/modules... https://github.com/fedora-selinux/selinux-policy/blob/rawhide/policy/modules... https://github.com/k3s-io/k3s/issues/1372#issuecomment-581797716 - Android APK permissions https://developer.android.com/reference/android/Manifest.permission https://developer.android.com/guide/topics/permissions/overview - containers - WebExtensions https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/p... they need in the `permissions` manifest.json key. The main advantages of asking for permissions at install time are:
- The user is only asked once, so it's less disruptive for them, and a simpler decision. - The extension can rely on the access to the APIs it needs, because if already running, the permissions have been granted.
In most major browsers, users can see if their installed extensions request advanced permissions through the browser's extensions manager.
$ pip freeze $ conda env export --from-history $ docker sbom
With the permissions API, an extension can ask for additional permissions at runtime. These permissions need to be listed in the `optional_permissions` manifest.json key.
Terms: - DAC: Discretionary Access Control - MAC: Mandatory Access Control Things that could enforce the conjunctive sum of the access control policies for each package and c extension module in a given set of paths in sys.path: - ~~Python runtime itself~~ - a process spawner that wraps systemd-nspawn and similar for other OSes - Flatpak (Linux) $ flatpak run "$flatpakname" - $ firejail --appimage= https://github.com/netblue30/firejail - Containers / VMs: virtual machines - Gvisor - Firecracker - https://github.com/containers/oci-seccomp-bpf-hook - https://github.com/falcosecurity/falco On Wed, Mar 1, 2023, 4:50 PM Paul Bryan <pbryan@anode.ca> wrote:
I'm of the opinion that trying to sandbox an otherwise unaltered runtime and standard library will run into the same walls as previous attempts. My sense of this is if the Python community had the appetite for effective fine-grained access control policies, it would require embedding enforcement into the stdlib modules themselves. Pretty much a refactor across the board. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2S7WBM... Code of Conduct: http://python.org/psf/codeofconduct/
Flatpak does seccomp syscall filtering like Docker containers does on Linux "Move all seccomp filters to xdg-seccomp-filters project" https://github.com/flatpak/flatpak/issues/4466 - Is there a limited set of syscalls for bin/python in general use? - A given application which uses Python only needs certain syscalls, and there's no way to specify which in the python packaging ecosystem yet; so, tools that dynamically trace syscalls at runtime (while running integration tests of the complete application, or tests of packages or modules or callables) are useful for generating and manually cleaning up an allow list of access control rules. The stopdisablingselinux.com talk has a walkthrough of audit2allow, which tails dmesg (journalctl --dmesg) and generates candidate SELinux Policies. "WIP: Add an all-syscalls feature which disables seccomp filtering" : "Performance impact of seccomp filter in games" https://github.com/flatpak/flatpak/issues/4187#issuecomment-1075512546 - list of reasons to not run flatpaks without seccomp Seccomp syscall filter rules are Linux only, though; so A more abstract permission set similar to Android's list of strings for package manifest.xml files which is *verifiably* implemented as {e.g. seccomp, AppArmor, SELinux Policies, and MacOS and Windows equivalents} prior to cryptographically-signing the package manifests (and uploading to e.g. PyPI where what's uploaded will be TUF-signed) would be necessary. Potential development workflow changes: 1. Update setup.py: add os-portable permission strings and/or os-specific rules to package's' setup.py's and meta.yml's, modules, and/or callables 2. 3. Generate {setup.py console_script package entrypoint scripts with syscall filtering, flatpak packages with syscall filtering, AppArmor scripts, SELinux Policies, and OCI container seccomp config ,} without having to again trace syscalls while running tests 4. 5. Generate config dicts for IDK subprocess.safe_Popen(security_opts=) ? (Given each package's os-portable permission strings and/or os-specific rules) 6. Determine whether plain Python code even needs WASI system access when run in a WASM runtime (which can be imported from CPython with e.g. emscripten-forge/pyjs-code-runner, (which doesn't itself do seccomp syscall filtering)) On Wed, Mar 1, 2023, 11:09 PM Wes Turner <wes.turner@gmail.com> wrote:
There must be capabilities/permissions specified in wheel package manifests:
OCI Open Container Interface specs are implemented in e.g. Podman and buildah but not yet in Docker (moby engine) or BuildKit, fwiu. Like Docker, Podman works on Linux//Mac/Windows.
The OCI specs do not specify how or whether to AppArmor and/or SELinux within the container and/or on the host; but they do specify setcap and dropcap capabilities that
The OCI specs: https://opencontainers.org/about/overview/ :
The OCI currently contains three specifications: the Runtime Specification (runtime-spec), the Image Specification (image-spec) and the Distribution Specification (distribution-spec). The Runtime Specification outlines how to run a “filesystem bundle” that is unpacked on disk. At a high-level an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle. At this point the OCI Runtime Bundle would be run by an OCI Runtime.
https://github.com/opencontainers/image-spec/blob/main/spec.md - https://github.com/opencontainers/image-spec/blob/main/config.md#example
For example: - AppArmor https://wiki.archlinux.org/title/AppArmor#Understanding_profiles
- SELinux Policies
https://wiki.archlinux.org/title/SELinux#Concepts:_Mandatory_Access_Controls
https://github.com/fedora-selinux/selinux-policy/blob/rawhide/policy/modules...
https://github.com/fedora-selinux/selinux-policy/blob/rawhide/policy/modules...
https://github.com/fedora-selinux/selinux-policy/blob/rawhide/policy/modules... https://github.com/k3s-io/k3s/issues/1372#issuecomment-581797716
- Android APK permissions https://developer.android.com/reference/android/Manifest.permission https://developer.android.com/guide/topics/permissions/overview
- containers
- WebExtensions
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/p...
Extensions need permissions to access more powerful WebExtension APIs. They can ask for permissions at install time, by including the permissions they need in the `permissions` manifest.json key. The main advantages of asking for permissions at install time are: - The user is only asked once, so it's less disruptive for them, and a simpler decision. - The extension can rely on the access to the APIs it needs, because if already running, the permissions have been granted.
In most major browsers, users can see if their installed extensions request advanced permissions through the browser's extensions manager.
$ pip freeze $ conda env export --from-history $ docker sbom
With the permissions API, an extension can ask for additional permissions at runtime. These permissions need to be listed in the `optional_permissions` manifest.json key.
Terms: - DAC: Discretionary Access Control - MAC: Mandatory Access Control
Things that could enforce the conjunctive sum of the access control policies for each package and c extension module in a given set of paths in sys.path:
- ~~Python runtime itself~~ - a process spawner that wraps systemd-nspawn and similar for other OSes - Flatpak (Linux) $ flatpak run "$flatpakname" - $ firejail --appimage= https://github.com/netblue30/firejail - Containers / VMs: virtual machines - Gvisor - Firecracker - https://github.com/containers/oci-seccomp-bpf-hook - https://github.com/falcosecurity/falco
On Wed, Mar 1, 2023, 4:50 PM Paul Bryan <pbryan@anode.ca> wrote:
I'm of the opinion that trying to sandbox an otherwise unaltered runtime and standard library will run into the same walls as previous attempts. My sense of this is if the Python community had the appetite for effective fine-grained access control policies, it would require embedding enforcement into the stdlib modules themselves. Pretty much a refactor across the board. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2S7WBM... Code of Conduct: http://python.org/psf/codeofconduct/
On Sun, 2023-02-26 at 01:21 +0000, python--- via Python-ideas wrote:
Hello all,
Supply chain attacks are becoming a pressing concern in software development due to the large number of dependencies and multiple attack vectors. Using third party modules (libraries, packages etc) is always a risk but the true potential of these attacks is now being weaponized. One way to deal with the risk is by limiting access to sensitive APIs like filesystem, shell, network and ffi so that packages which aren't explicitly granted permissions cannot use them, reducing their ability to do damage.
For example, a yaml parser should not need to use ffi, network nor shell. A command line argument parser library should not use network, ffi nor filesystem. Deno, a runtime for Typescript contains an interesting implementation of a permissions model for APIs.
I strongly think Python could benefit from such functionality and hacked together a quick experiment here: https://github.com/R9295/cpython Currently, it only prevents module imports in a very elementary manner but perhaps it can be of use to spark a discussion for an implementation.
Looking forward to your thoughts, Aarnav
With the way Python is designed, this is super difficult, so good luck ;) If your use-case is when using this in production, you're likely running Linux. So, why not use seccomp[1]? libseccomp even has Python bindings[2]. This is a bit tricker to use than your proposal, as it applies limitations to the whole thread. If you want to have different limitations for your code than you have for the 3rd party one, you'll probably want to have a thread running the bits of your code that need to the unsafe syscalls (eg. fs-interaction), and have the rest of code running in a locked down thread. You just need to make sure you are not running code that originated from the protected thread in the unprotected thread, so just make sure you are not passing Python objects, even builtins like str, from the unprotected thread to the protected one. [1] https://man.archlinux.org/man/seccomp.2 [2] https://lwn.net/Articles/634391/ Cheers, Filipe Laíns
participants (10)
-
Chris Angelico
-
edenwheeler60@gmail.com
-
Filipe Laíns
-
Joao S. O. Bueno
-
Lucas Wiman
-
Paul Bryan
-
Paul Moore
-
python@ruebezahl.mozmail.com
-
Tobias HT
-
Wes Turner