Skip to content

Commit 986abf9

Browse files
committed
Fix Remote Files feature from LSPosed Modern API Implementation
- Update Selinux policy of files on boot. - Fix Read-Write Issue - Sync sepolicy.rule file with LSPosed IT. This fixes issues for modules such as PlayStrong.
1 parent 4e4b573 commit 986abf9

File tree

4 files changed

+156
-4
lines changed

4 files changed

+156
-4
lines changed

daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.lsposed.lspd.models.PreLoadedApk;
4242
import org.lsposed.lspd.util.InstallerVerifier;
4343
import org.lsposed.lspd.util.Utils;
44+
import static org.lsposed.lspd.service.LSPModuleService.FILES_DIR;
4445

4546
import java.io.BufferedReader;
4647
import java.io.File;
@@ -60,6 +61,8 @@
6061
import java.nio.file.OpenOption;
6162
import java.nio.file.Path;
6263
import java.nio.file.Paths;
64+
import java.nio.file.DirectoryStream;
65+
import java.nio.file.FileVisitOption;
6366
import java.nio.file.SimpleFileVisitor;
6467
import java.nio.file.StandardOpenOption;
6568
import java.nio.file.attribute.BasicFileAttributes;
@@ -70,6 +73,7 @@
7073
import java.util.HashSet;
7174
import java.util.List;
7275
import java.util.Locale;
76+
import java.util.regex.Pattern;
7377
import java.util.zip.Deflater;
7478
import java.util.zip.ZipEntry;
7579
import java.util.zip.ZipFile;
@@ -455,19 +459,154 @@ static void ensureModuleFilePath(String path) throws RemoteException {
455459
static Path resolveModuleDir(String packageName, String dir, int userId, int uid) throws IOException {
456460
var path = modulePath.resolve(String.valueOf(userId)).resolve(packageName).resolve(dir).normalize();
457461
if (uid != -1) {
458-
if (path.toFile().mkdirs()) {
462+
var directory = path.toFile();
463+
464+
if (directory.mkdirs()) {
459465
try {
460466
SELinux.setFileContext(path.toString(), "u:object_r:xposed_file:s0");
461467
Os.chown(path.toString(), uid, uid);
462468
Os.chmod(path.toString(), 0755);
463469
} catch (ErrnoException e) {
464470
throw new IOException(e);
465471
}
472+
} else if (directory.isDirectory()) {
473+
try {
474+
Files.walkFileTree(path, new SimpleFileVisitor<>() {
475+
@Override
476+
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
477+
try {
478+
SELinux.setFileContext(dir.toString(), "u:object_r:xposed_file:s0");
479+
Os.chown(dir.toString(), uid, uid);
480+
Os.chmod(dir.toString(), 0755);
481+
} catch (Throwable e) {
482+
Log.w(TAG, "Failed to secure directory: " + dir + " " + Log.getStackTraceString(e));
483+
}
484+
return FileVisitResult.CONTINUE;
485+
}
486+
487+
@Override
488+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
489+
try {
490+
SELinux.setFileContext(file.toString(), "u:object_r:xposed_file:s0");
491+
Os.chown(file.toString(), uid, uid);
492+
Os.chmod(file.toString(), 0660);
493+
} catch (Throwable e) {
494+
Log.w(TAG, "Failed to secure file: " + file + " " + Log.getStackTraceString(e));
495+
}
496+
return FileVisitResult.CONTINUE;
497+
}
498+
});
499+
500+
SELinux.setFileContext(path.toString(), "u:object_r:xposed_file:s0");
501+
Os.chown(path.toString(), uid, uid);
502+
Os.chmod(path.toString(), 0755);
503+
} catch (Throwable e) {
504+
throw new IOException(e);
505+
}
466506
}
467507
}
468508
return path;
469509
}
470510

