본문 바로가기
프로그램/안드로이드

SELinux 정책파일(.te) 사용법

by 고무다라 2014. 11. 14.
반응형

SELinux 정책파일(.te) 사용법

 

??안녕하세요? 고무다라입니다. 최근 안드로이드 5.0 롤리팝(Lollipop)이 릴리즈 되었죠? 이와 관련하여 SElinux의 정책파일인 .te에 대해 사용법을 찾다가 아래와 같이 정리하게 되었네요. SElinux를 포팅하는게 아니라면 주로 다루게 될 부분이 정책만 조정하는 것이기에, 정책파일 사용법에 대하여 알아보고자 합니다.

 

SELinux와 유사하게 SEAndroid가 있는데, 이는 Security Enhancements for Android 라고 하며, 안드로이드를 위한 개선된 보안기능이라 할 수 있겠습니다. 즉 SELinux가 확장된 개념이라 할 수 있으며, SEAndroidEnforcing Mode는 안드로이드 킷캣(KitKat)에 추가된 주요기능 중의 하나 입니다. 이것이 의미하는 바는 안드로이드의 모든 컴포넌트의 액세스 권한을 SEAndroid의 통제아래 두겠다는 의미라고 할 수 있습니다[각주:1].

 

 

 

  1. 정책파일의 위치 - Nexus5(hammerhead) 기준

 

먼저 롤리팝의 소스는 아래에서 받으시면 됩니다. 브랜치는 상위꺼나 릴리즈 버전을 받으셔도 될것 같습니다.

 

$ repo init -u https://android.googlesource.com/platform/manifest -b android-5.0.0_r2
$ repo sync

 

 

Nexus5는 햄머헤드(hammerhead)로 불리며, device/lge/hammerhead/sepolicy/ 에 정책파일이 있습니다. 사용되는 .te 파일 리스트는 BoardConfig.mk 파일에서 보면 아래와 같습니다.

 

lge/hammerhead/BoardConfig.mk:

... 

BOARD_SEPOLICY_DIRS
+= \
       device/lge/hammerhead/sepolicy

# The list below is order dependent
BOARD_SEPOLICY_UNION += \
       app.te \
       bluetooth_loader.te \
       bridge.te \
       camera.te \
       device.te \
       domain.te \
       file.te \
       hostapd.te \
       irsc_util.te \
       mediaserver.te \
       mpdecision.te \
       netmgrd.te \
       platform_app.te \
       qmux.te \
       radio.te \
       rild.te \
       rmt.te \
       sensors.te \
       ssr.te \
       surfaceflinger.te \
       system_server.te \
       tee.te \
       thermald.te \
       time.te \
       ueventd.te \
       vss.te \
       wpa.te \
       file_contexts \
       genfs_contexts \
       te_macros

...

 

 

BOARD_SEPOLICY_DIRS BOARD_SEPOLICY_UNION 의 사용은 external/sepolicy에서 사용되고 있습니다. 또한 기본 SELinux 정책 버전은 POLICYVERS ?= 26으로 커널버전 3.0이상을 요구 합니다.

 

external/sepolicy/Android.mk:

...

# SELinux policy version.
# Must be <= /selinux/policyvers reported by the Android kernel.
# Must be within the compatibility range reported by checkpolicy -V.
POLICYVERS ?= 26
 

...

# Quick edge case error detection for BOARD_SEPOLICY_REPLACE.
# Builds the singular path for each replace file.
sepolicy_replace_paths :=
$(foreach pf, $(BOARD_SEPOLICY_REPLACE), \
  $(if $(filter $(pf), $(BOARD_SEPOLICY_UNION)), \
    $(error Ambiguous request for sepolicy $(pf). Appears in both \
      BOARD_SEPOLICY_REPLACE and BOARD_SEPOLICY_UNION), \
  ) \
  $(eval _paths := $(filter-out $(BOARD_SEPOLICY_IGNORE), \
  $(wildcard $(addsuffix /$(pf), $(BOARD_SEPOLICY_DIRS))))) \
  $(eval _occurrences := $(words $(_paths))) \
  $(if $(filter 0,$(_occurrences)), \
    $(error No sepolicy file found for $(pf) in $(BOARD_SEPOLICY_DIRS)), \
  ) \
  $(if $(filter 1, $(_occurrences)), \
    $(eval sepolicy_replace_paths += $(_paths)), \
    $(error Multiple occurrences of replace file $(pf) in $(_paths)) \
  ) \
  $(if $(filter 0, $(words $(wildcard $(addsuffix /$(pf), $(LOCAL_PATH))))), \
    $(error Specified the sepolicy file $(pf) in BOARD_SEPOLICY_REPLACE, \
      but none found in $(LOCAL_PATH)), \
  ) \
)

