Problemas de permisos que deben resolverse cuando la aplicación de Android accede a los nodos del puerto serie

Este artículo es una reproducción de la contribución de Le Xiaodi contra compañeros de clase. El artículo comparte principalmente cómo implementar la autorización subyacente del sistema. ¡Creo que será útil para todos!

Direccion original:

https://juejin.cn/post/7234795667478003770

La capa de aplicación a menudo necesita lidiar con nodos de controlador al desarrollar funciones de puerto serie. Cuando agregamos un nuevo dispositivo de hardware, generalmente se proporcionará el nodo correspondiente para que acceda la capa superior (marco, aplicación).

Cómo acceder al nodo

  • Java E/S

  • gato de concha adb

Tomando el nodo USB como ejemplo, su ruta es /sys/devices/platform/soc/a600000.ssusb/mode, generalmente usamos el flujo IO estándar de Java

public static final String NODE_PATH = "/sys/devices/platform/soc/a600000.ssusb/mode";

    public void readNode(View view) {
        String result = FileUtils.readFileByLines(NODE_PATH);
        tvShow.setText(result);
        Log.d(TAG, "node data:"+result);
    }

    public static String readFileByLines(String fileName) {
        BufferedReader bufferedReader = null;
        FileReader fileReader = null;
        try {
            File file = new File(fileName);
            if (!file.exists()) {
                return "文件不存在";
            }
            fileReader = new FileReader(file);
            bufferedReader = new BufferedReader(fileReader);
            String string;
            StringBuffer sb = new StringBuffer();
            while ((string = bufferedReader.readLine()) != null) {
                sb.append(string);
            }
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

O ingrese al adb shell y acceda directamente al nombre del nodo correspondiente para acceder a los datos del nodo.

8e597bc715e37ae435dca49c69f4c3fd.jpeg

Problema de permisos

Pero el acceso directo definitivamente no es posible y se informará un error de permiso.

872f10256fce75ecfb7178b4fcce63ab.png

Entonces, el núcleo para lograr el acceso de la capa superior a los nodos subyacentes es lidiar con los problemas de permisos, que incluyen principalmente el procesamiento de permisos en dos direcciones:

  • Permisos de Android

  • Permisos de lectura y escritura para el propio archivo de nodo

En primer lugar, la aplicación pertenece a la capa de aplicación y el nodo del controlador pertenece a la capa del núcleo. Debido a las limitaciones de SEAndroid, la capa de aplicación no puede acceder a los archivos del nodo del controlador de la capa del núcleo. Debemos entender esto bien. Si el La capa de aplicación puede acceder fácilmente al kernel, entonces Android es demasiado inseguro. En este momento, las restricciones de permisos de SEAndroid deben modificarse para que las aplicaciones de terceros también puedan acceder al archivo del nodo del kernel.

Introducción a SEAndroid

Antes de resolver este problema de permisos de SEAndroid, primero comprendamos qué es SEAndroid, aquí lo presentaré brevemente en un lenguaje fácil de entender:

Antes de comprender SEAndroid, primero debe comprender SELinux. SELinux es un módulo de seguridad de control de acceso obligatorio extendido para Linux desarrollado por la NSA y la SCC de EE. UU. SEAndroid es equivalente a una versión personalizada de SELinux, que se utiliza especialmente para la gestión de seguridad de los sistemas Android. Antes de Android 4.4, los permisos del proceso eran consistentes con los permisos del usuario actual, es decir, si inicio un proceso como usuario root, entonces el proceso tiene permisos de root y puede hacer lo que quiera. Este modo es llamado DAC (Control de acceso discrecional). Obviamente, DAC era demasiado flojo, por lo que se agregó SEAndroid. Cualquier proceso que quiera hacer algo debe recibir permisos en el "Archivo de política de seguridad", este es el modo MAC (control de acceso obligatorio).

De hecho, el sistema Android actual utiliza los modos DAC y MAC. El sistema primero realizará una verificación del DAC. Si falla, la operación fallará directamente. Después de pasar la verificación DAC, realice la verificación MAC.

En cuanto a los archivos de políticas de seguridad MAC, SELinux tiene un conjunto de reglas para escribir, que se denomina lenguaje de políticas SELinux. Para conocer las reglas básicas de este idioma, consulte este artículo "Sistema Android SELinux (SEAndroid)" (https://blog.csdn.net/tq501501/article/details/118214159).

Manejo de permisos

Para resolver el problema de permisos, generalmente primero desactive la verificación de SELinux y, al mismo tiempo, establezca los permisos de lectura y escritura del archivo del nodo de destino al máximo y ejecute

adb root
adb shell setenforce 0
adb shell chmod 777 /sys/devices/platform/soc/a600000.ssusb/mode

Vea si puede acceder con éxito al nodo. Si tiene éxito, significa que efectivamente se trata de un problema de permisos. Luego tome el registro logcat (marco) y el registro dmesg (kernel) respectivamente, y busque la palabra clave avc para obtener los registros de errores relacionados. a los permisos.

implementar

# 抓取logcat日志
adb logcat | findstr avc > E://logcat.txt
# 抓取dmesg日志
adb shell dmesg | findstr avc > E://dmesg.txt

Los resultados del registro capturados son los siguientes

[  312.961648] type=1400 audit(1684478793.923:22): avc: denied { read } for comm=".jason.nodetest" name="soc" dev="sysfs" ino=10272 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:sysfs:s0 tclass=dir permissive=0
[  312.962343] type=1400 audit(1684478793.923:23): avc: denied { read } for comm=".jason.nodetest" name="soc" dev="sysfs" ino=10272 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:sysfs:s0 tclass=dir permissive=0
[  314.145472] type=1400 audit(1684478795.107:24): avc: denied { read } for comm=".jason.nodetest" name="mode" dev="sysfs" ino=29874 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:vendor_sysfs_usb_device:s0 tclass=file permissive=0
[  314.886338] type=1400 audit(1684478795.847:25): avc: denied { write } for comm=".jason.nodetest" name="mode" dev="sysfs" ino=29874 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:vendor_sysfs_usb_device:s0 tclass=file permissive=0
[  315.523664] type=1400 audit(1684478796.483:26): avc: denied { write } for comm=".jason.nodetest" name="mode" dev="sysfs" ino=29874 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:vendor_sysfs_usb_device:s0 tclass=file permissive=0
[  315.945379] type=1400 audit(1684478796.907:27): avc: denied { write } for comm=".jason.nodetest" name="mode" dev="sysfs" ino=29874 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:vendor_sysfs_usb_device:s0 tclass=file permissive=0
[  316.294456] type=1400 audit(1684478797.255:28): avc: denied { read } for comm=".jason.nodetest" name="mode" dev="sysfs" ino=29874 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:vendor_sysfs_usb_device:s0 tclass=file permissive=0

Analicemos uno de los registros en detalle.

[  314.145472] type=1400 audit(1684478795.107:24): avc: denied { read } for comm=".jason.nodetest" name="mode" dev="sysfs" ino=29874 scontext=u:r:untrusted_app:s0:c66,c256,c522,c768 tcontext=u:object_r:vendor_sysfs_usb_device:s0 tclass=file permissive=0
  • avc significa que este es un error relacionado con SELinux

  • denegado {leer} indica falta de permiso de lectura

  • comm=".jason.nodetest" indica qué proceso está accediendo

  • name="mode" indica el archivo de destino

  • dev="sysfs" indica el tipo de archivo del archivo de destino al que accederá el proceso .jason.nodetest

  • scontext=u:r:untrusted_app indica el tipo de proceso de acceso, aquí indica una aplicación de terceros

  • tcontext=u:object_r:vendor_sysfs_usb_device:s0 indica el nombre del espacio del archivo de destino

Traducido, una aplicación de terceros necesita permiso de lectura para acceder al archivo de modo en el espacio seller_sysfs_usb_device.

Bien, ahora que conocemos la causa del error, agreguemos permisos.

Paso 1: busque la declaración del archivo del nodo de destino en el archivo genfs_contexts

genfscon sysfs /devices/soc/a800000.ssusb/a800000.dwc3/xhci-hcd.0.auto/usb1 u:object_r:vendor_sysfs_usb_device:s0
genfscon sysfs /devices/soc/a800000.ssusb/a800000.dwc3/xhci-hcd.0.auto/usb2 u:object_r:vendor_sysfs_usb_device:s0
genfscon sysfs /devices/platform/soc/a600000.ssusb/mode                 u:object_r:vendor_sysfs_usb_device:s0
# 目标节点
genfscon sysfs /devices/platform/soc/a800000.ssusb/mode                 u:object_r:vendor_sysfs_usb_device:s0

Se descubrió que, de hecho, está definido en el espacio proveedor_sysfs_usb_device, y otros nodos también están definidos en este espacio.

Paso 2: busque la definición de tipo de espacio seller_sysfs_usb_device en el archivo file.te

type vendor_sysfs_usb_device, sysfs_type, fs_type;

Los tipos son sysfs y fs

Paso 3: agregue el permiso de la aplicación de terceros para acceder al espacio seller_sysfs_usb_device en el archivo untrusted_app_25.te

allow untrusted_app vendor_sysfs_usb_device:file rw_file_perms;

En cuanto a cómo escribir esta sintaxis, lo mencioné antes en otro artículo "Transplantación de GNSS en la plataforma Qualcomm Android 11" (https://juejin.cn/post/7225152932676927543), y lo publicaré nuevamente a continuación.

2f6a908d4b7ab3ff5ae8ed37d766dca9.png

Si le resulta difícil recordar, también puede utilizar la herramienta audit2allow proporcionada por Linux para analizar y generar automáticamente

audit2allow -i dmesg.txt

3c92ff59019a89dacb8888c0da6bd96c.jpeg

Configure directamente el comando te generado en el archivo te

Después de la configuración, asegúrese de recordar que la política de seguridad no puede entrar en conflicto con neverallow. Verificamos las reglas de neverallow y descubrimos que SEAndroid estipula que las aplicaciones de terceros no pueden acceder a archivos de tipo sysfs y fs.

# Do not allow any write access to files in /sys
# 第三方app不允许访问sysfs类型文件
neverallow all_untrusted_apps sysfs_type:file { no_w_file_perms no_x_file_perms };

# Apps may never access the default sysfs label.
# 第三方app不允许访问sysfs类型文件
neverallow all_untrusted_apps sysfs:file no_rw_file_perms;

neverallow { all_untrusted_apps -mediaprovider } {
# 不允许访问fs类型文件
  fs_type
  -sdcard_type
  file_type
  -app_data_file            # The apps sandbox itself
  -privapp_data_file
  -app_exec_data_file       # stored within the app sandbox directory
  -media_rw_data_file       # Internal storage. Known that apps can
                            # leave artfacts here after uninstall.
  -user_profile_data_file   # Access to profile files
  userdebug_or_eng(`
    -method_trace_data_file # only on ro.debuggable=1
    -coredump_file          # userdebug/eng only
  ')
}:dir_file_class_set { create unlink };

Eliminaremos estos neverallows. Tenga en cuenta que system/sepolicy/private/app_neverallows.te y system/sepolicy/prebuilts/api/30.0/private/app_neverallows.te deben eliminarse. Estos dos archivos deben ser consistentes; de lo contrario, se generará un error de compilación. informó.

En este punto, podemos completar la verificación. En este momento, encontraremos que no hay ningún problema al leer el nodo, pero todavía hay un problema de permiso al escribir datos en el nodo. Esto se debe a que el archivo del nodo en sí solo ha leído permiso, por lo que es necesario otorgar el archivo de nodo después de que se inicie el sistema. Agregue permiso de escritura bajo la condición de inicio en system/core/rootdir/init.rc.

chmod 0777 /sys/devices/platform/soc/a600000.ssusb/mode

Al compilar y ejecutar, se seguirá informando un error de permiso, porque el propietario de este archivo de nodo es root.

El propietario del proceso de inicio es el sistema. No es suficiente que el propietario del sistema modifique directamente los permisos de archivo del propietario raíz. Es necesario agregar permisos de acceso a seller_sysfs_usb_device al proceso de inicio. Agregue esto en el archivo init.te.

allow init vendor_sysfs_usb_device:file setattr;

También defina seller_sysfs_usb_device como tipo de objeto mlstrusted

type vendor_sysfs_usb_device, sysfs_type, fs_type, mlstrustedobject;

En este momento, vuelva a compilar y verificar, y la aplicación de terceros podrá leer y escribir directamente el nodo del controlador.

Leer nodo

edbdeb8d8f58f735733aa36ad6cef1e7.png

escribir nodo

713d1126d13423121a13d9fab753225d.png

Resumir

Este artículo puede hacer que los amigos que están desarrollando Android se den cuenta de que el hardware subyacente debe ser accesible a la capa superior y cómo lidiar con los problemas de permisos. Los puntos de conocimiento relacionados con SELinux son muy abstractos y difíciles de entender para los principiantes, pero siempre que lidiar con algunos relacionados Puedes descubrir de inmediato lo que está pasando.

Sígueme para obtener más conocimientos o contribuir con artículos.

c6d2a8404df76b9683733af1b2893682.jpeg

8fe9aa38c8e60279e47594a42ad10d53.jpeg

Supongo que te gusta

Origin blog.csdn.net/c6E5UlI1N/article/details/132632518
Recomendado
Clasificación