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 "symbol_cache.h"
#include <linux/fs.h>
#include <fcntl.h>
static_assert(FS_IOC_SETFLAGS == LP_SELECT(0x40046602, 0x40086602));
namespace lspd {
extern int *allowUnload;

View File

@ -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,12 +147,26 @@ 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)) {
if (chattr0(logDirPath)) {
deleteFolderIfExists(oldLogDirPath);
Files.move(logDirPath, oldLogDirPath);
}
}
Files.createDirectories(logDirPath);
} catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e));

View File

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

View File

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

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