# Quick edge case error detection for BOARD_SEPOLICY_UNION.
# This ensures that a requested union file exists somewhere
# in one of the listed BOARD_SEPOLICY_DIRS.
$(foreach pf, $(BOARD_SEPOLICY_UNION), \
  $(if $(filter 0, $(words $(wildcard $(addsuffix /$(pf), $(BOARD_SEPOLICY_DIRS))))), \
    $(error No sepolicy file found for $(pf) in $(BOARD_SEPOLICY_DIRS)), \
  ) \
)

# Builds paths for all requested policy files w.r.t
# both BOARD_SEPOLICY_REPLACE and BOARD_SEPOLICY_UNION
# product variables.
# $(1): the set of policy name paths to build
build_policy = $(foreach type, $(1), \
  $(filter-out $(BOARD_SEPOLICY_IGNORE), \
    $(foreach expanded_type, $(notdir $(wildcard $(addsuffix /$(type), $(LOCAL_PATH)))), \
      $(if $(filter $(expanded_type), $(BOARD_SEPOLICY_REPLACE)), \
        $(wildcard $(addsuffix $(expanded_type), $(sort $(dir $(sepolicy_replace_paths))))), \
        $(LOCAL_PATH)/$(expanded_type) \
      ) \
    ) \
    $(foreach union_policy, $(wildcard $(addsuffix /$(type), $(BOARD_SEPOLICY_DIRS))), \
      $(if $(filter $(notdir $(union_policy)), $(BOARD_SEPOLICY_UNION)), \
        $(union_policy), \
      ) \
    ) \
  ) \
)

...

 

여기서 보면 4가지의 변수가 사용되는데 /external/sepolicy/README를 보면, 각각의 의미는 아래와 같습니다.

 

1. BOARD_SEPOLICY_REPLACE :

external/sepolicy의 파일을 BOARD_SEPOLICY_REPLACE 파일로 치환합니다.


2. BOARD_SEPOLICY_UNION :

external/sepolicy의 파일에 BOARD_SEPOLICY_UNION의 파일을 추가합니다.


3. BOARD_SEPOLICY_DIRS :

BOARD_SEPOLICY_REPLACE, BOARD_SEPOLICY_UNION의 파일이 위치한 폴더리스트 이며, 치환, 혹은 추가할 파일을 찾지 못하면 오류가 발생합니다. 파일 생성후

out/target/product/<device>/etc/sepolicy_intermediates/policy.conf 에서 확인할 수 있습니다.

 

4. BOARD_SEPOLICY_IGNORE :

정책파일에서 제외되어야 할 것으로 제거의 의미입니다.

예로)

     BOARD_SEPOLICY_DIRS += X Y
     BOARD_SEPOLICY_REPLACE += A
     BOARD_SEPOLICY_IGNORE += X/A

     폴더 X, Y가 있고, A의 파일을 치환하면, X/A, Y/A가 되며,

여기서 X/A를 제거하면 결국 Y/A만 남게 됩니다.

 

관련한 커널 Config 설정값[각주:2]은 아래와 같습니다. linario에 적용된 것으로 테스트는 해 보지 않았습니다. 하지만 UBER-L/arch/arm/configs/hammerhead_defconfig[각주:3]를 확인해 보니 모두 적용되어 있습니다.

 

+CONFIG_AUDIT=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=4096
+CONFIG_SECURITY_SELINUX=y

