Erkin E
Erkin E

Reputation: 11

AOSP System Service JNI /sys/class/gpio/export Permission Denied

I added a system shared JNI library which tries to export/read/write GPIOs. In file 'build/make/target/product/base_system.mk'

PRODUCT_PACKAGES +=libarkgpiojni

I added my jni library folder to "/external" directory. Folder consists of Android.bp file, .c and .h file Contents of Android.bp file :

cc_library_shared {
    name: "libarkgpiojni",
    srcs: [
        "src/libarkgpiojni.c",
    ],
    header_libs: ["jni_headers"],
    shared_libs: [
        "liblog",
    ],
    cflags: [
        "-Wno-unused-parameter"
    ],
    export_include_dirs: [
        "src",
    ],
    system_shared_libs: [
        "libc",
    ],
}

In .c file I do open,read and write operations to "/sys/class/gpio/export", "/sys/class/gpio/gpio%d/direction", "/sys/class/gpio/gpio%d/value".

I added a system service to system server which uses my JNI library

Added .AIDL file to "frameworks/base/core/java/android/os/" Added service.c file and gpiocontrol.c file to "frameworks/base/core/java/com/android/server/" Service.c file uses gpiocontrol.c file to access my jni library. Service.c contents :

public class ArkGPIOControl {
    static 
    {
        System.loadLibrary("arkgpiojni"); 
    }                       
    public native int exportGpio(int pin);
    public native int setDirection(int pin, String direction);
    public native int setValue(int pin, boolean value);
}

I added my service manager .c file to "frameworks/base/core/java/android/app/" Modified "frameworks/base/services/java/com/android/server/SystemServer.java" file and added these lines to 'startOtherServices' function.

try
       {
            Slog.i(TAG, "***ArkGPIOService***");
            ServiceManager.addService(Context.ARKGPIO_SERVICE, new ArkGPIOService());
       } 
       catch (Throwable e)
       {
           Slog.e(TAG, "Failure starting ArkGPIO Service", e);
       }

I added these lines to "frameworks/base/core/java/android/app/SystemServiceRegistry.java"

registerService(Context.ARKGPIO_SERVICE, ArkGpioServiceManager.class,
                new CachedServiceFetcher<ArkGpioServiceManager>() {
            @Override
            public ArkGpioServiceManager createService (ContextImpl ctx) {
                IBinder binder = ServiceManager.getService(Context.ARKGPIO_SERVICE);
                IArkGpioService service = IArkGpioService.Stub.asInterface(binder);
                return ArkGpioServiceManager.getInstance();
           }});

I added this line to "frameworks/base/core/java/android/content/Context.java"

public static final String ARKGPIO_SERVICE = "arkgpio";

Added required sepolicies Added this line to "service_contexts" file under these directories "system/sepolicy/private", "system/sepolicy/prebuilts/api/31.0/private"

arkgpio         u:object_r:arkgpio_service:s0

Added this line to "untrusted_app.te" file under these directories "system/sepolicy/private", "system/sepolicy/prebuilts/api/31.0/private"

allow untrusted_app arkgpio_service:service_manager { find };

Added this line to "service.te" file under these directories "system/sepolicy/private", "system/sepolicy/prebuilts/api/31.0/private"

type arkgpio_service, system_api_service, system_server_service, service_manager_type;

Added this line to "system_server.te" file under these directories "system/sepolicy/private", "system/sepolicy/prebuilts/api/31.0/private"

allow arkgpio_service sysfs:file { read write getattr };
allow arkgpio_service sysfs:dir { read write getattr search };

than I run these commands

make update-api -j12
make sepolicy

than I build Android images.

Prepared a User App (GUI) to Access System Service Contents :

ArkGpioServiceManager arkGpioServiceManager = (ArkGpioServiceManager) getSystemService("arkgpio");
int turnOffLedResult = arkGpioServiceManager.turnOffLed();

Problem is : User app can access service manager, service manager can access system service, system service can access my jni library without any problem.

In my JNI library in this line :

fd = open("/sys/class/gpio/export", O_WRONLY);
    if (fd < 0)
    {
    LOGE("ExportGpio open failed: %s", strerror(errno));
        return -1;
    }

I'm getting "ExportGpio open failed: Permission denied."

Why?

I was expected I can access "/sys/class/gpio/export" from my jni library.

Update : If I connect ADB su shell and 'setenforce 0' 'permission denied' problem fixes temporarily.

Upvotes: 1

Views: 119

Answers (2)

satur9nine
satur9nine

Reputation: 15072

You may be mixing two distinct possible approaches:

  1. Introduce a new binderized HAL with a new SELinux context
  2. Add functionality to system server

If you did want to take the first approach then I suggest reading this page that has pretty much everything you need to create a new AOSP HAL: https://www.codeinsideout.com/blog/android/hal/hidl/binderized/#define-selinux-policy-for-hal-service

If you want to stick with your current approach then I suggest you clear out all your SELinux changes since you aren't introducing a new SELinux context, because your code is still running in system_server just via JNI.

At this point the quickest way to find the problem might be to just look at logcat and/or kernel logs (dmesg) to see if there is an SELinux denied message. Here is an example of what one looks like:

webview_zygote: type=1400 audit(0.0:9): avc: denied { getattr } for path="/data/data/com.android.webview" dev="mmcblk0p73" ino=24587 scontext=u:r:webview_zygote:s0 tcontext=u:object_r:app_data_file:s0:c43,c256,c512,c768 tclass=dir permissive=0

Specifically look for system_server and/or /sys/class/gpio/export in the path. This may directly inform you what SELinux rule you need to write.

You should also confirm the DAC permissions and MAC SELinux context of the file you wish to access. On an Android device I have I see the following but the same may not be true for yours:

$ ls -laZ /sys/class/gpio/export
--w------- 1 root root u:object_r:sysfs:s0 4096 2024-09-01 22:23 /sys/class/gpio/export

Note that system_server does not run as root so it won't even have standard Linux permissions to access that file. Confirm system_server user and context like so (could be different on your device but unlikely):

$ ps -AZ | grep system_server
u:r:system_server:s0           system        1391  1152 7293480 105128 SyS_epoll_wait      0 S system_server

To allow standard file access you would need to add the following or similar to an init.rc script:

on boot
    chown root system /sys/class/gpio/export
    chmod 0220 /sys/class/gpio/export

Usually system_server already has SELinux access to sysfs (assuming your export file is actually sysfs. Look through the rules for something like:

allow system_server sysfs:file rw_file_perms;
allow system_server sysfs:dir r_dir_perms;

Upvotes: 0

Rajat Gupta
Rajat Gupta

Reputation: 773

@ErkinE now that you mentioned it goes away when being SE Linux Permissive, it is best to assume there is another SEPolicy denial. Please refer to below link to fix this: https://source.android.com/docs/security/features/selinux/device-policy

You could look at tools like audit2allow to check for the exact denial.

Upvotes: 0

Related Questions