511+
static void fixModulesDirContext() throws IOException {
512+
var directory = modulePath.toFile();
513+
if (directory.mkdirs()) {
514+
try {
515+
SELinux.setFileContext(directory.toString(), "u:object_r:system_file:s0");
516+
Os.chown(directory.toString(), 0, 0);
517+
Os.chmod(directory.toString(), 0777);
518+
} catch (ErrnoException e) {
519+
throw new IOException(e);
520+
}
521+
} else if (directory.isDirectory()) {
522+
try {
523+
// Recursively set context, uid, gid and mode
524+
// to avoid issues caused by incorrect file context.
525+
// /data/adb/lspd/modules/<userId>/<packageName>/files/<files>
526+
// directory = /data/adb/lspd/modules
527+
// <userId> = u:object_r:system_file:s0 777 root root
528+
// <packageName> = u:object_r:system_file:s0 777 root root
529+
// files = u:object_r:xposed_file:s0 755 root root
530+
// <files> = u:object_r:xposed_file:s0 660 root root
531+
// Recursively walk through all subdirectories
532+
Files.walkFileTree(modulePath, new SimpleFileVisitor<Path>() {
533+
@Override
534+
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
535+
try {
536+
String pathStr = dir.toString();
537+
538+
// Get relative path from modulePath
539+
Path relative = modulePath.relativize(dir);
540+
String[] parts = relative.toString().split(Pattern.quote(File.separator));
541+
542+
if (parts.length == 1) {
543+
// <userId> dir (e.g., "0")
544+
SELinux.setFileContext(pathStr, "u:object_r:system_file:s0");
545+
Os.chown(pathStr, 0, 0);
546+
Os.chmod(pathStr, 0777);
547+
} else if (parts.length == 2) {
548+
// <packageName> dir (e.g., "com.example.module")
549+
SELinux.setFileContext(pathStr, "u:object_r:system_file:s0");
550+
Os.chown(pathStr, 0, 0);
551+
Os.chmod(pathStr, 0777);
552+
} else if (parts.length >= 3 && parts[2].equals(FILES_DIR)) {
553+
// Inside `files/` or deeper
554+
if (parts.length == 3) {
555+
// The `files` directory itself
556+
SELinux.setFileContext(pathStr, "u:object_r:xposed_file:s0");
557+
Os.chown(pathStr, 0, 0);
558+
Os.chmod(pathStr, 0755);
559+
} else {
560+
// Subdirectories or files under `files/`
561+
SELinux.setFileContext(pathStr, "u:object_r:xposed_file:s0");
562+
Os.chown(pathStr, 0, 0);
563+
// Dirs: 0755, Files: 0660
564+
if (Files.isDirectory(dir)) {
565+
Os.chmod(pathStr, 0755);
566+
} else {
567+
Os.chmod(pathStr, 0660);
568+
}
569+
}
570+
} else {
571+
// Other dirs (not in files/) — keep system context
572+
SELinux.setFileContext(pathStr, "u:object_r:system_file:s0");
573+
Os.chown(pathStr, 0, 0);
574+
Os.chmod(pathStr, 0777);
575+
}
576+
} catch (Exception e) {
577+
Log.w(TAG, "Failed to secure directory: " + dir + " " + Log.getStackTraceString(e));
578+
}
579+
return FileVisitResult.CONTINUE;
580+
}
581+
582+
@Override
583+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
584+
try {
585+
String pathStr = file.toString();
586+
Path relative = modulePath.relativize(file);
587+
String[] parts = relative.toString().split(Pattern.quote(File.separator));
588+
589+
if (parts.length >= 3 && parts[2].equals("files")) {
590+
SELinux.setFileContext(pathStr, "u:object_r:xposed_file:s0");
591+
Os.chown(pathStr, 0, 0);
592+
Os.chmod(pathStr, 0660);
593+
} else {
594+
SELinux.setFileContext(pathStr, "u:object_r:system_file:s0");
595+
Os.chown(pathStr, 0, 0);
596+
Os.chmod(pathStr, 0644);
597+
}
598+
} catch (Exception e) {
599+
Log.w(TAG, "Failed to secure file: " + file + " " + Log.getStackTraceString(e));
600+
}
601+
return FileVisitResult.CONTINUE;
602+
}
603+
});
604+
} catch (Throwable e) {
605+
throw new IOException(e);
606+
}
607+
}
608+
}
609+
471610
private static class FileLocker {
472611
private final FileChannel lockChannel;
473612
private final FileLock locker;

daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import android.os.RemoteException;
1010
import android.util.Log;
1111

12+
import java.io.File;
13+
import java.io.IOException;
14+
1215
import org.lsposed.lspd.models.Module;
1316

1417
import java.util.Map;
@@ -57,7 +60,7 @@ public ParcelFileDescriptor openRemoteFile(String path) throws RemoteException {
5760
var userId = Binder.getCallingUid() / PER_USER_RANGE;
5861
try {
5962
var dir = ConfigFileManager.resolveModuleDir(mPackageName, FILES_DIR, userId, -1);
60-
return ParcelFileDescriptor.open(dir.resolve(path).toFile(), ParcelFileDescriptor.MODE_READ_ONLY);
63+
return ParcelFileDescriptor.open(dir.resolve(path).toFile(), (ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE));
6164
} catch (Throwable e) {
6265
throw new RemoteException(e.getMessage());
6366
}

daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141

4242
import org.lsposed.daemon.BuildConfig;
4343
import org.lsposed.lspd.util.FakeContext;
44+
import static org.lsposed.lspd.service.LSPModuleService.FILES_DIR;
4445

4546
import java.io.File;
47+
import java.io.IOException;
4648
import java.lang.AbstractMethodError;
4749
import java.lang.Class;
4850
import java.lang.reflect.Field;
@@ -132,6 +134,13 @@ public static void start(String[] args) {
132134
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
133135
Looper.prepareMainLooper();
134136

137+
// Ensure the modules directory has correct SELinux context
138+
try {
139+
ConfigFileManager.fixModulesDirContext();
140+
} catch (IOException e) {
141+
throw new RuntimeException("Fix Modules dir context failed", e);
142+
}
143+
135144

136145
mainService = new LSPosedService();
137146
applicationService = new LSPApplicationService();
@@ -180,7 +189,7 @@ public void onSystemServerDied() {
180189
managerService.onSystemServerDied();
181190
}
182191
});
183-
192+
184193
// Force logging on boot, now let's see if we need to stop logging
185194
if (!configManager.verboseLog()) {
186195
logcatService.stopVerbose();

magisk-loader/magisk_module/sepolicy.rule

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ allow shell shell dir write
44

55
type xposed_file file_type
66
typeattribute xposed_file mlstrustedobject
7-
allow {dex2oat installd isolated_app shell} xposed_file {file dir} *
7+
allow domain xposed_file {file dir} *
88

99
allow dex2oat unlabeled file *
1010

1111
type xposed_data file_type
1212
typeattribute xposed_data mlstrustedobject
1313
allow * xposed_data {file dir} *
14+
allow system_server apk_data_file file execute

0 commit comments

Comments
 (0)