신나2

 

 

 

 2. 초기화 코드 확인

 

system/core/init/init.cmain() 함수에서 selinux_initialize()의 호출로 SElinux의 초기화가 시작됩니다.

 

system/core/init/init.c:

int main(int argc, char **argv)
{
...

    union selinux_callback cb;
    cb.func_log = log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    selinux_initialize();
...

    return 0;
}

 

 

▶selinux_initialize()SElinux 관련 함수 초기화를 수행합니다. SElinux disable 되었는지의 여부를 먼저 확인후, 정책파일을 읽은 후, 오류가 있으면 recovery 모드로 안드로이드를 재 부팅 시킵니다. 정상적으로 정책파일이 로드되었으면, SElinux 관련 모든 핸들러들을 초기화 시키고, enforcing 모드인지 확인후 현재 모드로 재 설정을 하게 됩니다.

 

system/core/init/init.c:

static void selinux_initialize(void)
{
    if (selinux_is_disabled()) {
        return;
    }

    INFO("loading selinux policy\n");
    if (selinux_android_load_policy() < 0) {
        ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
        android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
        while (1) { pause(); }  // never reached
    }

    selinux_init_all_handles();
    bool is_enforcing = selinux_is_enforcing();
    INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
    security_setenforce(is_enforcing);
}

 

 

▶selinux_is_disabled(void) 함수는 Android.mk의 -DALLOW_DISABLE_SELINUX 의 컴파일러 외부정의에 의하여 설정되며, userdebug, eng 모드일 경우 활성화 됩니다. 활성화 체크 하는 방법은 /sys/fs/selinux 폴더를 체크 하거나, property값중 ro.boot.selinux의 값을 읽어 확인합니다.

 

system/core/init/init.c:

static bool selinux_is_disabled(void)
{
#ifdef ALLOW_DISABLE_SELINUX
    char tmp[PROP_VALUE_MAX];

    if (access("/sys/fs/selinux", F_OK) != 0) {
        /* SELinux is not compiled into the kernel, or has been disabled
         * via the kernel command line "selinux=0".
         */
        return true;
    }

    if ((property_get("ro.boot.selinux", tmp) != 0) && (strcmp(tmp, "disabled") == 0)) {
        /* SELinux is compiled into the kernel, but we've been told to disable it. */
        return true;
    }
#endif

    return false;
}

 

system/core/init/Android.mk:

...

ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))

LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
endif

...

 

 

▶selinux_android_load_policy()external/libselinux/src/android.c에 라이브러리 형태로 위치 하고 있으며, 내부적으로는 set_selinuxmnt() 호출 후 selinux_android_load_policy_helper() 를 호출합니다.

 

external/libselinux/src/android.c:

int selinux_android_load_policy(void)
{
 const char *mnt = SELINUXMNT;
 int rc;
 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
 if (rc < 0) {
  if (errno == ENODEV) {
   /* SELinux not enabled in kernel */
   return -1;
  }
  if (errno == ENOENT) {
   /* Fall back to legacy mountpoint. */
   mnt = OLDSELINUXMNT;
   rc = mkdir(mnt, 0755);
   if (rc == -1 && errno != EEXIST) {
    selinux_log(SELINUX_ERROR,"SELinux:  Could not mkdir:  %s\n",
     strerror(errno));
    return -1;
   }
   rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
  }
 }
 if (rc < 0) {
  selinux_log(SELINUX_ERROR,"SELinux:  Could not mount selinuxfs:  %s\n",
    strerror(errno));
  return -1;
 }
 set_selinuxmnt(mnt);

    return selinux_android_load_policy_helper(false);
}

 

 

▶selinux_android_load_policy_helper()은 정책 로딩을 위한 메모리 맵핑을 하고, security_load_policy() 호출에 의해 정책이 로드 된다.

 

external/libselinux/src/android.c:

static int selinux_android_load_policy_helper(bool reload)
{
...
 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
...

 rc = security_load_policy(map, sb.st_size);
...

 return 0;
}

 

 

▶security_load_policy()selinux_mnt 폴더의 load 파일을 열어 정책파일을 기록한다.

 

