sepolicy: add version_policy tool and version non-platform policy.

In order to support platform changes without simultaneous updates from
non-platform components, the platform and non-platform policies must be
split.  In order to provide a guarantee that policy written for
non-platform objects continues to provide the same access, all types
exposed to non-platform policy are versioned by converting them and the
policy using them into attributes.

This change performs that split, the subsequent versioning and also
generates a mapping file to glue the different policy components
together.

Test: Device boots and runs.
Bug: 31369363
Change-Id: Ibfd3eb077bd9b8e2ff3b2e6a0ca87e44d78b1317
diff --git a/Android.mk b/Android.mk
index 3eddee8..5209145 100644
--- a/Android.mk
+++ b/Android.mk
@@ -38,14 +38,13 @@
 #  in this policy to ensure that policy targeting attributes from public
 #  policy from an older platform version continues to work.
 
-# TODO - build process for device:
+# build process for device:
 # 1) convert policies to CIL:
 #    - private + public platform policy to CIL
 #    - mapping file to CIL (should already be in CIL form)
 #    - non-platform public policy to CIL
 #    - non-platform public + private policy to CIL
 # 2) attributize policy
-#    - TODO: do this for platform policy?
 #    - run script which takes non-platform public and non-platform combined
 #      private + public policy and produces attributized and versioned
 #      non-platform policy
@@ -55,6 +54,27 @@
 
 PLAT_PUBLIC_POLICY := $(LOCAL_PATH)/public
 PLAT_PRIVATE_POLICY := $(LOCAL_PATH)/private
+REQD_MASK_POLICY := $(LOCAL_PATH)/reqd_mask
+
+# TODO: move to README when doing the README update and finalizing versioning.
+# BOARD_SEPOLICY_VERS should contain the platform version identifier
+#  corresponding to the platform on which the non-platform policy is to be
+#  based.  If unspecified, this will build against the current public platform
+#  policy in tree.
+# BOARD_SEPOLICY_VERS_DIR should contain the public platform policy which
+#  is associated with the given BOARD_SEPOLICY_VERS.  The policy therein will be
+#  versioned according to the BOARD_SEPOLICY_VERS identifier and included as
+#  part of the non-platform policy to ensure removal of access in future
+#  platform policy does not break non-platform policy.
+ifndef BOARD_SEPOLICY_VERS
+$(warning BOARD_SEPOLICY_VERS not specified, assuming current platform version)
+BOARD_SEPOLICY_VERS := current
+BOARD_SEPOLICY_VERS_DIR := $(PLAT_PUBLIC_POLICY)
+else
+ifndef BOARD_SEPOLICY_VERS_DIR
+$(error BOARD_SEPOLICY_VERS_DIR not specified for versioned sepolicy.)
+endif
+endif
 
 ###########################################################
 # Compute policy files to be used in policy build.
@@ -83,6 +103,7 @@
                         global_macros \
                         neverallow_macros \
                         mls_macros \
+                        mls_decl \
                         mls \
                         policy_capabilities \
                         te_macros \
@@ -90,6 +111,7 @@
                         ioctl_defines \
                         ioctl_macros \
                         *.te \
+                        roles_decl \
                         roles \
                         users \
                         initial_sid_contexts \
