已阅读5页,还剩20页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
SEAndroid安全机制中的文件安全上下文关联分析前面一篇文章提到,SEAndroid是一种基于安全策略的MAC安全机制。这种安全策略实施在主体和客体的安全上下文之上。这意味着安全策略在实施之前,SEAndroid安全机制中的主休和客体是已经有安全上下文的。在SEAndroid安全机制中,主体一般就是进程,而客体一般就是文件。文件的安全上下文的关联有不同的方式。本文主要分析文件安全上下文的设置过程,接下来的一篇文章再分析进程安全上下文的设置过程。在SEAndroid中,文件的安全上下文是在文件的创建过程中设置的。在Android系统中,文件的产生方式主要分为两种,一种是预置在ROM里面的,另外一种是动态创建的,即在系统在运行的过程中创建的。对于预置在ROM里面的文件,例如打包在system.img里面的文件,它们的安全上下文在是制作ROM的过程中设置的。而对于动态创建的文件,它们的安全上下文如果没有特别指定,就与父目录的安全上下文一致。 假设动态创建的文件的安全上下文来自于父目录。这时候就有一个问题需要解决,就是最开始的父目录的安全上下文是怎么来的呢?如果最开始的父目录是预置在ROM里面的,那么这个问题就很好解决。但是有一些目录,它们并不是预置在ROM的,而是在系统启动或者运行的过程中动态安装的,即我们平时所说的虚拟文件系统,例如我们在前面一篇文章中提到的selinux文件系统。这些虚拟文件系统在安装的时候,SEAndroid安全机制会根据安全策略给它们的根目录设置相应的安全上下文,这样以后在里面创建的文件就可以从父目录继承安全上下文了。 此外,有些文件的安全上下文是不适合使用父目录的安全上下文的,例如应用程序数据文件,它们的安全上文需要根据一定的规则来特别指定。在前面一篇文章中提到,SEAndroid安全机制根据应用程序类型的签名来给其数据文件设置不同的安全上下文,以区分系统应用程序和第三方应用程序的数据文件。由于无论是系统应用程序,还是第三方应用程序,它们的数据文件都是位于data分区的data子目录中的,因此我们需要有一种机制给在/data/data目录中创建的数据文件设置不同的安全上下文。我们知道,应用程序在安装的时候,PackageManagerService会通过守护进程installd在/data/data目录中创建相应的数据目录,以后应用程序在运行的过程中默认创建的数据文件就位于对应的数据目录中,因此只要给这些数据目录设置不同的安全上下文,就可以让不同类型的应用程序在运行的过程中创建不同安全上下文的数据文件。 我们通过图1总结上面描述的文件安全上下文创建方式,如下所示:接下来,我们就分别详细分析上述三种文件安全上下文关联方式。 1. 设置打包在ROM里面的文件的安全上下文 这里我们以ROM里面的system.img为例,说明打包在ROM里面的文件的安全上下文的设置过程。在前面一篇文章中,我们已经分析过system.img的制作过程了,因此这里我们只关注与安全上下文设置相关的逻辑。 生成system.img的命令位于build/core/Makefile文件中,如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img # $(1): output file define build-systemimage-target echo Target system fs image: $(1) mkdir -p $(dir $(1) $(systemimage_intermediates) & rm -rf $(systemimage_intermediates)/system_image_info.txt $(call generate-userimage-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt, skip_fsck=true) $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$PATH ./build/tools/releasetools/build_image.py $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1) endef $(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE) $(call build-systemimage-target,$) 从这里就可以看出,system.img由命令build-system-target生成。build-system-target命令在执行的过程中,又会执行两个子命令。第一个子命令是generate-userimage-prop-dictionary,用来生成一个属性文件system_image_info.txt。第二个子命令是build_image,用来制作system.img镜像文件。注意,第二个命令在制作system.img镜像文件的过程中,会用到第一个命令生成的属性文件system_image_info.txt。 第一个子命令generate-userimage-prop-dictionary也是实现在build/core/Makefile文件中,如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片SELINUX_FC := $(TARGET_ROOT_OUT)/file_contexts . # $(1): the path of the output dictionary file # $(2): additional key=value pairs to append to the dictionary file. define generate-userimage-prop-dictionary $(if $(INTERNAL_USERIMAGES_EXT_VARIANT),$(hide) echo fs_type=$(INTERNAL_USERIMAGES_EXT_VARIANT) $(1) $(if $(BOARD_SYSTEMIMAGE_PARTITION_SIZE),$(hide) echo system_size=$(BOARD_SYSTEMIMAGE_PARTITION_SIZE) $(1) $(if $(BOARD_USERDATAIMAGE_PARTITION_SIZE),$(hide) echo userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE) $(1) $(if $(BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE),$(hide) echo cache_fs_type=$(BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE) $(1) $(if $(BOARD_CACHEIMAGE_PARTITION_SIZE),$(hide) echo cache_size=$(BOARD_CACHEIMAGE_PARTITION_SIZE) $(1) $(if $(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE),$(hide) echo vendor_fs_type=$(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE) $(1) $(if $(BOARD_VENDORIMAGE_PARTITION_SIZE),$(hide) echo vendor_size=$(BOARD_VENDORIMAGE_PARTITION_SIZE) $(1) $(if $(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG),$(hide) echo extfs_sparse_flag=$(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG) $(1) $(if $(mkyaffs2_extra_flags),$(hide) echo mkyaffs2_extra_flags=$(mkyaffs2_extra_flags) $(1) $(hide) echo selinux_fc=$(SELINUX_FC) $(1) 这里传过来的第一个参数便是指向上述的属性文件system_image_info.txt,它的内容是通过一系列的echo命令生成的,每一行都是“key=value“形式。其中,与文件安全上下文相关的是最后一行:plain view plain copy 在CODE上查看代码片派生到我的代码片selinux_fc=$(SELINUX_FC) 变量SELINUX_FC指向一个file_contexts文件。这个file_contexts文件就是我们在前面一篇文章中提到的file_contexts文件,用来描述文件的安全上下文。我们知道,system.img镜像文件是安装在目标设备上的/system目录的,因此我们就观察一下在file_contexts文件中与/system目录相关的文件的安全上下文是如何设置的。 文件file_contexts最开始是位于build/external/sepolicy目录中的,经过编译后,就会保存在$OUT/root目录中,其中$OUT指向的是产品输出目录。打开$OUT/root/file_contexts文件,我们就可以看到与/system目录相关的文件的安全上下文的设置规则:plain view plain copy 在CODE上查看代码片派生到我的代码片# # System files # /system(/.*)? u:object_r:system_file:s0 /system/bin/ash u:object_r:shell_exec:s0 /system/bin/mksh u:object_r:shell_exec:s0 /system/bin/sh - u:object_r:shell_exec:s0 /system/bin/run-as - u:object_r:runas_exec:s0 /system/bin/app_process u:object_r:zygote_exec:s0 /system/bin/servicemanager u:object_r:servicemanager_exec:s0 /system/bin/surfaceflinger u:object_r:surfaceflinger_exec:s0 /system/bin/drmserver u:object_r:drmserver_exec:s0 /system/bin/vold u:object_r:vold_exec:s0 /system/bin/netd u:object_r:netd_exec:s0 /system/bin/rild u:object_r:rild_exec:s0 /system/bin/mediaserver u:object_r:mediaserver_exec:s0 /system/bin/dbus-daemon u:object_r:dbusd_exec:s0 /system/bin/installd u:object_r:installd_exec:s0 /system/bin/keystore u:object_r:keystore_exec:s0 /system/bin/debuggerd u:object_r:debuggerd_exec:s0 /system/bin/bluetoothd u:object_r:bluetoothd_exec:s0 /system/bin/wpa_supplicant u:object_r:wpa_exec:s0 /system/bin/qemud u:object_r:qemud_exec:s0 /system/bin/sdcard u:object_r:sdcardd_exec:s0 /system/bin/dhcpcd u:object_r:dhcp_exec:s0 /system/bin/mtpd u:object_r:mtp_exec:s0 /system/bin/pppd u:object_r:ppp_exec:s0 /system/bin/tf_daemon u:object_r:tee_exec:s0 /system/bin/racoon u:object_r:racoon_exec:s0 /system/etc/ppp(/.*)? u:object_r:ppp_system_file:s0 /system/etc/dhcpcd(/.*)? u:object_r:dhcp_system_file:s0 /system/xbin/su u:object_r:su_exec:s0 /system/vendor/bin/gpsd u:object_r:gpsd_exec:s0 /system/bin/ping u:object_r:ping_exec:s0 接下来我们再来看第二个子命令build_image的实现,它是由文件build/tools/releasetools/build_image.py实现的,它的入口函数main的实现如下所示:python view plain copy 在CODE上查看代码片派生到我的代码片def main(argv): . in_dir = argv0 glob_dict_file = argv1 out_file = argv2 glob_dict = LoadGlobalDict(glob_dict_file) image_filename = os.path.basename(out_file) mount_point = if image_filename = system.img: mount_point = system elif image_filename = userdata.img: mount_point = data elif image_filename = cache.img: mount_point = cache elif image_filename = vendor.img: mount_point = vendor else: print sys.stderr, error: unknown image file name , image_filename exit(1) image_properties = ImagePropFromGlobalDict(glob_dict, mount_point) if not BuildImage(in_dir, image_properties, out_file): print sys.stderr, error: failed to build %s from %s % (out_file, in_dir) exit(1) if _name_ = _main_: main(sys.argv1:) 参数argv1指向的就是我们上面提到的属性文件system_image_info.txt,最终保存在本地变量glob_dict_file中。另外一个参数argv2指向的要输出的system.img文件路径,最终保存在本地变量out_file中。 函数LoadGlobalDict用来打开属性文件system_image_info.txt,并且将它每一行的key和value提取出来,并且保在字典glob_dict中。注意,这个字典glob_dict包含有一个key等于selinux_fc、value等于file_contexts文件路径的项。 接下来再通过os.path.basename将输出的文件路径out_file的最后一项提取出来,就可以得到image_filename的值为”system.img“,因此再接下来就会得到本地变量mount_point的值为”system“,表示我们现在正在打包的是system.img文件。 函数ImagePropFromGlobalDict用来从字典glob_dict中提取与安装点mount_point相关的项,并且保存在另外一个字典中返回给调用者,它的实现如下所示:python view plain copy 在CODE上查看代码片派生到我的代码片def ImagePropFromGlobalDict(glob_dict, mount_point): Build an image property dictionary from the global dictionary. Args: glob_dict: the global dictionary from the build system. mount_point: such as system, data etc. d = def copy_prop(src_p, dest_p): if src_p in glob_dict: ddest_p = str(glob_dictsrc_p) common_props = ( extfs_sparse_flag, mkyaffs2_extra_flags, selinux_fc, skip_fsck, ) for p in common_props: copy_prop(p, p) dmount_point = mount_point if mount_point = system: copy_prop(fs_type, fs_type) copy_prop(system_size, partition_size) elif mount_point = data: copy_prop(fs_type, fs_type) copy_prop(userdata_size, partition_size) elif mount_point = cache: copy_prop(cache_fs_type, fs_type) copy_prop(cache_size, partition_size) elif mount_point = vendor: copy_prop(vendor_fs_type, fs_type) copy_prop(vendor_size, partition_size) return d 从这里就可以看出,函数ImagePropFromGlobalDict返回给调用者的字典包含一个以selinux_fc为key值的项,它的值指向上述分析的file_contexts文件。 回到函数main中,最后它调用另外一个函数BuildImage来生成最终的system.img文件,它的实现如下所示:python view plain copy 在CODE上查看代码片派生到我的代码片def BuildImage(in_dir, prop_dict, out_file): Build an image to out_file from in_dir with property prop_dict. Args: in_dir: path of input directory. prop_dict: property dictionary. out_file: path of the output image file. Returns: True iff the image is built successfully. build_command = fs_type = prop_dict.get(fs_type, ) run_fsck = False if fs_type.startswith(ext): build_command = mkuserimg.sh . build_command.extend(in_dir, out_file, fs_type, prop_dictmount_point) . if selinux_fc in prop_dict: build_command.append(prop_dictselinux_fc) else: build_command = mkyaffs2image, -f . build_command.append(in_dir) build_command.append(out_file) if selinux_fc in prop_dict: build_command.append(prop_dictselinux_fc) build_command.append(prop_dictmount_point) exit_code = RunCommand(build_command) . return exit_code = 0 参数prop_dict指向的就是前面调用ImagePropFromGlobalDict获得的字典,如果它里面包含有一个key为fs_type的项,并且它的value等于ext,那么就意味着将要制作ext格式的system.img镜像文件,否则的话,就意味着将要制作yaffs2格式的system.img镜像文件。前者通过命令mkuserimg来生成,而后者通过命令mkyaffs2image来生成。无论生成的是什么格式的system.img镜像文件, 只要参数prop_dict包含有一个key为selinux_fc的项,那么都会将它的value提取出来,并且作为一个参数传递给命令mkuserimg或者mkyaffs2image使用。 根据前面我们的分析,参数prop_dict描述的字典包含有key为selinux_fc的项,并且它的value描述的就是我们在上面提到的file_contexts的路径。当我们将这个file_contexts文件路径传递给命令mkuserimg或者mkyaffs2image时,后者就会根据它设置的规则给打包在system.img里面的文件关联安全上下文。这样我们就获得了一个关联有安全上下文的system.img镜像文件了。 2. 设置虚拟文件系统的安全上下文 这里我们以selinux虚拟文件系统的安装过程为例,说明虚拟文件系统的安全上下文的设置过程。在前面的一篇文章中提到,系统启动之后,会由init进程在/sys/fs/selinux中安装一个selinux虚拟文件系统,接着再加载SEAndroid安全策略到内核空间的SELinux LSM模块中去。 SEAndroid安全策略是由external/sepolicy模块生成的。观察external/sepolicy模块的编译脚本Android.mk,我们就会发现,SEAndroid安全策略包含有文件genfs_contexts定义的安全上下文设置规则,如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# include $(CLEAR_VARS) LOCAL_MODULE := sepolicy LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) include $(BUILD_SYSTEM)/base_rules.mk sepolicy_policy.conf := $(intermediates)/policy.conf $(sepolicy_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS) $(sepolicy_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS) $(sepolicy_policy.conf) : $(call build_policy, security_classes initial_sids access_vectors global_macros mls_macros mls policy_capabilities te_macros attributes *.te roles users initial_sid_contexts fs_use genfs_contexts port_contexts) mkdir -p $(dir $) $(hide) m4 -D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) -s $ $ $(hide) sed /dontaudit/d $ $.dontaudit $(LOCAL_BUILT_MODULE) : $(sepolicy_policy.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy mkdir -p $(dir $) $(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -c $(POLICYVERS) -o $ $ $(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -c $(POLICYVERS) -o $(dir $)/$(notdir $).dontaudit $.dontaudit built_sepolicy := $(LOCAL_BUILT_MODULE) sepolicy_policy.conf := 生成的SEAndroid安全策略保存在一个名称为policy.conf文件中。在生成这个policy.conf文件的过程中,会调用一个build_policy函数。传递给函数build_policy的参数包含了生成SEAndroid安全策略所需要的源文件。其中,源文件genfs_contexts描述的是虚拟文件系统的安全上下文设置规则,它的内容如下所示:plain view plain copy 在CODE上查看代码片派生到我的代码片# Label inodes with the fs label. genfscon rootfs / u:object_r:rootfs:s0 # proc labeling can be further refined (longest matching prefix). genfscon proc / u:object_r:proc:s0 genfscon proc /net/xt_qtaguid/ctrl u:object_r:qtaguid_proc:s0 # selinuxfs booleans can be individually labeled. genfscon selinuxfs / u:object_r:selinuxfs:s0 genfscon cgroup / u:object_r:cgroup:s0 # sysfs labels can be set by userspace. genfscon sysfs / u:object_r:sysfs:s0 genfscon inotifyfs / u:object_r:inotify:s0 genfscon vfat / u:object_r:sdcard_external:s0 genfscon debugfs / u:object_r:debugfs:s0 genfscon fuse / u:object_r:sdcard_internal:s0 从这里我们就可以看出selinux虚拟文件系统关联的安全上下文为”u:object_r:selinuxfs:s0“,这意味着只有那些对Type为”selinuxfs“的文件有访问权限的进程才可以访问selinux虚拟文件系统,也就是/sys/fs/selinux目录下的文件。 3. 设置应用程序数据文件的安全上下文 在Android系统中,每一个应用程序在/data/data目录下都有一个以包名命名的目录,用来作为数据保存目录。这个数据目录是在应用程序安装的时候由守护进程installd创建的。守护进程installd在创建应用程序数据目录的时候,会同时设置它的安全上下文,以便可以对它进行保护。Android应用程序的详细安装过程可以参考前面一文,这里只关注应用程序数据目录的创建及其安全上下文设置的过程。 PackageManagerService负责安装Android应用程序,它在启动的时候会通过SELinuxMMAC类的静态成员函数readInstallPolicy读取我们在前面一文分析的mac_permissions.xml文件,如下所示:java view plain copy 在CODE上查看代码片派生到我的代码片public class PackageManagerService extends IPackageManager.Stub . public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) . synchronized (mInstallLock) / writer synchronized (mPackages) . mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); . / synchronized (mPackages) / synchronized (mInstallLock) . 这个函数定义在文件frameworks/base/services/java/com/android/server/pm/PackageManagerService.java文件中。 SELinuxMMAC类的静态成员函数readInstallPolicy的实现如下所示:java view plain copy 在CODE上查看代码片派生到我的代码片public final class SELinuxMMAC . / Signature seinfo values read from policy. private static final HashMap sSigSeinfo = new HashMap(); / Package name seinfo values read from policy. private static final HashMap sPackageSeinfo = new HashMap(); / Locations of potential install policy files. private static final File INSTALL_POLICY_FILE = new File(Environment.getDataDirectory(), system/mac_permissions.xml), new File(Environment.getRootDirectory(), etc/security/mac_permissions.xml), null; . public static boolean readInstallPolicy() return readInstallPolicy(INSTALL_POLICY_FILE); . private static boolean readInstallPolicy(File policyFiles) FileReader policyFile = null; int i = 0; while (policyFile = null & policyFiles != null & policyFilesi != null) try policyFile = new FileReader(policyFilesi); break; catch (FileNotFoundException e) Slog.d(TAG,Couldnt find install policy + policyFilesi.getPath(); i+; . try XmlPullParser parser = Xml.newPullParser(); parser.setInput(policyFile); XmlUtils.beginDocument(parser, policy); while (true) XmlUtils.nextElement(parser); if (parser.getEventType() = XmlPullParser.END_DOCUMENT) break; String tagName = parser.getName(); if (signer.equals(tagName) String cert = parser.getAttributeValue(null, signature); . Signature signature; try signature = new Signature(cert); catch (IllegalArgumentException e) . String seinfo = readSeinfoTag(parser); if (seinfo != null) . sSigSeinfo.put(signature, seinfo); else if (default.equals(tagName) String seinfo = readSeinfoTag(parser); if (seinfo != null) . / The null signature is the default seinfo value sSigSeinfo.put(null, seinfo); else if (package.equals(tagName) String pkgName = parser.getAttributeValue(null, name); . String seinfo = readSeinfoTag(parser); if (seinfo != null) . sPackageSeinfo.put(pkgName, seinfo); else XmlUtils.skipC
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 上海外国语大学《口腔黏膜病学》2025-2026学年期末试卷
- 上海现代化工职业学院《体内药物分析》2025-2026学年期末试卷
- 上海电机学院《传播学教程》2025-2026学年期末试卷
- 上海交通职业技术学院《电视节目类型学》2025-2026学年期末试卷
- 太原理工大学《临床概要学》2025-2026学年期末试卷
- 朔州师范高等专科学校《对外汉语教学概论》2025-2026学年期末试卷
- 上海音乐学院《抽样调查》2025-2026学年期末试卷
- 上海科学技术职业学院《监察法》2025-2026学年期末试卷
- 上海大学《沟通与写作》2025-2026学年期末试卷
- 电力电费核算员电费计算考试题目及答案
- T∕CISIA 015-2025 生物刺激剂 术语与分类
- 静脉输液查对流程
- 商业数据分析实战案例合集及应用
- (必看)2025年3月29日云南省事业单位联考A类《职测》真题及答案
- 计算机视觉与自然语言
- 龙门铣床加工知识培训班课件
- 大学生生活中的痛点及解决方案
- GB/T 16783.1-2025石油天然气工业钻井液现场测试第1部分:水基钻井液
- 2025年工程造价专升本真题汇编及答案(含答案)
- 生物有机肥生产工艺流程
- 开源RISC-V芯片设计与实现
评论
0/150
提交评论