/external/libselinux/src/policy.h:

#define SELINUXMNT "/sys/fs/selinux"

 

/external/libselinux/src/load_policy.c:

int security_load_policy(void *data, size_t len)
{
...

 snprintf(path, sizeof path, "%s/load", selinux_mnt);
 fd = open(path, O_RDWR);
 if (fd < 0)
  return -1;

 ret = write(fd, data, len);
...
 return 0;
}

 

 

▶selinux_init_all_handlessehandlesehandle_prop 핸들을 설정하며, 관련한 파일은 아래와 같다.

 

/external/libselinux/src/android.c:

#define POLICY_OVERRIDE_VERSION    "/data/security/current/selinux_version"
#define POLICY_BASE_VERSION        "/selinux_version"

 

 

▶selinux_is_enforcing()enforcing이 설정되었는지 체크 하며, 기본값은 enforcing 모드이다. 확인 방법은 ro.boot.selinux의 값을 읽고, 설정이 안되었으면 enforcing 모드라 가정하며, permissive 모드이면 fasle를 반환한다. 그외 나머지 값은 enforcing 모드라고 가정한다.

 

system/core/init/init.c:

static bool selinux_is_enforcing(void)
{
#ifdef ALLOW_DISABLE_SELINUX
    char tmp[PROP_VALUE_MAX];

    if (property_get("ro.boot.selinux", tmp) == 0) {
        /* Property is not set.  Assume enforcing */
        return true;
    }

    if (strcmp(tmp, "permissive") == 0) {
        /* SELinux is in the kernel, but we've been told to go into permissive mode */
        return false;
    }

    if (strcmp(tmp, "enforcing") != 0) {
        ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
    }

#endif
    return true;
}

 

 

▶security_setenforce() 호출을 마지막으로 selinux_mntenforce 파일에 enforcing 모드값을 설정하고 초기화를 완료한다.

 

external/libselinux/src/setenforce.c:

int security_setenforce(int value)
{
...

 snprintf(path, sizeof path, "%s/enforce", selinux_mnt);
 fd = open(path, O_RDWR);
 if (fd < 0)
  return -1;

 snprintf(buf, sizeof buf, "%d", value);
 ret = write(fd, buf, strlen(buf));
...

 return 0;
}

 

감사

 

 

 3. 정책파일 .te 의 사용법

 

그럼 sepolicy에 있는 .te 파일에 정책설정하는 방법에 대하여 알아보겠습니다. 사용법에 관한 내용은 아래 NSA 사이트[각주:4]를 참고하였으며, TE 설정파일의 예를 보면 아래와 같습니다.

 

Table 7. TE Configuration Files

