diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java index e8e6943d..6e72014f 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java @@ -70,6 +70,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.stream.Stream; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -454,20 +455,38 @@ public class ConfigFileManager { static Path resolveModuleDir(String packageName, String dir, int userId, int uid) throws IOException { var path = modulePath.resolve(String.valueOf(userId)).resolve(packageName).resolve(dir).normalize(); - if (uid != -1) { - if (path.toFile().mkdirs()) { - try { - SELinux.setFileContext(path.toString(), "u:object_r:xposed_data:s0"); - Os.chown(path.toString(), uid, uid); - Os.chmod(path.toString(), 0755); - } catch (ErrnoException e) { - throw new IOException(e); - } + // Ensure the directory and any necessary parent directories exist. + path.toFile().mkdirs(); + + if (SELinux.getFileContext(path.toString()) != "u:object_r:xposed_data:s0") { + // SELinux label could be reset after a reboot. + try { + setSelinuxContextRecursive(path, "u:object_r:xposed_data:s0"); + Os.chown(path.toString(), uid, uid); + Os.chmod(path.toString(), 0755); + } catch (ErrnoException e) { + throw new IOException(e); } } return path; } + private static void setSelinuxContextRecursive(Path path, String context) throws IOException { + try { + SELinux.setFileContext(path.toString(), context); + + if (Files.isDirectory(path)) { + try (Stream stream = Files.list(path)) { + for (Path entry : (Iterable) stream::iterator) { + setSelinuxContextRecursive(entry, context); + } + } + } + } catch (Exception e) { + throw new IOException("Failed to recursively set SELinux context for " + path, e); + } + } + private static class FileLocker { private final FileChannel lockChannel; private final FileLock locker; diff --git a/hiddenapi/stubs/src/main/java/android/os/SELinux.java b/hiddenapi/stubs/src/main/java/android/os/SELinux.java index 991a84fe..2119bd29 100644 --- a/hiddenapi/stubs/src/main/java/android/os/SELinux.java +++ b/hiddenapi/stubs/src/main/java/android/os/SELinux.java @@ -9,6 +9,10 @@ public class SELinux { throw new UnsupportedOperationException("Stub"); } + public static String getFileContext(String path) { + throw new UnsupportedOperationException("Stub"); + } + public static boolean setFSCreateContext(String context){ throw new UnsupportedOperationException("Stub"); }