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