@@ -128,11 +150,64 @@
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
-platform_policy.conf := $(intermediates)/plat_policy.conf
-$(platform_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
-$(platform_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
-$(platform_policy.conf): PRIVATE_ADDITIONAL_M4DEFS := $(LOCAL_ADDITIONAL_M4DEFS)
-$(platform_policy.conf): $(call build_policy, $(sepolicy_build_files), \
+# reqd_policy_mask - a policy.conf file which contains only the bare minimum
+# policy necessary to use checkpolicy.  This bare-minimum policy needs to be
+# present in all policy.conf files, but should not necessarily be exported as
+# part of the public policy.  The rules generated by reqd_policy_mask will allow
+# the compilation of public policy and subsequent removal of CIL policy that
+# should not be exported.
+
+reqd_policy_mask.conf := $(intermediates)/reqd_policy_mask.conf
+$(reqd_policy_mask.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
+$(reqd_policy_mask.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
+$(reqd_policy_mask.conf): PRIVATE_ADDITIONAL_M4DEFS := $(LOCAL_ADDITIONAL_M4DEFS)
+$(reqd_policy_mask.conf): $(call build_policy, $(sepolicy_build_files), $(REQD_MASK_POLICY))
+	@mkdir -p $(dir $@)
+	$(hide) m4 $(PRIVATE_ADDITIONAL_M4DEFS) \
+		-D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
+		-D target_build_variant=$(TARGET_BUILD_VARIANT) \
+		-s $^ > $@
+
+reqd_policy_mask.cil := $(intermediates)/reqd_policy_mask.cil
+$(reqd_policy_mask.cil): $(reqd_policy_mask.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy
+	@mkdir -p $(dir $@)
+	$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -C -M -c $(POLICYVERS) -o $@ $<
+
+# plat_pub_policy - policy that will be exported to be a part of non-platform
+# policy corresponding to this platform version.  This is a limited subset of
+# policy that would not compile in checkpolicy on its own.  To get around this
+# limitation, add only the required files from private policy, which will
+# generate CIL policy that will then be filtered out by the reqd_policy_mask.
+plat_pub_policy.conf := $(intermediates)/plat_pub_policy.conf
+$(plat_pub_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
+$(plat_pub_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
+$(plat_pub_policy.conf): PRIVATE_ADDITIONAL_M4DEFS := $(LOCAL_ADDITIONAL_M4DEFS)
+$(plat_pub_policy.conf): $(call build_policy, $(sepolicy_build_files), \
+$(BOARD_SEPOLICY_VERS_DIR) $(REQD_MASK_POLICY))
+	@mkdir -p $(dir $@)
+	 $(hide) m4 $(PRIVATE_ADDITIONAL_M4DEFS) \
+		-D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
+		-D target_build_variant=$(TARGET_BUILD_VARIANT) \
+		-s $^ > $@
+
+plat_pub_policy.cil := $(intermediates)/plat_pub_policy.cil
+$(plat_pub_policy.cil): $(plat_pub_policy.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy
+	@mkdir -p $(dir $@)
+	$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -C -M -c $(POLICYVERS) -o $@ $<
+
+pruned_plat_pub_policy.cil := $(intermediates)/pruned_plat_pub_policy.cil
+$(pruned_plat_pub_policy.cil): $(reqd_policy_mask.cil) $(plat_pub_policy.cil)
+	@mkdir -p $(dir $@)
+	$(hide) grep -Fxv -f $^ > $@
+
+# plat_policy.conf - A combination of the private and public platform policy
+# which will ship with the device.  The platform will always reflect the most
+# recent platform version and is not currently being attributized.
+plat_policy.conf := $(intermediates)/plat_policy.conf
+$(plat_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
+$(plat_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
+$(plat_policy.conf): PRIVATE_ADDITIONAL_M4DEFS := $(LOCAL_ADDITIONAL_M4DEFS)
+$(plat_policy.conf): $(call build_policy, $(sepolicy_build_files), \
 $(PLAT_PUBLIC_POLICY) $(PLAT_PRIVATE_POLICY))
 	@mkdir -p $(dir $@)
 	$(hide) m4 $(PRIVATE_ADDITIONAL_M4DEFS) \
@@ -144,15 +219,23 @@
 		-s $^ > $@
 	$(hide) sed '/dontaudit/d' $@ > $@.dontaudit
 
-# TODO: add steps for non-platform public and combined files with checkpolicy
-# support. b/31932523
+plat_policy.cil := $(intermediates)/plat_policy.cil
+$(plat_policy.cil): $(plat_policy.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy
+	@mkdir -p $(dir $@)
+	$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -C -c $(POLICYVERS) -o $@.tmp $<
+	$(hide) grep -v neverallow $@.tmp > $@
 
-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): PRIVATE_ADDITIONAL_M4DEFS := $(LOCAL_ADDITIONAL_M4DEFS)
-$(sepolicy_policy.conf): $(call build_policy, $(sepolicy_build_files), \
-$(PLAT_PUBLIC_POLICY) $(PLAT_PRIVATE_POLICY) $(BOARD_SEPOLICY_DIRS))
+# nonplat_policy.conf - A combination of the non-platform private and the
+# exported platform policy associated with the version the non-platform policy
+# targets.  This needs attributization and to be combined with the
+# platform-provided policy.  Like plat_pub_policy.conf, this needs to make use
+# of the reqd_policy_mask files from private policy in order to use checkpolicy.
+nonplat_policy.conf := $(intermediates)/nonplat_policy.conf
+$(nonplat_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
+$(nonplat_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
+$(nonplat_policy.conf): PRIVATE_ADDITIONAL_M4DEFS := $(LOCAL_ADDITIONAL_M4DEFS)
+$(nonplat_policy.conf): $(call build_policy, $(sepolicy_build_files), \
+$(BOARD_SEPOLICY_VERS_DIR) $(REQD_MASK_POLICY) $(BOARD_SEPOLICY_DIRS))
 	@mkdir -p $(dir $@)
 	$(hide) m4 $(PRIVATE_ADDITIONAL_M4DEFS) \
 		-D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
@@ -164,10 +247,47 @@
 		-s $^ > $@
 	$(hide) sed '/dontaudit/d' $@ > $@.dontaudit
 
-$(LOCAL_BUILT_MODULE): $(sepolicy_policy.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
+nonplat_policy.cil := $(intermediates)/nonplat_policy.cil
+$(nonplat_policy.cil): $(nonplat_policy.conf) $(HOST_OUT_EXECUTABLES)/checkpolicy
 	@mkdir -p $(dir $@)
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -c $(POLICYVERS) -o $@.tmp $< > /dev/null
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -c $(POLICYVERS) -o $(dir $<)/$(notdir $@).dontaudit $<.dontaudit > /dev/null
+	$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -C -M -c $(POLICYVERS) -o $@ $<
+
+pruned_nonplat_policy.cil := $(intermediates)/pruned_nonplat_policy.cil
+$(pruned_nonplat_policy.cil): $(reqd_policy_mask.cil) $(nonplat_policy.cil)
+	@mkdir -p $(dir $@)
+	$(hide) grep -Fxv -f $^ | grep -v neverallow > $@
+
+vers_nonplat_policy.cil := $(intermediates)/vers_nonplat_policy.cil
+$(vers_nonplat_policy.cil) : PRIVATE_VERS := $(BOARD_SEPOLICY_VERS)
+$(vers_nonplat_policy.cil) : PRIVATE_TGT_POL := $(pruned_nonplat_policy.cil)
+$(vers_nonplat_policy.cil) : $(pruned_plat_pub_policy.cil) $(pruned_nonplat_policy.cil) \
+$(HOST_OUT_EXECUTABLES)/version_policy
+	@mkdir -p $(dir $@)
+	$(HOST_OUT_EXECUTABLES)/version_policy -b $< -t $(PRIVATE_TGT_POL) -n $(PRIVATE_VERS) -o $@
+
+# auto-generate the mapping file for current platform policy, since it needs to
+# track platform policy development
+current_mapping.cil := $(intermediates)/mapping/current.cil
+$(current_mapping.cil) : PRIVATE_VERS := $(BOARD_SEPOLICY_VERS)
+$(current_mapping.cil) : $(pruned_plat_pub_policy.cil) $(HOST_OUT_EXECUTABLES)/version_policy
+	@mkdir -p $(dir $@)
+	$(hide) $(HOST_OUT_EXECUTABLES)/version_policy -b $< -m -n $(PRIVATE_VERS) -o $@
+
+ifeq ($(BOARD_SEPOLICY_VERS), current)
+mapping.cil := $(current_mapping.cil)
+else
+mapping.cil := $(addsuffix /$(BOARD_SEPOLICY_VERS).cil, $(PLAT_PRIVATE_POLICY)/mapping)
+endif
+
+all_cil_files := \
+    $(plat_policy.cil) \
+    $(vers_nonplat_policy.cil) \
+    $(mapping.cil)
+
+$(LOCAL_BUILT_MODULE): PRIVATE_CIL_FILES := $(all_cil_files)
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_EXECUTABLES)/secilc $(HOST_OUT_EXECUTABLES)/sepolicy-analyze $(all_cil_files)
+	@mkdir -p $(dir $@)
+	$(hide) $< -M true -c $(POLICYVERS) $(PRIVATE_CIL_FILES) -o $@.tmp
 	$(hide) $(HOST_OUT_EXECUTABLES)/sepolicy-analyze $@.tmp permissive > $@.permissivedomains
 	$(hide) if [ "$(TARGET_BUILD_VARIANT)" = "user" -a -s $@.permissivedomains ]; then \
 		echo "==========" 1>&2; \
@@ -179,6 +299,20 @@
 	$(hide) mv $@.tmp $@
 
 built_sepolicy := $(LOCAL_BUILT_MODULE)
+reqd_policy_mask.conf :=
+reqd_policy_mask.cil :=
+plat_pub_policy.conf :=
+plat_pub_policy.cil :=
+pruned_plat_pub_policy.cil :=
+plat_policy.conf :=
+plat_policy.cil :=
+nonplat_policy.conf :=
+nonplat_policy.cil :=
+pruned_nonplat_policy.cil :=
+vers_nonplat_policy.cil :=
+current_mapping.cil :=
+mapping.cil :=
+all_cil_files :=
 sepolicy_policy.conf :=
 
 ##################################
@@ -311,7 +445,7 @@
 $(file_contexts.device.sorted.tmp): PRIVATE_SEPOLICY := $(built_sepolicy)
 $(file_contexts.device.sorted.tmp): $(file_contexts.device.tmp) $(built_sepolicy) $(HOST_OUT_EXECUTABLES)/fc_sort $(HOST_OUT_EXECUTABLES)/checkfc
 	@mkdir -p $(dir $@)
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc -e $(PRIVATE_SEPOLICY) $<
+	# TODO: fix with attributized types $(hide) $(HOST_OUT_EXECUTABLES)/checkfc -e $(PRIVATE_SEPOLICY) $<
 	$(hide) $(HOST_OUT_EXECUTABLES)/fc_sort $< $@
 
 file_contexts.concat.tmp := $(intermediates)/file_contexts.concat.tmp
@@ -322,7 +456,7 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_SEPOLICY := $(built_sepolicy)
 $(LOCAL_BUILT_MODULE): $(file_contexts.concat.tmp) $(built_sepolicy) $(HOST_OUT_EXECUTABLES)/sefcontext_compile $(HOST_OUT_EXECUTABLES)/checkfc
 	@mkdir -p $(dir $@)
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc $(PRIVATE_SEPOLICY) $<
+	# TODO: fix with attributized types	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc $(PRIVATE_SEPOLICY) $<
 	$(hide) $(HOST_OUT_EXECUTABLES)/sefcontext_compile -o $@ $<
 
 built_fc := $(LOCAL_BUILT_MODULE)
@@ -352,7 +486,7 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_SEPOLICY := $(built_general_sepolicy)
 $(LOCAL_BUILT_MODULE): $(general_file_contexts.tmp) $(built_general_sepolicy) $(HOST_OUT_EXECUTABLES)/sefcontext_compile $(HOST_OUT_EXECUTABLES)/checkfc
 	@mkdir -p $(dir $@)
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc $(PRIVATE_SEPOLICY) $<
+	#  TODO: fix with attributized types $(hide) $(HOST_OUT_EXECUTABLES)/checkfc $(PRIVATE_SEPOLICY) $<
 	$(hide) $(HOST_OUT_EXECUTABLES)/sefcontext_compile -o $@ $<
 
 general_file_contexts.tmp :=
@@ -433,7 +567,7 @@
 $(LOCAL_BUILT_MODULE): $(property_contexts.tmp) $(built_sepolicy) $(HOST_OUT_EXECUTABLES)/checkfc
 	@mkdir -p $(dir $@)
 	$(hide) sed -e 's/#.*$$//' -e '/^$$/d' $< > $@
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc -p $(PRIVATE_SEPOLICY) $@
+	# TODO: fix with attributized types $(hide) $(HOST_OUT_EXECUTABLES)/checkfc -p $(PRIVATE_SEPOLICY) $@
 
 built_pc := $(LOCAL_BUILT_MODULE)
 all_pc_files :=
@@ -458,7 +592,7 @@
 $(LOCAL_BUILT_MODULE): $(general_property_contexts.tmp) $(built_general_sepolicy) $(HOST_OUT_EXECUTABLES)/checkfc $(ACP)
 	@mkdir -p $(dir $@)
 	$(hide) sed -e 's/#.*$$//' -e '/^$$/d' $< > $@
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc -p $(PRIVATE_SEPOLICY) $@
+	# TODO: fix with attributized types $(hide) $(HOST_OUT_EXECUTABLES)/checkfc -p $(PRIVATE_SEPOLICY) $@
 
 general_property_contexts.tmp :=
 
@@ -486,7 +620,7 @@
 $(LOCAL_BUILT_MODULE): $(service_contexts.tmp) $(built_sepolicy) $(HOST_OUT_EXECUTABLES)/checkfc $(ACP)
 	@mkdir -p $(dir $@)
 	sed -e 's/#.*$$//' -e '/^$$/d' $< > $@
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc -s $(PRIVATE_SEPOLICY) $@
+	# TODO: fix with attributized types$(hide) $(HOST_OUT_EXECUTABLES)/checkfc -s $(PRIVATE_SEPOLICY) $@
 
 built_svc := $(LOCAL_BUILT_MODULE)
 all_svc_files :=
@@ -511,7 +645,7 @@
 $(LOCAL_BUILT_MODULE): $(general_service_contexts.tmp) $(built_general_sepolicy) $(HOST_OUT_EXECUTABLES)/checkfc $(ACP)
 	@mkdir -p $(dir $@)
 	sed -e 's/#.*$$//' -e '/^$$/d' $< > $@
-	$(hide) $(HOST_OUT_EXECUTABLES)/checkfc -s $(PRIVATE_SEPOLICY) $@
+	# TODO: fix with attributized types $(hide) $(HOST_OUT_EXECUTABLES)/checkfc -s $(PRIVATE_SEPOLICY) $@
 
 general_service_contexts.tmp :=