mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 19:41:10 +00:00
Merge pull request #4 from maxjivi05/fix/proot-performance
proot: build from source with WinNative's performance fixes
This commit is contained in:
12 files changed
+511
-16
No files matched your search
@@ -240,6 +240,21 @@ jobs:
|
||||
tar --use-compress-program=unzstd -tf app/src/main/assets/pulseaudio.tzst | grep -c '\.so$'
|
||||
rm -rf pa-bundle sink-out
|
||||
|
||||
- name: Cache proot
|
||||
id: proot
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
app/src/main/jniLibs/arm64-v8a/libproot.so
|
||||
app/src/main/jniLibs/arm64-v8a/libproot-loader.so
|
||||
key: proot-${{ env.NDK_VERSION }}-${{ hashFiles('tools/proot/**') }}
|
||||
- name: Build proot
|
||||
if: steps.proot.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export NDK="${ANDROID_NDK_LATEST_HOME:-${ANDROID_NDK_HOME:-$ANDROID_NDK_ROOT}}"
|
||||
tools/proot/build.sh app/src/main/jniLibs/arm64-v8a
|
||||
|
||||
- name: Check the preloads
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -11,6 +11,8 @@ captures/
|
||||
# Built in CI from tools/linuxfs and app/src/main/cpp/fakeinput.cpp, never committed, so the two
|
||||
# copies cannot drift.
|
||||
app/src/main/assets/linuxfs/
|
||||
app/src/main/jniLibs/arm64-v8a/libproot.so
|
||||
app/src/main/jniLibs/arm64-v8a/libproot-loader.so
|
||||
|
||||
# Kotlin compiler session files (build-tool state, never source).
|
||||
.kotlin/
|
||||
|
||||
@@ -58,30 +58,22 @@ public final class LinuxRuntime {
|
||||
/** Where the runtime carries the host-side proot; see tools/linuxfs/prebuilt/proot/README.md. */
|
||||
private static final String HOST_DIR = "opt/android-host";
|
||||
|
||||
/**
|
||||
* proot, preferred from the installed runtime and falling back to the copy in the apk.
|
||||
*
|
||||
* <p>It is an Android binary rather than part of the rootfs - it is what creates the rootfs -
|
||||
* but it travels in the runtime tarball so that reinstalling the app cannot replace the one
|
||||
* binary everything else depends on, and so a device with no working packaged proot can still
|
||||
* run the runtime.
|
||||
*/
|
||||
public static File prootBinary(Context context) {
|
||||
File shipped = new File(rootDir(context), HOST_DIR + "/proot");
|
||||
if (shipped.isFile()) return shipped;
|
||||
return new File(context.getApplicationInfo().nativeLibraryDir, "libproot.so");
|
||||
File packaged = new File(context.getApplicationInfo().nativeLibraryDir, "libproot.so");
|
||||
if (packaged.isFile()) return packaged;
|
||||
return new File(rootDir(context), HOST_DIR + "/proot");
|
||||
}
|
||||
|
||||
public static File prootLoader(Context context) {
|
||||
File shipped = new File(rootDir(context), HOST_DIR + "/loader");
|
||||
if (shipped.isFile()) return shipped;
|
||||
return new File(context.getApplicationInfo().nativeLibraryDir, "libproot-loader.so");
|
||||
File packaged = new File(context.getApplicationInfo().nativeLibraryDir, "libproot-loader.so");
|
||||
if (packaged.isFile()) return packaged;
|
||||
return new File(rootDir(context), HOST_DIR + "/loader");
|
||||
}
|
||||
|
||||
/** proot links against libtalloc, which sits beside it; empty when the apk copy is in use. */
|
||||
public static String prootLibraryPath(Context context) {
|
||||
File dir = new File(rootDir(context), HOST_DIR);
|
||||
return new File(dir, "proot").isFile() ? dir.getPath() : "";
|
||||
return dir.equals(prootBinary(context).getParentFile()) ? dir.getPath() : "";
|
||||
}
|
||||
|
||||
/** The rootfs is present with gamescope and the session script the launcher hands control to. */
|
||||
|
||||
@@ -982,7 +982,7 @@ class SessionService : Service() {
|
||||
private const val EXTRA_AUXILIARY_PID = "auxiliaryPid"
|
||||
/** Command lines that can only belong to a session of ours. */
|
||||
private val STRAGGLERS = listOf("bannerlator-session", "gamescope", "Xwayland", "steamrtarm64",
|
||||
"steamwebhelper", "linuxfs/opt/android-host/proot", "pulseaudio/libpulseaudio.so")
|
||||
"steamwebhelper", "linuxfs/opt/android-host/proot", "/libproot.so", "pulseaudio/libpulseaudio.so")
|
||||
/** How long proot gets to run its own cleanup before it is killed outright. */
|
||||
private const val GRACE_MS = 1200L
|
||||
private const val NO_PAD_SWITCH = "Download/droiddeck-no-pad"
|
||||
|
||||
@@ -135,6 +135,7 @@ fi
|
||||
export NDK="${sdk_dir}/ndk/${ndk_version}"
|
||||
sink_output="${staging_dir}/sink-out"
|
||||
"${repo_root}/tools/aaudio-sink/build.sh" "${pa_source}" "${sink_output}"
|
||||
"${repo_root}/tools/proot/build.sh" "${repo_root}/app/src/main/jniLibs/arm64-v8a"
|
||||
|
||||
cp -p "${bundle_asset}" "${bundle_backup}"
|
||||
bundle_dir="${staging_dir}/pulseaudio-bundle"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# proot patches carried by the app
|
||||
|
||||
Built by `tools/proot/build.sh` with the NDK on top of termux/proot `4dba3afb` (Termux's
|
||||
5.1.107-70 package, the proot the Linux runtime ships at `opt/android-host/proot`; every
|
||||
`file.c:line` site in that binary matches this commit). talloc is linked in statically from
|
||||
Samba's release tarball, so the apk carries one self-contained `libproot.so` plus
|
||||
`libproot-loader.so`, and `LinuxRuntime` prefers them over the runtime's copy.
|
||||
|
||||
Ported from WinNative (`feature/proot-enhancements`, e7af0f24):
|
||||
|
||||
- `0001-tracee-lookup-by-pid.patch` - tracees are hashed by pid, so each ptrace stop finds its
|
||||
tracee without walking one list entry per thread, and terminated tracees are swept only after a
|
||||
termination.
|
||||
- `0002-canon-resolve-parent-at-once.patch` - a clean absolute guest path at least three
|
||||
directories deep under the rootfs binding alone has its parent opened once with `O_PATH` and
|
||||
taken as canonical when `/proc/self/fd` names the path proot would build, replacing an `lstat`
|
||||
per component. The final component of a call that does not follow it is no longer `lstat`ed.
|
||||
Extensions still see the parent's host path, and the fast path stays off while the f2fs
|
||||
workaround is active.
|
||||
- `0003-clone3-flags-read-guard.patch` - a thread created with `clone3` keeps the flags it
|
||||
inherited when `struct clone_args` cannot be read, instead of being tracked as a fork.
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
OUTDIR=$(mkdir -p "$1" && cd "$1" && pwd)
|
||||
: "${NDK:?set NDK to the Android NDK root}"
|
||||
API=26
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
. "$HERE/source.env"
|
||||
case "$(uname -s):$(uname -m)" in
|
||||
Darwin:*) NDK_HOST=darwin-x86_64 ;;
|
||||
Linux:x86_64) NDK_HOST=linux-x86_64 ;;
|
||||
Linux:aarch64|Linux:arm64) NDK_HOST=linux-aarch64 ;;
|
||||
*) echo "Unsupported build host: $(uname -s) $(uname -m)" >&2; exit 1 ;;
|
||||
esac
|
||||
TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/$NDK_HOST/bin"
|
||||
if [[ ! -d "$TOOLCHAIN" && -d "$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin" ]]; then
|
||||
TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
||||
fi
|
||||
CC="$TOOLCHAIN/aarch64-linux-android${API}-clang"
|
||||
if [[ ! -x "$CC" ]]; then
|
||||
echo "Android NDK toolchain not found at $TOOLCHAIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
fetch() {
|
||||
curl -fsSL --retry 3 -o "$WORK/$1" "$2"
|
||||
echo "$3 $WORK/$1" | shasum -a 256 -c -
|
||||
mkdir -p "$WORK/${1%%.*}"
|
||||
tar -xzf "$WORK/$1" -C "$WORK/${1%%.*}" --strip-components=1
|
||||
}
|
||||
fetch proot.tar.gz "https://github.com/termux/proot/archive/${PROOT_COMMIT}.tar.gz" "$PROOT_SHA256"
|
||||
fetch talloc.tar.gz "https://www.samba.org/ftp/talloc/talloc-${TALLOC_VERSION}.tar.gz" "$TALLOC_SHA256"
|
||||
for patch in "$HERE"/patches/*.patch; do
|
||||
patch -d "$WORK/proot" -p1 --forward --quiet < "$patch"
|
||||
done
|
||||
mkdir -p "$WORK/talloc/config"
|
||||
cp "$HERE/talloc-config.h" "$WORK/talloc/config/config.h"
|
||||
"$CC" -c -O2 -fPIC -ffile-prefix-map="$WORK"=. -D__STDC_WANT_LIB_EXT1__=1 -DHAVE_CONFIG_H \
|
||||
-I"$WORK/talloc/config" -I"$WORK/talloc" -I"$WORK/talloc/lib/replace" \
|
||||
-o "$WORK/talloc.o" "$WORK/talloc/talloc.c"
|
||||
"$TOOLCHAIN/llvm-ar" rcs "$WORK/libtalloc.a" "$WORK/talloc.o"
|
||||
mkdir -p "$WORK/bin"
|
||||
ln -s "$TOOLCHAIN/llvm-readelf" "$WORK/bin/readelf"
|
||||
PATH="$WORK/bin:$PATH" make -C "$WORK/proot/src" -j"$(getconf _NPROCESSORS_ONLN)" \
|
||||
CC="$CC" STRIP="$TOOLCHAIN/llvm-strip" OBJCOPY="$TOOLCHAIN/llvm-objcopy" OBJDUMP="$TOOLCHAIN/llvm-objdump" \
|
||||
CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I. -I$WORK/talloc -DARG_MAX=131072 -Wno-error=implicit-function-declaration" \
|
||||
LDFLAGS="$WORK/libtalloc.a -Wl,-z,noexecstack" \
|
||||
PROOT_UNBUNDLE_LOADER=/nonexistent proot loader
|
||||
install -m755 "$WORK/proot/src/proot" "$OUTDIR/libproot.so"
|
||||
install -m755 "$WORK/proot/src/loader/loader" "$OUTDIR/libproot-loader.so"
|
||||
"$TOOLCHAIN/llvm-strip" --strip-unneeded "$OUTDIR/libproot.so"
|
||||
grep -q '^#define HAVE_SECCOMP_FILTER' "$WORK/proot/src/build.h" || { echo "ERROR: proot was built without seccomp acceleration"; exit 1; }
|
||||
grep -q '^#define HAVE_PROCESS_VM' "$WORK/proot/src/build.h" || { echo "ERROR: proot was built without process_vm"; exit 1; }
|
||||
NEEDED=$("$TOOLCHAIN/llvm-readelf" -d "$OUTDIR/libproot.so" | sed -n 's/.*NEEDED.*\[\(.*\)\]/\1/p' | tr '\n' ' ')
|
||||
echo "libproot.so NEEDED: $NEEDED"
|
||||
for lib in $NEEDED; do
|
||||
case $lib in libc.so|libdl.so|libm.so) ;;
|
||||
*) echo "ERROR: unexpected dependency $lib"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
ls -l "$OUTDIR/libproot.so" "$OUTDIR/libproot-loader.so"
|
||||
@@ -0,0 +1,137 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: maxjivi05 <maxjividen@gmail.com>
|
||||
Date: Wed, 23 Sep 2026 21:44:45 -0400
|
||||
Subject: [PATCH] tracee: find tracees by pid, and sweep only after a
|
||||
termination
|
||||
|
||||
---
|
||||
src/cli/cli.c | 2 +-
|
||||
src/tracee/event.c | 2 +-
|
||||
src/tracee/tracee.c | 26 +++++++++++++++++++++++++-
|
||||
src/tracee/tracee.h | 2 ++
|
||||
4 files changed, 29 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/cli/cli.c b/src/cli/cli.c
|
||||
index bbc6400..ec50712 100644
|
||||
--- a/src/cli/cli.c
|
||||
+++ b/src/cli/cli.c
|
||||
@@ -465,7 +465,7 @@ int main(int argc, char *const argv[])
|
||||
tracee = get_tracee(NULL, 0, true);
|
||||
if (tracee == NULL)
|
||||
goto error;
|
||||
- tracee->pid = getpid();
|
||||
+ set_tracee_pid(tracee, getpid());
|
||||
|
||||
/* Set verboseness from env variable, may be overriden by option */
|
||||
{
|
||||
diff --git a/src/tracee/event.c b/src/tracee/event.c
|
||||
index 756aa7e..ec79ef3 100644
|
||||
--- a/src/tracee/event.c
|
||||
+++ b/src/tracee/event.c
|
||||
@@ -106,7 +106,7 @@ int launch_process(Tracee *tracee, char *const argv[])
|
||||
|
||||
default: /* parent */
|
||||
/* We know the pid of the first tracee now. */
|
||||
- tracee->pid = pid;
|
||||
+ set_tracee_pid(tracee, pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/tracee/tracee.c b/src/tracee/tracee.c
|
||||
index a97757d..90894a0 100644
|
||||
--- a/src/tracee/tracee.c
|
||||
+++ b/src/tracee/tracee.c
|
||||
@@ -48,6 +48,16 @@
|
||||
|
||||
static Tracees tracees;
|
||||
|
||||
+#define TRACEE_BUCKETS 1024
|
||||
+static Tracees buckets[TRACEE_BUCKETS];
|
||||
+
|
||||
+static bool terminations_pending = false;
|
||||
+
|
||||
+static Tracees *bucket_of(pid_t pid)
|
||||
+{
|
||||
+ return &buckets[(unsigned int) pid % TRACEE_BUCKETS];
|
||||
+}
|
||||
+
|
||||
|
||||
/**
|
||||
* Remove @zombie from its parent's list of zombies. Note: this is a
|
||||
@@ -89,6 +99,7 @@ static int remove_tracee(Tracee *tracee)
|
||||
int event;
|
||||
|
||||
LIST_REMOVE(tracee, link);
|
||||
+ LIST_REMOVE(tracee, bucket_link);
|
||||
|
||||
/* Clean objects that are linked to this tracee's life
|
||||
* span. */
|
||||
@@ -226,6 +237,7 @@ static Tracee *new_tracee(pid_t pid)
|
||||
tracee->vpid = next_vpid++;
|
||||
|
||||
LIST_INSERT_HEAD(&tracees, tracee, link);
|
||||
+ LIST_INSERT_HEAD(bucket_of(pid), tracee, bucket_link);
|
||||
|
||||
tracee->life_context = talloc_new(tracee);
|
||||
|
||||
@@ -327,7 +339,7 @@ Tracee *get_tracee(const Tracee *current_tracee, pid_t pid, bool create)
|
||||
if (current_tracee != NULL && current_tracee->pid == pid)
|
||||
return (Tracee *)current_tracee;
|
||||
|
||||
- LIST_FOREACH(tracee, &tracees, link) {
|
||||
+ LIST_FOREACH(tracee, bucket_of(pid), bucket_link) {
|
||||
if (tracee->pid == pid) {
|
||||
/* Flush then allocate a new memory collector. */
|
||||
TALLOC_FREE(tracee->ctx);
|
||||
@@ -340,12 +352,20 @@ Tracee *get_tracee(const Tracee *current_tracee, pid_t pid, bool create)
|
||||
return (create ? new_tracee(pid) : NULL);
|
||||
}
|
||||
|
||||
+void set_tracee_pid(Tracee *tracee, pid_t pid)
|
||||
+{
|
||||
+ tracee->pid = pid;
|
||||
+ LIST_REMOVE(tracee, bucket_link);
|
||||
+ LIST_INSERT_HEAD(bucket_of(pid), tracee, bucket_link);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* Mark tracee as terminated and optionally take action.
|
||||
*/
|
||||
void terminate_tracee(Tracee *tracee)
|
||||
{
|
||||
tracee->terminated = true;
|
||||
+ terminations_pending = true;
|
||||
|
||||
/* Case where the terminated tracee is marked
|
||||
to kill all tracees on exit.
|
||||
@@ -363,6 +383,10 @@ void free_terminated_tracees()
|
||||
{
|
||||
Tracee *next;
|
||||
|
||||
+ if (!terminations_pending)
|
||||
+ return;
|
||||
+ terminations_pending = false;
|
||||
+
|
||||
/* Items can't be deleted when using LIST_FOREACH. */
|
||||
next = tracees.lh_first;
|
||||
while (next != NULL) {
|
||||
diff --git a/src/tracee/tracee.h b/src/tracee/tracee.h
|
||||
index 3dcbc7b..e4be3ff 100644
|
||||
--- a/src/tracee/tracee.h
|
||||
+++ b/src/tracee/tracee.h
|
||||
@@ -79,6 +79,7 @@ typedef struct tracee {
|
||||
|
||||
/* Link for the list of all tracees. */
|
||||
LIST_ENTRY(tracee) link;
|
||||
+ LIST_ENTRY(tracee) bucket_link;
|
||||
|
||||
/* Process identifier. */
|
||||
pid_t pid;
|
||||
@@ -300,6 +301,7 @@ typedef struct tracee {
|
||||
#define TRACEE(a) talloc_get_type_abort(talloc_parent(talloc_parent(a)), Tracee)
|
||||
|
||||
extern Tracee *get_tracee(const Tracee *tracee, pid_t pid, bool create);
|
||||
+extern void set_tracee_pid(Tracee *tracee, pid_t pid);
|
||||
extern Tracee *get_stopped_ptracee(const Tracee *ptracer, pid_t pid,
|
||||
bool only_with_pevent, word_t wait_options);
|
||||
extern bool has_ptracees(const Tracee *ptracer, pid_t pid, word_t wait_options);
|
||||
@@ -0,0 +1,198 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: maxjivi05 <maxjividen@gmail.com>
|
||||
Date: Wed, 23 Sep 2026 21:44:45 -0400
|
||||
Subject: [PATCH] canon: resolve a deep parent directory at once, and skip the
|
||||
lstat of a final component that is not followed
|
||||
|
||||
---
|
||||
src/path/canon.c | 94 +++++++++++++++++++++++++++++++++++++++++++--
|
||||
src/path/f2fs-bug.c | 7 +++-
|
||||
src/path/f2fs-bug.h | 1 +
|
||||
3 files changed, 97 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/path/canon.c b/src/path/canon.c
|
||||
index 6c5d4c0..cabd0c0 100644
|
||||
--- a/src/path/canon.c
|
||||
+++ b/src/path/canon.c
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <limits.h> /* PATH_MAX, */
|
||||
#include <sys/param.h> /* MAXSYMLINKS, */
|
||||
#include <errno.h> /* E*, */
|
||||
+#include <fcntl.h>
|
||||
#include <sys/stat.h> /* lstat(2), S_ISREG(), */
|
||||
#include <unistd.h> /* access(2), lstat(2), */
|
||||
#include <string.h> /* string(3), */
|
||||
@@ -133,7 +134,8 @@ static inline Finality next_component(char component[NAME_MAX], const char **cur
|
||||
* (returned value is 1), otherwise it returns -errno (-ENOENT or
|
||||
* -ENOTDIR).
|
||||
*/
|
||||
-static inline int substitute_binding_stat(Tracee *tracee, Finality finality, unsigned int recursion_level,
|
||||
+static inline int substitute_binding_stat(Tracee *tracee, Finality finality, bool deref_final,
|
||||
+ unsigned int recursion_level,
|
||||
const char guest_path[PATH_MAX], char host_path[PATH_MAX])
|
||||
{
|
||||
struct stat statl;
|
||||
@@ -152,6 +154,9 @@ static inline int substitute_binding_stat(Tracee *tracee, Finality finality, uns
|
||||
return status;
|
||||
}
|
||||
|
||||
+ if (finality == FINAL_NORMAL && !deref_final && tracee->glue_type == 0)
|
||||
+ return 0;
|
||||
+
|
||||
statl.st_mode = 0;
|
||||
if (should_skip_file_access_due_to_f2fs_bug(tracee, host_path)) {
|
||||
status = -ENOENT;
|
||||
@@ -186,6 +191,87 @@ static inline int substitute_binding_stat(Tracee *tracee, Finality finality, uns
|
||||
return (S_ISLNK(statl.st_mode) ? 1 : 0);
|
||||
}
|
||||
|
||||
+#define RESOLVE_AT_ONCE_MIN_DEPTH 3
|
||||
+
|
||||
+static size_t resolve_parent_at_once(Tracee *tracee, const char *user_path,
|
||||
+ char guest_path[PATH_MAX])
|
||||
+{
|
||||
+ char parent[PATH_MAX];
|
||||
+ char expected[PATH_MAX];
|
||||
+ char resolved[PATH_MAX];
|
||||
+ char link[32];
|
||||
+ const Binding *binding;
|
||||
+ const char *last;
|
||||
+ const char *cursor;
|
||||
+ size_t parent_length;
|
||||
+ size_t prefix_length;
|
||||
+ size_t expected_length;
|
||||
+ ssize_t length;
|
||||
+ int depth;
|
||||
+ int fd;
|
||||
+
|
||||
+ if (tracee->glue_type != 0 || f2fs_bug_workaround_active(tracee))
|
||||
+ return 0;
|
||||
+
|
||||
+ last = strrchr(user_path, '/');
|
||||
+ if (last == NULL || last == user_path || last[1] == '\0'
|
||||
+ || strcmp(last + 1, ".") == 0 || strcmp(last + 1, "..") == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ parent_length = last - user_path;
|
||||
+ if (parent_length >= PATH_MAX)
|
||||
+ return 0;
|
||||
+
|
||||
+ depth = 0;
|
||||
+ for (cursor = user_path; cursor < last; ) {
|
||||
+ const char *end;
|
||||
+
|
||||
+ end = memchr(cursor + 1, '/', last - cursor);
|
||||
+ if (end == NULL)
|
||||
+ end = last;
|
||||
+ if (end == cursor + 1
|
||||
+ || (end == cursor + 2 && cursor[1] == '.')
|
||||
+ || (end == cursor + 3 && cursor[1] == '.' && cursor[2] == '.'))
|
||||
+ return 0;
|
||||
+ depth++;
|
||||
+ cursor = end;
|
||||
+ }
|
||||
+ if (depth < RESOLVE_AT_ONCE_MIN_DEPTH)
|
||||
+ return 0;
|
||||
+
|
||||
+ memcpy(parent, user_path, parent_length);
|
||||
+ parent[parent_length] = '\0';
|
||||
+
|
||||
+ binding = get_binding(tracee, GUEST, parent);
|
||||
+ if (binding == NULL || binding->guest.length != 1)
|
||||
+ return 0;
|
||||
+
|
||||
+ prefix_length = (binding->host.length == 1 ? 0 : binding->host.length);
|
||||
+ expected_length = prefix_length + parent_length;
|
||||
+ if (expected_length >= PATH_MAX)
|
||||
+ return 0;
|
||||
+ memcpy(expected, binding->host.path, prefix_length);
|
||||
+ strcpy(expected + prefix_length, parent);
|
||||
+
|
||||
+ fd = open(expected, O_PATH | O_DIRECTORY | O_CLOEXEC);
|
||||
+ if (fd < 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ snprintf(link, sizeof(link), "/proc/self/fd/%d", fd);
|
||||
+ length = readlink(link, resolved, sizeof(resolved));
|
||||
+ close(fd);
|
||||
+
|
||||
+ if (length < 0 || (size_t) length != expected_length
|
||||
+ || memcmp(resolved, expected, expected_length) != 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (notify_extensions(tracee, HOST_PATH, (intptr_t) expected, false) < 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ strcpy(guest_path, parent);
|
||||
+ return last + 1 - user_path;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* Copy in @guest_path the canonicalization (see `man 3 realpath`) of
|
||||
* @user_path regarding to @tracee->root. The path to canonicalize
|
||||
@@ -227,6 +313,8 @@ int canonicalize(Tracee *tracee, const char *user_path, bool deref_final,
|
||||
|
||||
/* Canonicalize recursely 'user_path' into 'guest_path'. */
|
||||
cursor = user_path;
|
||||
+ if (user_path[0] == '/')
|
||||
+ cursor += resolve_parent_at_once(tracee, user_path, guest_path);
|
||||
finality = NOT_FINAL;
|
||||
while (!IS_FINAL(finality)) {
|
||||
Comparison comparison;
|
||||
@@ -260,7 +348,7 @@ int canonicalize(Tracee *tracee, const char *user_path, bool deref_final,
|
||||
* symlink. For this latter case, we check that the
|
||||
* symlink points to a directory once it is
|
||||
* canonicalized, at the end of this loop. */
|
||||
- status = substitute_binding_stat(tracee, finality, recursion_level, scratch_path, host_path);
|
||||
+ status = substitute_binding_stat(tracee, finality, deref_final, recursion_level, scratch_path, host_path);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
@@ -338,7 +426,7 @@ int canonicalize(Tracee *tracee, const char *user_path, bool deref_final,
|
||||
|
||||
/* Check that a non-final canonicalized/dereferenced
|
||||
* symlink exists and is a directory. */
|
||||
- status = substitute_binding_stat(tracee, finality, recursion_level, guest_path, host_path);
|
||||
+ status = substitute_binding_stat(tracee, finality, deref_final, recursion_level, guest_path, host_path);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
diff --git a/src/path/f2fs-bug.c b/src/path/f2fs-bug.c
|
||||
index 4a5ee45..e4bddb9 100644
|
||||
--- a/src/path/f2fs-bug.c
|
||||
+++ b/src/path/f2fs-bug.c
|
||||
@@ -113,7 +113,7 @@ end:
|
||||
return result;
|
||||
}
|
||||
|
||||
-bool should_skip_file_access_due_to_f2fs_bug(const Tracee *tracee, const char *path) {
|
||||
+bool f2fs_bug_workaround_active(const Tracee *tracee) {
|
||||
/* On first call check if workaround should be enabled */
|
||||
static bool f2fs_bug_probed;
|
||||
static bool f2fs_bug_detected;
|
||||
@@ -130,9 +130,12 @@ bool should_skip_file_access_due_to_f2fs_bug(const Tracee *tracee, const char *p
|
||||
}
|
||||
f2fs_bug_probed = true;
|
||||
}
|
||||
+ return f2fs_bug_detected;
|
||||
+}
|
||||
|
||||
+bool should_skip_file_access_due_to_f2fs_bug(const Tracee *tracee, const char *path) {
|
||||
/* If workaround is not active don't skip access to file */
|
||||
- if (!f2fs_bug_detected) {
|
||||
+ if (!f2fs_bug_workaround_active(tracee)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
diff --git a/src/path/f2fs-bug.h b/src/path/f2fs-bug.h
|
||||
index b8eabdf..360f149 100644
|
||||
--- a/src/path/f2fs-bug.h
|
||||
+++ b/src/path/f2fs-bug.h
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdbool.h> /* bool, true, false, */
|
||||
#include "tracee/tracee.h" /* Tracee, */
|
||||
|
||||
+bool f2fs_bug_workaround_active(const Tracee *tracee);
|
||||
bool should_skip_file_access_due_to_f2fs_bug(const Tracee *tracee, const char *path);
|
||||
|
||||
#endif /* F2FS_BUG_H */
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: maxjivi05 <maxjividen@gmail.com>
|
||||
Date: Wed, 23 Sep 2026 21:44:45 -0400
|
||||
Subject: [PATCH] tracee: keep a thread's inherited clone flags when clone3's
|
||||
arguments cannot be read
|
||||
|
||||
---
|
||||
src/tracee/tracee.c | 9 +++++----
|
||||
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/tracee/tracee.c b/src/tracee/tracee.c
|
||||
index 90894a0..7c0c50c 100644
|
||||
--- a/src/tracee/tracee.c
|
||||
+++ b/src/tracee/tracee.c
|
||||
@@ -423,10 +423,11 @@ int new_child(Tracee *parent, word_t clone_flags)
|
||||
status = fetch_regs(parent);
|
||||
if (status >= 0 && get_sysnum(parent, CURRENT) == PR_clone)
|
||||
clone_flags = peek_reg(parent, CURRENT, SYSARG_1);
|
||||
- else if (status >= 0 && get_sysnum(parent, CURRENT) == PR_clone3)
|
||||
- // Look at the first word of the clone_args structure, which
|
||||
- // contains the usual clone flags.
|
||||
- clone_flags = peek_word(parent, peek_reg(parent, CURRENT, SYSARG_1));
|
||||
+ else if (status >= 0 && get_sysnum(parent, CURRENT) == PR_clone3) {
|
||||
+ word_t flags = peek_word(parent, peek_reg(parent, CURRENT, SYSARG_1));
|
||||
+ if (errno == 0)
|
||||
+ clone_flags = flags;
|
||||
+ }
|
||||
|
||||
/* Get the pid of the parent's new child. */
|
||||
status = ptrace(PTRACE_GETEVENTMSG, parent->pid, NULL, &pid);
|
||||
@@ -0,0 +1,4 @@
|
||||
PROOT_COMMIT=4dba3afbf3a63af89b4d9c1a59bf2bda10f4d10f
|
||||
PROOT_SHA256=de94f648547d1b62431073b82dc99d56ef0ddcef6da022e0dfffe2bf661cc34e
|
||||
TALLOC_VERSION=2.4.3
|
||||
TALLOC_SHA256=dc46c40b9f46bb34dd97fe41f548b0e8b247b77a918576733c528e83abd854dd
|
||||
@@ -0,0 +1,34 @@
|
||||
#define TALLOC_BUILD_VERSION_MAJOR 2
|
||||
#define TALLOC_BUILD_VERSION_MINOR 4
|
||||
#define TALLOC_BUILD_VERSION_RELEASE 3
|
||||
#define HAVE_STDBOOL_H 1
|
||||
#define HAVE_BOOL 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_INTTYPES_H 1
|
||||
#define HAVE_STRING_H 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_DLFCN_H 1
|
||||
#define HAVE_STRNLEN 1
|
||||
#define HAVE_STRNDUP 1
|
||||
#define HAVE_STRLCPY 1
|
||||
#define HAVE_STRLCAT 1
|
||||
#define HAVE_USLEEP 1
|
||||
#define HAVE_VA_COPY 1
|
||||
#define HAVE_VSNPRINTF 1
|
||||
#define HAVE_SNPRINTF 1
|
||||
#define HAVE_C99_VSNPRINTF 1
|
||||
#define HAVE_INTPTR_T 1
|
||||
#define HAVE_UINTPTR_T 1
|
||||
#define HAVE_PTRDIFF_T 1
|
||||
#define HAVE_SIG_ATOMIC_T_TYPE 1
|
||||
#define HAVE_ERRNO_DECL 1
|
||||
#define HAVE_MEMMOVE 1
|
||||
#define HAVE_CONSTRUCTOR_ATTRIBUTE 1
|
||||
#define HAVE_DESTRUCTOR_ATTRIBUTE 1
|
||||
#define HAVE_VISIBILITY_ATTR 1
|
||||
#define HAVE_FALLTHROUGH_ATTRIBUTE 1
|
||||
#define HAVE_SYS_AUXV_H 1
|
||||
#define HAVE_GETAUXVAL 1
|
||||
Reference in new issue
Block a user