|
| 1 | +## python-pathrs ## |
| 2 | + |
| 3 | +This is a basic Python wrapper around [libpathrs][libpathrs], a safe path |
| 4 | +resolution library for Linux. For more details about the security protections |
| 5 | +provided by [libpathrs][libpathrs], [see the main README][libpathrs-readme]. |
| 6 | + |
| 7 | +In order to use this library, you need to have `libpathrs.so` installed on your |
| 8 | +system. |
| 9 | + |
| 10 | +### Examples ### |
| 11 | + |
| 12 | +libpathrs allows you to operate on a container root filesystem safely, without |
| 13 | +worrying about an attacker swapping components and tricking you into operating |
| 14 | +on host files. |
| 15 | + |
| 16 | +```python |
| 17 | +import pathrs |
| 18 | + |
| 19 | +# Get a handle to the root filesystem. |
| 20 | +with pathrs.Root("/path/to/rootfs") as root: |
| 21 | + # Get an O_PATH handle to a path we want to operate on. |
| 22 | + with root.resolve("/etc/passwd") as passwd: |
| 23 | + # Upgrade the handle to one you can do regular IO on. |
| 24 | + with root.reopen("r") as f: |
| 25 | + for line in f: |
| 26 | + print(line.rstrip("\n")) |
| 27 | +``` |
| 28 | + |
| 29 | +Aside from just opening files, libpathrs also allows you to do most common |
| 30 | +filesystem operations: |
| 31 | + |
| 32 | +```python |
| 33 | +import pathrs |
| 34 | + |
| 35 | +# <fcntl.h> |
| 36 | +RENAME_EXCHANGE = 0x2 |
| 37 | + |
| 38 | +with pathrs.Root("/path/to/rootfs") as root: |
| 39 | + # symlink |
| 40 | + root.symlink("foo", "bar") # foo -> bar |
| 41 | + # link |
| 42 | + root.hardlink("a", "b") # a -> b |
| 43 | + # rename(at2) |
| 44 | + root.rename("foo", "b", flags=RENAME_EXCHANGE) # foo <-> b |
| 45 | + # open(O_CREAT) |
| 46 | + with root.creat("newfile", "w+") as f: |
| 47 | + f.write("Some contents.") |
| 48 | +``` |
| 49 | + |
| 50 | +It also supports operations like `mkdir -p` and `rm -f`, which are a little |
| 51 | +tricky to implement safely. |
| 52 | + |
| 53 | +```python |
| 54 | +import pathrs |
| 55 | + |
| 56 | +with pathrs.Root("/path/to/rootfs") as root: |
| 57 | + # rm -r |
| 58 | + root.remove_all("/tmp/foo") |
| 59 | + # mkdir -p |
| 60 | + root.mkdir_all("/tmp/foo/bar/baz/bing/boop", 0o755) |
| 61 | +``` |
| 62 | + |
| 63 | +In addition, libpathrs provides a safe `procfs` API, to allow for privileged |
| 64 | +programs to operate on `/proc` in a way that detects a maliciously-configured |
| 65 | +mount table. This is a somewhat esoteric requirement, but privileged processes |
| 66 | +that have to operate in untrusted mount namespaces need to handle this |
| 67 | +properly or risk serious security issues. |
| 68 | + |
| 69 | +```python |
| 70 | +import pathrs |
| 71 | + |
| 72 | +# readlink("/proc/thread-self/fd/0") |
| 73 | +stdin_path = pathrs.proc_readlink(pathrs.PROC_THREAD_SELF, "fd/0") |
| 74 | + |
| 75 | +# readlink("/proc/self/exe") |
| 76 | +exe_path = pathrs.proc_readlink(pathrs.PROC_SELF, "exe") |
| 77 | + |
| 78 | +# Read data from /proc/cpuinfo. |
| 79 | +with pathrs.proc_open(pathrs.PROC_ROOT, "cpuinfo", "r") as cpuinfo: |
| 80 | + for line in cpuinfo: |
| 81 | + print(line.rstrip("\n")) |
| 82 | +``` |
| 83 | + |
| 84 | +[libpathrs]: https://github.com/openSUSE/libpathrs |
| 85 | +[libpathrs-readme]: https://github.com/openSUSE/libpathrs/blob/main/README.md |
0 commit comments