int main(int argc, char *argv) {
std::string file { "/var/log/messages" };
FILE f { nullptr };
while (1) {
f = fopen(file.c_str(), "w");
if (f == nullptr) {
std::printf("open file error\n");
exit(1);
}
std::printf("Wait for another turn!\n");
std::this_thread::sleep_for(std::chrono::seconds(5));
fclose(f);
系统集成商可以将特定于功能的平台 HAL 接口(如 HVAC)与特定于技术的网络接口(如 CAN 总线)连接,以实现车载 HAL 模块。典型的实现可能包括运行专有实时操作系统 (RTOS) 的专用微控制器单元 (MCU),该微控制器单元用于 CAN 总线访问或类似操作,可通过串行链路连接到运行 Android Automotive 的 CPU。除了专用 MCU,还可以将总线访问作为虚拟 CPU 来实现。只要实现符合车载 HAL 的接口要求,每个合作伙伴都可以选择适合硬件的架构。
1. 背景
在具有操作系统的环境中,访问控制是必备的一个元素,对维护系统的安全性和稳定性起着至关重要的作用。访问控制可以为操作系统提供:
2. 访问控制模型
目前,有多种访问控制模型和策略来加强安全性和管理对资源的访问,常用的主要有:自主访问控制(Discretionary Access Control, DAC)、强制访问控制(Mandatory Access Control, MAC)、基于角色的访问控制(Role-Based Access Control, RBAC)和基于属性的访问控制(Attribute-Based Access Control, ABAC)。
2.1 DAC
自主访问控制目前是Linux的默认的访问控制模型,也是一种灵活的访问控制模型。它将访问权限的控制权交由对象的所有者自行决定对它的访问权限。所有者将访问权限划分为读、写和执行三种,同时将访问它的对象划分为所有者,组和其他三种,通过这两种方式的结合,得出一个对象的访问控制:
但这种访问控制模型在很大程度上依赖于对象的所有者的责任和其他访问对象的诚信上,并不是一个很理想的访问控制模型。
2.2 MAC
MAC是高安全环境中使用的严格访问控制模型,它根据预定义的安全策略,将进程划分为不同的主体,将资源划分为客体,并为主体访问客体制定了不同的标签和敏感级别,访问决策根据主体、客体以及不同的标签来做出访问策略,主体只能访问等于或者低于其指定的级别的对象。 主体、客体和控制策略需要满足基本的安全策略:
2.3 RBAC是一种使用较为广泛的访问控制模型,它为用户分配角色并根据角色授予权限,访问决策是根据用户的角色而不是个人身份来做出的。常见的HR系统和行政管理系统大多都是基于RBAC建立访问控制策略。
2.4 ABAC
ABAC通过动态计算一个或者一组属性是否满足规则来确定访问权限。访问控制规则定义条件和操作,根据条件的满足情况指定允许或拒绝哪些用户访问特定资源。 RBAC 允许根据业务需求灵活地定义访问控制策略。 属性通常来说分为四类:
3. SELinux
3.1 Overview of SELinux
SELinux最初是由美国国家安全局NSA开发的一个项目,它并不是Linux的一部分,而是作为一个可装载模块的形式存在,NSA为此开发了一个Linux Security Module的框架。在Linux Security Module的框架下,apparmor、tomoyo和smack等框架得以开发并hook进入Linux内核。
在Linux中使能SELinux并不是SELinux代替原有的DAC进行访问权限控制,而是在原有的DAC的访问控制的基础上,再增加一个MAC的访问控制策略,具体可以参考:
一个进程要访问一个资源,会调用一个系统调用,由用户态陷入内核态,在做一些基础检查且通过后,会先检查Linux的DAC规则,如果此次访问不符合DAC的访问控制策略,就会直接返回;只有通过了DAC访问控制策略后,才会由LSM的钩子调用SELinux访问控制策略做检查。因此使能SELinux的系统,并不是说SELinux将代替DAC对访问进行决策。 SELinux有三个工作模式:
policycoreutils
SELinux还定义了SELinux的工作策略:
3.2 SELinux的核心元素
SELinux的核心元素可以由上图给出:
主体(Subject):主体是一次访问控制中请求访问的一方,在Linux系统中则是一个进程,主体请求对客体的访问一般就是一个进程对系统资源的访问。
客体管理者(Object manager):客体管理者知道主体要访问的客体以及对应的访问曹组,它能够管理主体对客体的访问操作(通过查询访问控制向量表)。
安全服务器(Security server):安全服务器存储着配置好的访问控制策略,因此可以决定主体对客体的访问是否允许。
访问控制策略:通过内核的策略语言读取用户配置的访问策略
访问控制向量表:为了改善系统性能,Linux会缓存一部分常访问的策略,存储在AVC中。### 3.2.1 安全上下文 SELinux中,每一个主体(Subject)和客体(Object)都有自己的安全上下文,安全上下文的格式为:
安全上下文也被成为安全标签,上述的安全标签包含了几个关键信息:
SELinux用户(user):SELinux用户和我们常说的Linux用户类似,但是SELinux用户一般是一些Linux用户的集合或者组,举例来说,Linux的普通用户可以归结为user_u, 而管理员用户则是staff_u。有一个特别的SELinux用户: system_u,这个SELinux用户无法绑定到任何一个Linux用户。
角色(Role): 为了更方便进行访问控制,SELinux利用了RBAC的概念,基于角色的访问控制。这个特性允许SELinux用户和一个或者多个角色绑定,而角色又可以属于不同的域。基于此,SELinux的控制策略可以基于域或角色制定。
类型强制(Type Enforcement): 安全上下文的第三个元素是类型强制。在SELinux中,所有的主体(subject)和客体(Object)都有对应的类型。有了类型强制,SELinux可以基于类型进行访问控制,例如:
这条规则表明允许类别为unconfined_t的进程迁移到ext_gateway_t的类型。
3.2.2 客体(Object)
SELinux中的主体(Subject)只能是进程,但是客体有多重可能,它可以是一个进程,也可以是文件等。但是每一个客体都包含了一个类别标识(class identifier),这个类别标签标识这个客体是一个文件、套接字或者其他。这个类别标识还带有权限集合,SELinux中称为访问向量(Access Vector, AV),访问向量描述了这个客体可以执行的动作(读、写或者发送等),同时,如上所述,客体还包含了安全上下文。我们以SELinux的配置文件举例:
/etc/selinux/config
首先他是一个文件,因此类别标识为:file
。安全上下文为:system_u:object_t:selinux_config_t
,访问向量:read, write, append
。 这里举例一条规则,允许unconfined_t类型的进程对selinux_config_t类型的file类别的客体进行读取和写:这是一个allow规则,他的规则定义如下:
rule_name | source_type | target_type : class | permission
allow kernel_t filesystem_t : filesystem mount;
traceroute_t {port_type -port_t}:tcp_socket name_bind;
auditallow ada_t self:process execstack; allow ada_t self:process execstack;
allow appdomain test_data_t:dir search; neverallow app1 test_data_t:dir search;
4. How to enable SELinux on ubuntu 20.04
为了在Ubuntu20.04上使用SELinux,首先需要安装依赖:
安装完依赖后,便可以激活SELinux:
激活后,需要重启才能启用SELinux,启动后可以看到系统在对资源打标签,也就是安全上下文的计算:
启动后,便可以看到所有文件都被打上了标签:
进程也都被打上了标签:
4.1 规则设计
系统的规则位于
/etc/selinux/default
文件夹中,所有规则会被编译存储于/etc/selinux/default/policy
的二进制文件中,用户不能通过修改二进制的方式来增加规则。如果用户要增加规则,需要通过其他方式进行,这里以新增一个app的方式,讲述如何为系统的进程编写规则。int main(int argc, char *argv) { std::string file { "/var/log/messages" }; FILE f { nullptr };
}
return 0; }
output:
然后执行selinux_app,再查看selinux是否有告警(此时应保证
/var/log/messages
存在,且selinux_app有权限访问,另外,当前的selinux的模式为permissive)... type=AVC msg=audit(1699435224.165:573): avc: denied { execmem } for pid=1745 comm="gjs" scontext=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 tcontext=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 tclass=process permissive=1
time->Wed Nov 8 01:20:31 2023 type=AVC msg=audit(1699435231.529:575): avc: denied { search } for pid=386 comm="systemd-journal" name="user" dev="tmpfs" ino=1023 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:user_runtime_root_t:s0 tclass=dir permissive=1
执行后,可以发现生成了几个文件:
其中,te文件是类型强制文件,里面描述了对selinux_app的类型设置;if文件为接口文件;fc描述了是文件上下文文件;sh脚本是要运行进行规则生成的:
此时再执行selinux_app,可以看到审计日志里有了记录:
sudo ausearch -m AVC -ts recent
type=AVC msg=audit(1699435247.640:590): avc: denied { open } for pid=1977 comm="selinux_app" path="/var/log/messages" dev="sda5" ino=4336677 scontext=system_u:system_r:selinux_app_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=file permissive=1 type=AVC msg=audit(1699435247.640:590): avc: denied { write } for pid=1977 comm="selinux_app" name="messages" dev="sda5" ino=4336677 scontext=system_u:system_r:selinux_app_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=file permissive=1 type=AVC msg=audit(1699435247.640:590): avc: denied { search } for pid=1977 comm="selinux_app" name="log" dev="sda5" ino=4325384 scontext=system_u:system_r:selinux_app_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=dir permissive=1
设置允许规则 首先查看文件夹
/var
,/var/log/
和文件`/var/log/messages``的安全上下文:因此,要确保selinux_app_t对var_t、var_log_t文件夹和var_log_t文件有读写权限,由于打开文件还需要ioctl的权限,因此,要补充:
但是,由于selinux_app.te中没有声明var_t和var_log_t类型,因此需要在文件开始处增加声明:
最终的selinux_app.te的增量为:
######################################## #
Declarations
#
type selinux_app_t; type selinux_app_exec_t; +type var_t; +type var_log_t; init_daemon_domain(selinux_app_t, selinux_app_exec_t)
permissive selinux_app_t;
######################################## #
selinux_app local policy
# allow selinux_app_t self:fifo_file rw_fifo_file_perms; allow selinux_app_t self:unix_stream_socket create_stream_socket_perms;
+allow selinux_app_t var_t:dir {open search getattr}; +allow selinux_app_t var_log_t:dir {getattr search open read lock ioctl}; +allow selinux_app_t var_log_t:file { open {getattr write append lock ioctl} };
domain_use_interactive_fds(selinux_app_t)
files_read_etc_files(selinux_app_t)
miscfiles_read_localization(selinux_app_t)
再访问:
此时除了系统的一些告警外,没有任何关于selinux_app的告警日志记录了:
5. SELinux and Android Automotive
当前的智能汽车中,座舱域控制器为座舱提供了许多高阶娱乐功能,例如:座舱游戏、座舱音乐、座舱电影等,这些功能的引入也对座舱的基础设施提出了更高的要求。安卓系统中引入了Android Automotive的概念,借助各种总线拓扑,很多汽车子系统都可以实现互连以及与车载信息娱乐 (IVI) 系统的连接。不同的制造商提供的确切总线类型和协议之间有很大差异(甚至同一品牌的不同车型之间也是如此),例如控制器局域网 (CAN) 总线、区域互连网路 (LIN) 总线、面向媒体的系统传输 (MOST) 总线以及汽车级以太网和 TCP/IP 网络(如 BroadR-Reach)。
Android Automotive 的硬件抽象层 (HAL) 为 Android 框架提供了一致的接口(无需考虑物理传输层)。此车载 HAL 是开发 Android Automotive 实现的接口。
系统集成商可以将特定于功能的平台 HAL 接口(如 HVAC)与特定于技术的网络接口(如 CAN 总线)连接,以实现车载 HAL 模块。典型的实现可能包括运行专有实时操作系统 (RTOS) 的专用微控制器单元 (MCU),该微控制器单元用于 CAN 总线访问或类似操作,可通过串行链路连接到运行 Android Automotive 的 CPU。除了专用 MCU,还可以将总线访问作为虚拟 CPU 来实现。只要实现符合车载 HAL 的接口要求,每个合作伙伴都可以选择适合硬件的架构。
但是,座舱功能的增加同时也增加了座舱的风险暴露面,尤其是Android系统可能会安装第三方应用,甚至是未授权安装的应用,如何限制第三方应用和未授权应用对车辆控制系统的访问,是一个亟需解决的问题。因此Android Automotive的车载适配层HAL得以提出,车载HAL是汽车和车辆网络服务之间的一些接口定义:
其中,CAR Service是通过CAR API的方式为OEM APPs提供服务的,因此,如何禁止第三方应用或者未授权应用访问车辆控制系统的问题就缩小到如何限制第三方应用或者未授权应用访问CAR API的问题。Android系统提供的应用权限功能首先提供了一层保护。
5.1 安卓应用权限
应用APK中包含了一个应用权限申请的manifest文件,该文件中详细描述了该应用所要使用到的权限,可以通过这个接口定义的方式强制要求CAR API对应的功能只有拥有特定的权限的应用才允许调用:
当某个应用调用对应的API时,通过AIDL封装的接口能获取进程的PID和permission,再由binder模块检查对应的权限是否满足,以此来达到权限控制的目的:
这虽然能达到控制权限的目的,但是由于权限是否需要是由APK自行定义,控制权并不在系统中,因此这个方案必须和证书绑定,才能发挥作用,且自由度较低。
5.2 SELinux
由于CAR SERVICE都是通过Android调用对应的硬件驱动去发送控制报文(例如CAN报文、LIN报文等)来实现控制车辆(例如打开空调、打开车门等)的目的,因此可以通过SELinux的策略配置,只允许特定的系统进程才允许对这些驱动的访问,从而从系统上禁止第三方应用或者未授权应用对CAR SERVICE的未授权访问。 在安卓系统中,使能SELinux后,会在
system/sepolicy
中生成SELinux的规则,然后整合到SELinux内核策略,并覆盖上游的Android操作系统。但是,用户如果需要自定义SEPolicy,却无法通过修改system/sepolicy
的方式进行,Android提供了另外的机制给用户自行定义SELInux规则。用户自行定义的SELinux规则位于/device/manufacturer/device-name/sepolicy
目录中,在Android8.0以及更高的版本中,对这个目录的SELinux规则的修改,只会影响供应商目录的政策,这个举措使得系统默认SELinux规则和供应商的规则独立,使得系统隔离更彻底。 因此,SELinux在Android Automotive上的应用,主要是控制不同APP对车辆接口的访问,即限制APP对CAN INTERFACE、ETH INTERFACE、LIN INTERFACE和MOST INTERFACE的访问。6. Reference