chattr -i for log directory (#1398)

Co-authored-by: Howard Wu <40033067+Howard20181@users.noreply.github.com>
This commit is contained in:
LoveSy 2021-11-13 09:14:15 +08:00 committed by GitHub
parent 6dcceec3c9
commit a04f2159ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 148 additions and 33 deletions

View File

@ -31,6 +31,11 @@
#include "service.h" #include "service.h"
#include "symbol_cache.h" #include "symbol_cache.h"
#include <linux/fs.h>
#include <fcntl.h>
static_assert(FS_IOC_SETFLAGS == LP_SELECT(0x40046602, 0x40086602));
namespace lspd { namespace lspd {
extern int *allowUnload; extern int *allowUnload;

View File

@ -9,6 +9,7 @@ import android.os.ParcelFileDescriptor;
import android.os.SELinux; import android.os.SELinux;
import android.os.SharedMemory; import android.os.SharedMemory;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants; import android.system.OsConstants;
import android.util.Log; import android.util.Log;
@ -45,6 +46,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import hidden.HiddenApiBridge;
public class ConfigFileManager { public class ConfigFileManager {
static final Path basePath = Paths.get("/data/adb/lspd"); static final Path basePath = Paths.get("/data/adb/lspd");
static final Path managerApkPath = basePath.resolve("manager.apk"); 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() { static void moveLogDir() {
try { try {
if (Files.exists(logDirPath)) { if (Files.exists(logDirPath)) {
deleteFolderIfExists(oldLogDirPath); if (chattr0(logDirPath)) {
Files.move(logDirPath, oldLogDirPath); deleteFolderIfExists(oldLogDirPath);
Files.move(logDirPath, oldLogDirPath);
}
} }
Files.createDirectories(logDirPath); Files.createDirectories(logDirPath);
} catch (IOException e) { } catch (IOException e) {

View File

@ -11,6 +11,7 @@ import org.lsposed.lspd.BuildConfig;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
@ -19,7 +20,6 @@ import java.nio.file.Files;
import java.nio.file.LinkOption; import java.nio.file.LinkOption;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays;
public class LogcatService implements Runnable { public class LogcatService implements Runnable {
private static final String TAG = "LSPosedLogcat"; private static final String TAG = "LSPosedLogcat";
@ -27,8 +27,8 @@ public class LogcatService implements Runnable {
ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_TRUNCATE |
ParcelFileDescriptor.MODE_APPEND; ParcelFileDescriptor.MODE_APPEND;
private Path modulesLog = null; private int modulesFd = -1;
private Path verboseLog = null; private int verboseFd = -1;
private Thread thread = null; private Thread thread = null;
@SuppressLint("UnsafeDynamicallyLoadedCode") @SuppressLint("UnsafeDynamicallyLoadedCode")
@ -56,42 +56,45 @@ public class LogcatService implements Runnable {
try { try {
File log; File log;
if (isVerboseLog) { if (isVerboseLog) {
checkFdFile(verboseLog); checkFd(verboseFd);
log = ConfigFileManager.getNewVerboseLogPath(); log = ConfigFileManager.getNewVerboseLogPath();
} else { } else {
checkFdFile(modulesLog); checkFd(modulesFd);
log = ConfigFileManager.getNewModulesLogPath(); log = ConfigFileManager.getNewModulesLogPath();
} }
Log.i(TAG, "New log file: " + log); Log.i(TAG, "New log file: " + log);
ConfigFileManager.chattr0(log.toPath().getParent());
int fd = ParcelFileDescriptor.open(log, mode).detachFd(); int fd = ParcelFileDescriptor.open(log, mode).detachFd();
var fdFile = Paths.get("/proc/self/fd", String.valueOf(fd)); if (isVerboseLog) verboseFd = fd;
if (isVerboseLog) verboseLog = fdFile; else modulesFd = fd;
else modulesLog = fdFile;
return fd; return fd;
} catch (IOException e) { } catch (IOException e) {
if (isVerboseLog) verboseLog = null; if (isVerboseLog) verboseFd = -1;
else modulesLog = null; else modulesFd = -1;
Log.w(TAG, "refreshFd", e); Log.w(TAG, "refreshFd", e);
return -1; return -1;
} }
} }
private static void checkFdFile(Path fdFile) { private static void checkFd(int fd) {
if (fdFile == null) return; if (fd == -1) return;
try { try {
var file = Files.readSymbolicLink(fdFile); var jfd = new FileDescriptor();
if (!Files.exists(file)) { 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(); var parent = file.getParent();
if (!Files.isDirectory(parent, LinkOption.NOFOLLOW_LINKS)) { 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 name = file.getFileName().toString();
var originName = name.substring(0, name.lastIndexOf(' ')); var originName = name.substring(0, name.lastIndexOf(' '));
Files.copy(fdFile, parent.resolve(originName)); Files.copy(file, parent.resolve(originName));
} }
} catch (IOException e) { } catch (Throwable e) {
Log.w(TAG, "checkFd " + fdFile, e); Log.w(TAG, "checkFd " + fd, e);
} }
} }
@ -133,7 +136,7 @@ public class LogcatService implements Runnable {
} }
} }
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "GetProp: " + e + ": " + Arrays.toString(e.getStackTrace())); Log.e(TAG, "GetProp: ", e);
} }
}); });
t.start(); t.start();
@ -143,7 +146,7 @@ public class LogcatService implements Runnable {
writer.append(sb); writer.append(sb);
} }
} catch (IOException | InterruptedException | NullPointerException e) { } 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() { public File getVerboseLog() {
return verboseLog.toFile(); var path = fdToPath(verboseFd);
return path == null ? null : path.toFile();
} }
public File getModulesLog() { public File getModulesLog() {
return modulesLog.toFile(); var path = fdToPath(modulesFd);
return path == null ? null : path.toFile();
} }
public void checkLogFile() { public void checkLogFile() {
try { if (modulesFd == -1)
modulesLog.toRealPath();
} catch (IOException e) {
refresh(false); refresh(false);
} if (verboseFd == -1)
try {
verboseLog.toRealPath();
} catch (IOException e) {
refresh(true); refresh(true);
}
} }
} }

View File

@ -30,12 +30,20 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.ResourcesImpl; import android.content.res.ResourcesImpl;
import android.os.Binder; import android.os.Binder;
import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.UserHandle; 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.File;
import java.io.FileDescriptor;
import dalvik.system.VMRuntime;
public class HiddenApiBridge { public class HiddenApiBridge {
public static int AssetManager_addAssetPath(AssetManager am, String path) { public static int AssetManager_addAssetPath(AssetManager am, String path) {
@ -91,4 +99,18 @@ public class HiddenApiBridge {
public static CompatibilityInfo Resources_getCompatibilityInfo(Resources res) { public static CompatibilityInfo Resources_getCompatibilityInfo(Resources res) {
return res.getCompatibilityInfo(); 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();
}
} }

View File

@ -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;
}
}

View File

@ -0,0 +1,5 @@
package android.system;
public final class ErrnoException extends Exception {
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,9 @@
package android.util;
public final class MutableInt {
public int value;
public MutableInt(int value) {
this.value = value;
}
}