A preloaded library that checks file system access against a policy.

This package install /usr/lib64/libplatform-extension-proxy.so.0.0.0
as well as /etc/ld.so.preload which loads this library into every
process. The library provides proxy functions for various libc functions
accesing files and directories and checks if a process, based on policy,
can access requsted files. The main purpose of this library is to check
if hal services don't access files beyond permitted scope.

This library is a development tool and should not be used on a production image.

The access policy is loaded from /etc/platform-extension-proxy.policy at
startup. Each rule has a subject path, a target path, and an allow or deny
verdict. First matching rule wins, default is allow. The pattern matching works
like this:
- /dir matches /dir, /dir/file but not /directory,
- /dir/ does not match /dir itself, it only matches /dir/file,
- as a special case / matches everything.
# comments are allowed but only on the line start. If the policy is malformed
or fails to load, nothing is blocked.

The subject of a rule is the canonical path of the object (executable or
shared library) that called the libc function. If a HAL module accesses a
file through another library (for example glib or libstdc++), the subject is
that library, not the HAL module. The target is the canonical path of the
accessed file. For calls that do not follow a symbolic link in the last path
component (for example lstat, unlink, rename or O_NOFOLLOW), only the parent
directory is resolved. Denied accesses fail with EACCES and are logged to
/run/pe-proxy-deny.log (/dev/kmsg for PID 1).

The library cannot see accesses that do not go through the dynamically
linked libc functions it replaces. These include statically linked binaries,
direct syscall(2) calls, io_uring, and file access inside libc itself (for
example NSS or the dynamic loader).

Additionally, /etc/platform-extension-proxy.enforce is loaded at startup. Each
line contains a name of a function. If a function is mentioned in this file,
all checks for this function are enabled. Again, # comments are allowed but
only on the line start, and a malformed file or one that fails to load is
treated as if empty.

Performance notes:
The calling object of each proxied call is determined with _dl_find_object()
and cached per loaded object, so calls from objects that no deny rule applies
to cost nothing extra. For the others, the directory part of the target path
is resolved once and cached (32 entries, about 8 KB, in processes that
perform checks only), then the last component is checked with one lstat(2).
The cache is flushed whenever the process itself renames, unlinks, symlinks,
mounts etc., and entries expire after HAL_DIRCACHE_TTL_MS (default 1000), so
a change made to the file system by another process, e.g. retargeting a
symlink in a directory path, can go unnoticed for up to that long. Build with
-DHAL_DIRCACHE_TTL_MS=0 to disable the directory cache.
bench/run.sh, bench/difftest.sh and bench/cachetest.sh measure and test all
of this.