Filename Description
tunables/*.tun Defines policy tunables for customization.
attrib.te Defines type attributes.
macros/program/*.te Defines macros for specific program domains.
macros/*.te Defines commonly used macros.
types/*.te Defines general types.
domains/user.te Defines unprivileged user domains.
domains/admin.te Defines administrator domains.
domains/misc/*.te Defines miscellaneous domains not associated with a particular program.
domains/program/*.te Defines domains for specific programs.
domains/program/unused/*.te Optional domains for further programs.
assert.te Defines assertions on the TE configuration.

 

이를 기준으로 햄머헤드의 BOARD_SEPOLICY_UNION 설정파일중 몇개를 확인해 보도록 하겠습니다.

 

attrib.te 파일은 attributes을 정의한 것으로 되어 있으나, android-5.0.0_r2
에는 attrib.te 대신 external/sepolicy/attributes의 파일이 있습니다. dev_type의 속성은 주로 device.te 파일에, file_type, data_file_type의 속성은 file.te에 사용되고 있습니다. device.te는 디바이스와 관련된 설정이며, file.te는 파일과 관련된 설정이라 할 수 있습니다.

 

external/sepolicy/attributes:

######################################
# Attribute declarations
#

# All types used for devices.
attribute dev_type;

# All types used for processes.
attribute domain;

# All types used for filesystems.
attribute fs_type;

# All types used for context= mounts.
attribute contextmount_type;

# All types used for files that can exist on a labeled fs.
# Do not use for pseudo file types.
attribute file_type;

# All types used for domain entry points.
attribute exec_type;

# All types used for /data files.
attribute data_file_type;

# All types use for sysfs files.
attribute sysfs_type;

...

 

 

카메라와 관련된 정책파일인 camera.te를 보면 크게 type, allow, type_transition, macros 4가지를 사용하고 있음을 볼수 있습니다.

 

1. type :

type camera, domain;
type camera_exec, exec_type, file_type;

 

타입은 말 그대로 형태를 선언하는 것으로 주로 사용하는 카메라 타입은 프로세스 형태의 도메인과 카메라 실행타입은 실행형 타입과 파일형 타입의 특성을 가진것으로 선언되어 있습니다.

 

2. allow :

allow camera self:process execmem;

 

카메라 타입은 자기 자신의 프로세스를 메모리상에 실행가능하게 허락하는 설정입니다. execmemexternal/sepolicy/access_vectorclass process 내에 선언되어 있습니다.

 

 

3. type_transition :

type_transition camera system_data_file:sock_file camera_socket "cam_socket1";

 

타입변환은 camera 타입의 system_data_file:sockcamera_socket"cam_socekt1"으로 변환하는 설정입니다.

 

4. macro :

unix_socket_connect(camera, sensors, sensors)

 

unix_socket_connet의 경우 여러 .te 파일에서 사용되고 있으며, 정의된 곳은 te_macros에 정의 되어 있으며, 아래와 같습니다. 매크로는 define으로 시작하여 선언되며, ( )로 안에 구성을 하게 됩니다.

 

external/sepolicy/te_macros:

...

#####################################
# unix_socket_connect(clientdomain, socket, serverdomain)
# Allow a local socket connection from clientdomain via
# socket to serverdomain.
define(`unix_socket_connect', `
allow $1 $2_socket:sock_file write;
allow $1 $3:unix_stream_socket connectto;
')

...

 

device/lge/hammerhead/sepolicy/camera.te:

# Qualcomm MSM camera
type camera, domain;
type camera_exec, exec_type, file_type;

# Started by init
init_daemon_domain(camera)

allow camera self:process execmem;

# Interact with other media devices
allow camera camera_device:dir search;
allow camera { gpu_device video_device camera_device }:chr_file rw_file_perms;
allow camera { surfaceflinger mediaserver }:fd use;

# Create front and back camera sockets (/data/cam_socket[12])
type_transition camera system_data_file:sock_file camera_socket "cam_socket1";
type_transition camera system_data_file:sock_file camera_socket "cam_socket2";
allow camera camera_socket:sock_file { create unlink };
allow camera system_data_file:dir w_dir_perms;
allow camera system_data_file:sock_file unlink;

type_transition camera system_data_file:file camera_data_file "fdAlbum";
allow camera camera_data_file:file create_file_perms;

# Connect to sensor socket (/data/app/sensor_ctl_socket)
allow camera apk_data_file:dir r_dir_perms;
unix_socket_connect(camera, sensors, sensors)
allow camera sensors_socket:sock_file read;

allow camera sensors_device:chr_file rw_file_perms;

# Read camera files from persist filesystem
allow camera persist_file:dir search;
r_dir_file(camera, persist_camera_file)

 

 

컨텍스트의 확인은 ls -Z로 확인할 수 있으며, 아래의 file_context에 대하여 살펴보면, 크게 형태가 u:object_r:type_s#의 형태로 되어 있음을 볼 수 있으며, 각 의미하는 바는 아래와 같다.

  • u : user를 뜻하며 object를 기본적으로 가지고 있다.
  • r : role을 뜻함
  • type : 정책 타입을 말하며, 예로 device type, process type, file system type, network type, IPC type 등이 있다.
  • s : security Level(MLS의 확장기능)로 보안 레벨을 의미한다.

/device/lge/hammerhead/sepolicy/file_contexts:

# GPU device
/dev/kgsl-3d0       u:object_r:gpu_device:s0
/dev/kgsl           u:object_r:gpu_device:s0

# Bluetooth
/dev/ttyHS99        u:object_r:hci_attach_dev:s0

# nfc
/dev/bcm2079x       u:object_r:nfc_device:s0

# Used by keystore to access trustzone
/dev/qseecom        u:object_r:tee_device:s0

# GPS
/dev/gss               u:object_r:sensors_device:s0
...

 

 

마지막으로 파일 및 폴더에 대한 권한은 external/sepolicy/global_macros에서 찾아 볼 수 있으며, 3가지 일반적인 그룹으로 나뉘어 있으며, object class, permission, socket 그룹으로 나뉘어 있습니다.

 

external/sepolicy/global_macros:

#####################################
# Common groupings of object classes.
#
define(`capability_class_set', `{ capability capability2 }')

define(`devfile_class_set', `{ chr_file blk_file }')
define(`notdevfile_class_set', `{ file lnk_file sock_file fifo_file }')
define(`file_class_set', `{ devfile_class_set notdevfile_class_set }')
define(`dir_file_class_set', `{ dir file_class_set }')

define(`socket_class_set', `{ socket tcp_socket udp_socket rawip_socket netlink_socket packet_socket key_socket unix_stream_socket unix_dgram_socket appletalk_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket tun_socket }')
define(`dgram_socket_class_set', `{ udp_socket unix_dgram_socket }')
define(`stream_socket_class_set', `{ tcp_socket unix_stream_socket }')
define(`unpriv_socket_class_set', `{ tcp_socket udp_socket unix_stream_socket unix_dgram_socket }')

define(`ipc_class_set', `{ sem msgq shm ipc }')

#####################################
# Common groupings of permissions.
#
define(`x_file_perms', `{ getattr execute execute_no_trans }')
define(`r_file_perms', `{ getattr open read ioctl lock }')
define(`w_file_perms', `{ open append write }')
define(`rx_file_perms', `{ r_file_perms x_file_perms }')
define(`ra_file_perms', `{ r_file_perms append }')
define(`rw_file_perms', `{ r_file_perms w_file_perms }')
define(`rwx_file_perms', `{ rw_file_perms x_file_perms }')
define(`link_file_perms', `{ getattr link unlink rename }')
define(`create_file_perms', `{ create setattr rw_file_perms link_file_perms }')

define(`r_dir_perms', `{ open getattr read search ioctl }')
define(`w_dir_perms', `{ open search write add_name remove_name }')
define(`ra_dir_perms', `{ r_dir_perms add_name write }')
define(`rw_dir_perms', `{ r_dir_perms w_dir_perms }')
define(`create_dir_perms', `{ create reparent rmdir setattr rw_dir_perms link_file_perms }')

define(`r_ipc_perms', `{ getattr read associate unix_read }')
define(`w_ipc_perms', `{ write unix_write }')
define(`rw_ipc_perms', `{ r_ipc_perms w_ipc_perms }')
define(`create_ipc_perms', `{ create setattr destroy rw_ipc_perms }')

#####################################
# Common socket permission sets.
define(`rw_socket_perms', `{ ioctl read getattr write setattr append bind connect getopt setopt shutdown }')
define(`create_socket_perms', `{ create rw_socket_perms }')
define(`rw_stream_socket_perms', `{ rw_socket_perms listen accept }')
define(`create_stream_socket_perms', `{ create rw_stream_socket_perms }')

 

이상으로 .te 파일에 대하여 정리 해 보았습니다. 정책변경에 대한 .te 파일의 설정 및 개념정립에 도움이 되었으면 합니다.

 

홧팅2

끝.

 

 

 

  1. http://www.codeproject.com/Articles/806904/Android-Security-Customization-with-SEAndroid [본문으로]
  2. http://lists.linaro.org/pipermail/linaro-dev/2014-June/017279.html [본문으로]
  3. https://github.com/Cl3Kener/UBER-L/blob/master/arch/arm/configs/hammerhead_defconfig [본문으로]
  4. https://www.nsa.gov/research/_files/selinux/papers/policy2/t1.shtml [본문으로]
반응형

댓글