From a04f2159ad237897eb1ce6900fb68c7a88257da4 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sat, 13 Nov 2021 09:14:15 +0800 Subject: [PATCH] chattr -i for log directory (#1398) Co-authored-by: Howard Wu <40033067+Howard20181@users.noreply.github.com> --- core/src/main/cpp/main/src/context.cpp | 5 ++ .../lspd/service/ConfigFileManager.java | 21 +++++- .../lsposed/lspd/service/LogcatService.java | 66 ++++++++++--------- .../src/main/java/hidden/HiddenApiBridge.java | 22 +++++++ .../src/main/java/android/os/Build.java | 15 +++++ .../java/android/system/ErrnoException.java | 5 ++ .../main/java/android/system/Int32Ref.java | 15 +++++ .../src/main/java/android/system/Os.java | 23 +++++++ .../main/java/android/util/MutableInt.java | 9 +++ 9 files changed, 148 insertions(+), 33 deletions(-) create mode 100644 hiddenapi-stubs/src/main/java/android/os/Build.java create mode 100644 hiddenapi-stubs/src/main/java/android/system/ErrnoException.java create mode 100644 hiddenapi-stubs/src/main/java/android/system/Int32Ref.java create mode 100644 hiddenapi-stubs/src/main/java/android/system/Os.java create mode 100644 hiddenapi-stubs/src/main/java/android/util/MutableInt.java diff --git a/core/src/main/cpp/main/src/context.cpp b/core/src/main/cpp/main/src/context.cpp index 454e36c2..f1767413 100644 --- a/core/src/main/cpp/main/src/context.cpp +++ b/core/src/main/cpp/main/src/context.cpp @@ -31,6 +31,11 @@ #include "service.h" #include "symbol_cache.h" +#include +#include + +static_assert(FS_IOC_SETFLAGS == LP_SELECT(0x40046602, 0x40086602)); + namespace lspd { extern int *allowUnload; diff --git a/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java index 55f110c1..2c0b226b 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java +++ b/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java @@ -9,6 +9,7 @@ import android.os.ParcelFileDescriptor; import android.os.SELinux; import android.os.SharedMemory; import android.system.ErrnoException; +import android.system.Os; import android.system.OsConstants; import android.util.Log; @@ -45,6 +46,8 @@ import java.util.List; import java.util.Map; import java.util.zip.ZipFile; +import hidden.HiddenApiBridge; + public class ConfigFileManager { static final Path basePath = Paths.get("/data/adb/lspd"); static final Path managerApkPath = basePath.resolve("manager.apk"); @@ -144,11 +147,25 @@ public class ConfigFileManager { }); } + public static boolean chattr0(Path path) { + try { + var dir = Os.open(path.toAbsolutePath().toString(), OsConstants.O_RDONLY, 0); + HiddenApiBridge.Os_ioctlInt(dir, HiddenApiBridge.VMRuntime_is64Bit() ? 0x40086602 : 0x40046602, 0); + Os.close(dir); + return true; + } catch (Throwable e) { + Log.d(TAG, "chattr 0", e); + return false; + } + } + static void moveLogDir() { try { if (Files.exists(logDirPath)) { - deleteFolderIfExists(oldLogDirPath); - Files.move(logDirPath, oldLogDirPath); + if (chattr0(logDirPath)) { + deleteFolderIfExists(oldLogDirPath); + Files.move(logDirPath, oldLogDirPath); + } } Files.createDirectories(logDirPath); } catch (IOException e) { diff --git a/core/src/main/java/org/lsposed/lspd/service/LogcatService.java b/core/src/main/java/org/lsposed/lspd/service/LogcatService.java index 37bbf035..1b2a55f8 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LogcatService.java +++ b/core/src/main/java/org/lsposed/lspd/service/LogcatService.java @@ -11,6 +11,7 @@ import org.lsposed.lspd.BuildConfig; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; @@ -19,7 +20,6 @@ import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; public class LogcatService implements Runnable { private static final String TAG = "LSPosedLogcat"; @@ -27,8 +27,8 @@ public class LogcatService implements Runnable { ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_APPEND; - private Path modulesLog = null; - private Path verboseLog = null; + private int modulesFd = -1; + private int verboseFd = -1; private Thread thread = null; @SuppressLint("UnsafeDynamicallyLoadedCode") @@ -56,42 +56,45 @@ public class LogcatService implements Runnable { try { File log; if (isVerboseLog) { - checkFdFile(verboseLog); + checkFd(verboseFd); log = ConfigFileManager.getNewVerboseLogPath(); } else { - checkFdFile(modulesLog); + checkFd(modulesFd); log = ConfigFileManager.getNewModulesLogPath(); } Log.i(TAG, "New log file: " + log); + ConfigFileManager.chattr0(log.toPath().getParent()); int fd = ParcelFileDescriptor.open(log, mode).detachFd(); - var fdFile = Paths.get("/proc/self/fd", String.valueOf(fd)); - if (isVerboseLog) verboseLog = fdFile; - else modulesLog = fdFile; + if (isVerboseLog) verboseFd = fd; + else modulesFd = fd; return fd; } catch (IOException e) { - if (isVerboseLog) verboseLog = null; - else modulesLog = null; + if (isVerboseLog) verboseFd = -1; + else modulesFd = -1; Log.w(TAG, "refreshFd", e); return -1; } } - private static void checkFdFile(Path fdFile) { - if (fdFile == null) return; + private static void checkFd(int fd) { + if (fd == -1) return; try { - var file = Files.readSymbolicLink(fdFile); - if (!Files.exists(file)) { + var jfd = new FileDescriptor(); + jfd.getClass().getDeclaredMethod("setInt$", int.class).invoke(jfd, fd); + var stat = Os.fstat(jfd); + if (stat.st_nlink == 0) { + var file = Files.readSymbolicLink(fdToPath(fd)); var parent = file.getParent(); if (!Files.isDirectory(parent, LinkOption.NOFOLLOW_LINKS)) { - Files.deleteIfExists(parent); + if (ConfigFileManager.chattr0(parent)) + Files.deleteIfExists(parent); } - Files.createDirectories(parent); var name = file.getFileName().toString(); var originName = name.substring(0, name.lastIndexOf(' ')); - Files.copy(fdFile, parent.resolve(originName)); + Files.copy(file, parent.resolve(originName)); } - } catch (IOException e) { - Log.w(TAG, "checkFd " + fdFile, e); + } catch (Throwable e) { + Log.w(TAG, "checkFd " + fd, e); } } @@ -133,7 +136,7 @@ public class LogcatService implements Runnable { } } } catch (IOException e) { - Log.e(TAG, "GetProp: " + e + ": " + Arrays.toString(e.getStackTrace())); + Log.e(TAG, "GetProp: ", e); } }); t.start(); @@ -143,7 +146,7 @@ public class LogcatService implements Runnable { writer.append(sb); } } catch (IOException | InterruptedException | NullPointerException e) { - Log.e(TAG, "GetProp: " + Arrays.toString(e.getStackTrace())); + Log.e(TAG, "GetProp: ", e); } } @@ -163,24 +166,25 @@ public class LogcatService implements Runnable { } } + static private Path fdToPath(int fd) { + if (fd == -1) return null; + else return Paths.get("/proc/self/fd", String.valueOf(fd)); + } + public File getVerboseLog() { - return verboseLog.toFile(); + var path = fdToPath(verboseFd); + return path == null ? null : path.toFile(); } public File getModulesLog() { - return modulesLog.toFile(); + var path = fdToPath(modulesFd); + return path == null ? null : path.toFile(); } public void checkLogFile() { - try { - modulesLog.toRealPath(); - } catch (IOException e) { + if (modulesFd == -1) refresh(false); - } - try { - verboseLog.toRealPath(); - } catch (IOException e) { + if (verboseFd == -1) refresh(true); - } } } diff --git a/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java b/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java index 0941b634..f0ee0f76 100644 --- a/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java +++ b/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java @@ -30,12 +30,20 @@ import android.content.res.CompatibilityInfo; import android.content.res.Resources; import android.content.res.ResourcesImpl; import android.os.Binder; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.UserHandle; +import android.system.ErrnoException; +import android.system.Int32Ref; +import android.system.Os; +import android.util.MutableInt; import java.io.File; +import java.io.FileDescriptor; + +import dalvik.system.VMRuntime; public class HiddenApiBridge { public static int AssetManager_addAssetPath(AssetManager am, String path) { @@ -91,4 +99,18 @@ public class HiddenApiBridge { public static CompatibilityInfo Resources_getCompatibilityInfo(Resources res) { return res.getCompatibilityInfo(); } + + public static int Os_ioctlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException { + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) { + return Os.ioctlInt(fd, cmd, new MutableInt(arg)); + } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + return Os.ioctlInt(fd, cmd, new Int32Ref(arg)); + } else { + return Os.ioctlInt(fd, cmd); + } + } + + public static boolean VMRuntime_is64Bit() { + return VMRuntime.getRuntime().is64Bit(); + } } diff --git a/hiddenapi-stubs/src/main/java/android/os/Build.java b/hiddenapi-stubs/src/main/java/android/os/Build.java new file mode 100644 index 00000000..e0b70fc3 --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/os/Build.java @@ -0,0 +1,15 @@ +package android.os; + +public class Build { + public static class VERSION { + public final static int SDK_INT = SystemProperties.getInt( + "ro.build.version.sdk", 0); + } + public static class VERSION_CODES { + public static final int O_MR1 = 27; + public static final int P = 28; + public static final int Q = 29; + public static final int R = 30; + public static final int S = 31; + } +} diff --git a/hiddenapi-stubs/src/main/java/android/system/ErrnoException.java b/hiddenapi-stubs/src/main/java/android/system/ErrnoException.java new file mode 100644 index 00000000..014857bc --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/system/ErrnoException.java @@ -0,0 +1,5 @@ +package android.system; + +public final class ErrnoException extends Exception { + +} diff --git a/hiddenapi-stubs/src/main/java/android/system/Int32Ref.java b/hiddenapi-stubs/src/main/java/android/system/Int32Ref.java new file mode 100644 index 00000000..e44e01b0 --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/system/Int32Ref.java @@ -0,0 +1,15 @@ +package android.system; + +import java.util.Objects; + +public class Int32Ref { + public int value; + + public Int32Ref(int value) { + this.value = value; + } + + @Override public String toString() { + return Objects.toString(this); + } +} diff --git a/hiddenapi-stubs/src/main/java/android/system/Os.java b/hiddenapi-stubs/src/main/java/android/system/Os.java new file mode 100644 index 00000000..04f0ec2b --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/system/Os.java @@ -0,0 +1,23 @@ +package android.system; + +import android.util.MutableInt; + +import androidx.annotation.RequiresApi; + +import java.io.FileDescriptor; + +public class Os { + public static int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException { + throw new ErrnoException(); + } + + @RequiresApi(27) + public static int ioctlInt(FileDescriptor fd, int cmd, Int32Ref arg) throws ErrnoException { + throw new ErrnoException(); + } + + @RequiresApi(31) + public static int ioctlInt(FileDescriptor fd, int cmd) throws ErrnoException { + throw new ErrnoException(); + } +} diff --git a/hiddenapi-stubs/src/main/java/android/util/MutableInt.java b/hiddenapi-stubs/src/main/java/android/util/MutableInt.java new file mode 100644 index 00000000..177f52ee --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/util/MutableInt.java @@ -0,0 +1,9 @@ +package android.util; + +public final class MutableInt { + public int value; + + public MutableInt(int value) { + this.value = value; + } +}