#include "selinux/android.h"
#include <errno.h>
#include <memory>
+#include <atomic>
#include <nativehelper/ScopedLocalRef.h>
#include <nativehelper/ScopedUtfChars.h>
namespace android {
+namespace {
+std::atomic<selabel_handle*> sehandle{nullptr};
+
+selabel_handle* GetSELabelHandle() {
+ selabel_handle* h = sehandle.load();
+ if (h != nullptr) {
+ return h;
+ }
+
+ h = selinux_android_file_context_handle();
+ selabel_handle* expected = nullptr;
+ if (!sehandle.compare_exchange_strong(expected, h)) {
+ selabel_close(h);
+ return sehandle.load();
+ }
+ return h;
+}
+
+}
struct SecurityContext_Delete {
void operator()(security_context_t p) const {
return (security_getenforce() == 1) ? true : false;
}
+static jstring fileSelabelLookup(JNIEnv* env, jobject, jstring pathStr) {
+ if (isSELinuxDisabled) {
+ ALOGE("fileSelabelLookup => SELinux is disabled");
+ return NULL;
+ }
+
+ if (pathStr == NULL) {
+ ALOGE("fileSelabelLookup => got null path.");
+ jniThrowNullPointerException(
+ env, "Trying to get security context of a null path.");
+ return NULL;
+ }
+
+ ScopedUtfChars path(env, pathStr);
+ const char* path_c_str = path.c_str();
+ if (path_c_str == NULL) {
+ ALOGE("fileSelabelLookup => Got null path");
+ jniThrowNullPointerException(
+ env, "Trying to get security context of a null path.");
+ return NULL;
+ }
+
+ auto* selabel_handle = GetSELabelHandle();
+ if (selabel_handle == NULL) {
+ ALOGE("fileSelabelLookup => Failed to get SEHandle");
+ return NULL;
+ }
+
+ security_context_t tmp = NULL;
+ if (selabel_lookup(selabel_handle, &tmp, path_c_str, S_IFREG) != 0) {
+ ALOGE("fileSelabelLookup => selabel_lookup for %s failed: %d", path_c_str, errno);
+ return NULL;
+ }
+
+ Unique_SecurityContext context(tmp);
+ return env->NewStringUTF(context.get());
+}
+
static jstring getFdConInner(JNIEnv *env, jobject fileDescriptor, bool isSocket) {
if (isSELinuxDisabled) {
return NULL;
{ "native_restorecon" , "(Ljava/lang/String;I)Z" , (void*)native_restorecon},
{ "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon },
{ "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon },
+ { "fileSelabelLookup" , "(Ljava/lang/String;)Ljava/lang/String;" , (void*)fileSelabelLookup},
};
static int log_callback(int type, const char *fmt, ...) {
import android.os.PatternMatcher;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.SELinux;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
}
void writePackageListLPr(int creatingUserId) {
+ String filename = mPackageListFilename.getAbsolutePath();
+ String ctx = SELinux.fileSelabelLookup(filename);
+ if (ctx == null) {
+ Slog.wtf(TAG, "Failed to get SELinux context for " +
+ mPackageListFilename.getAbsolutePath());
+ }
+
+ if (!SELinux.setFSCreateContext(ctx)) {
+ Slog.wtf(TAG, "Failed to set packages.list SELinux context");
+ }
+ try {
+ writePackageListLPrInternal(creatingUserId);
+ } finally {
+ SELinux.setFSCreateContext(null);
+ }
+ }
+
+ private void writePackageListLPrInternal(int creatingUserId) {
// Only derive GIDs for active users (not dying)
final List<UserInfo> users = UserManagerService.getInstance().getUsers(true);
int[] userIds = new int[users.size()];