Allow /postinstall files to have custom contexts
We were mounting /postinstall with a 'context=...' option. This forces
all files within /postinstall to have a single selinux context,
limiting the possible granularity of our policies. Here we change it
to simply default to the 'postinstall_file' context for the 'system'
partition but allow individual files to have their own custom contexts
defined by /system/sepolicy. Other partitions retain the single
'postinstall_file' context.
The sample_images were updated to manually add a selinux label for
testing FS contexts.
Test: Manual OTA of blueline
Test: atest update_engine_unittests
Bug: 181182967
Change-Id: I0b8c2b2228fa08afecb64da9c276737eb9ae3631
diff --git a/aosp/hardware_android.cc b/aosp/hardware_android.cc
index 0ac82d6..624cfc9 100644
--- a/aosp/hardware_android.cc
+++ b/aosp/hardware_android.cc
@@ -346,4 +346,30 @@
return error_code;
}
+// Mount options for non-system partitions. This option causes selinux treat
+// every file in the mounted filesystem as having the 'postinstall_file'
+// context, regardless of what the filesystem itself records. See "SELinux
+// User's and Administrator's Guide" for more information on this option.
+constexpr const char* kDefaultPostinstallMountOptions =
+ "context=u:object_r:postinstall_file:s0";
+
+// Mount options for system partitions. This option causes selinux to use the
+// 'postinstall_file' context as a fallback if there are no other selinux
+// contexts associated with the file in the mounted partition. See "SELinux
+// User's and Administrator's Guide" for more information on this option.
+constexpr const char* kSystemPostinstallMountOptions =
+ "defcontext=u:object_r:postinstall_file:s0";
+
+// Name of the system-partition
+constexpr std::string_view kSystemPartitionName = "system";
+
+const char* HardwareAndroid::GetPartitionMountOptions(
+ const std::string& partition_name) const {
+ if (partition_name == kSystemPartitionName) {
+ return kSystemPostinstallMountOptions;
+ } else {
+ return kDefaultPostinstallMountOptions;
+ }
+}
+
} // namespace chromeos_update_engine
diff --git a/aosp/hardware_android.h b/aosp/hardware_android.h
index 78f056e..d20e8df 100644
--- a/aosp/hardware_android.h
+++ b/aosp/hardware_android.h
@@ -64,6 +64,8 @@
[[nodiscard]] ErrorCode IsPartitionUpdateValid(
const std::string& partition_name,
const std::string& new_version) const override;
+ [[nodiscard]] const char* GetPartitionMountOptions(
+ const std::string& partition_name) const override;
private:
DISALLOW_COPY_AND_ASSIGN(HardwareAndroid);
diff --git a/aosp/platform_constants_android.cc b/aosp/platform_constants_android.cc
index f468c3b..a0a2a5e 100644
--- a/aosp/platform_constants_android.cc
+++ b/aosp/platform_constants_android.cc
@@ -31,8 +31,6 @@
// No deadline file API support on Android.
const char kOmahaResponseDeadlineFile[] = "";
const char kNonVolatileDirectory[] = "/data/misc/update_engine";
-const char kPostinstallMountOptions[] =
- "context=u:object_r:postinstall_file:s0";
} // namespace constants
} // namespace chromeos_update_engine
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 29ba607..6c25183 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -216,6 +216,17 @@
return utils::IsTimestampNewer(old_version, new_version);
}
+ const char* GetPartitionMountOptions(
+ const std::string& partition_name) const override {
+#ifdef __ANDROID__
+ // TODO(allight): This matches the declaration in hardware_android.cc but
+ // ideally shouldn't be duplicated.
+ return "defcontext=u:object_r:postinstall_file:s0";
+#else
+ return "";
+#endif
+ }
+
private:
bool is_official_build_{true};
bool is_normal_boot_mode_{true};
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index 7460097..4e820f1 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -160,6 +160,9 @@
virtual ErrorCode IsPartitionUpdateValid(
const std::string& partition_name,
const std::string& new_version) const = 0;
+
+ virtual const char* GetPartitionMountOptions(
+ const std::string& partition_name) const = 0;
};
} // namespace chromeos_update_engine
diff --git a/common/platform_constants.h b/common/platform_constants.h
index c060133..06399e5 100644
--- a/common/platform_constants.h
+++ b/common/platform_constants.h
@@ -54,10 +54,6 @@
// The stateful directory used by update_engine.
extern const char kNonVolatileDirectory[];
-// Options passed to the filesystem when mounting the new partition during
-// postinstall.
-extern const char kPostinstallMountOptions[];
-
#ifdef __ANDROID_RECOVERY__
constexpr bool kIsRecovery = true;
#else
diff --git a/cros/hardware_chromeos.cc b/cros/hardware_chromeos.cc
index a57cd78..ad0a64d 100644
--- a/cros/hardware_chromeos.cc
+++ b/cros/hardware_chromeos.cc
@@ -363,4 +363,9 @@
return ErrorCode::kSuccess;
}
+const char* HardwareChromeOS::GetPartitionMountOptions(
+ const std::string& partition_name) const {
+ return "";
+}
+
} // namespace chromeos_update_engine
diff --git a/cros/hardware_chromeos.h b/cros/hardware_chromeos.h
index 8a920ef..a64f804 100644
--- a/cros/hardware_chromeos.h
+++ b/cros/hardware_chromeos.h
@@ -68,6 +68,8 @@
ErrorCode IsPartitionUpdateValid(
const std::string& partition_name,
const std::string& new_version) const override;
+ const char* GetPartitionMountOptions(
+ const std::string& partition_name) const override;
private:
friend class HardwareChromeOSTest;
diff --git a/cros/platform_constants_chromeos.cc b/cros/platform_constants_chromeos.cc
index fe94a45..5a5a521 100644
--- a/cros/platform_constants_chromeos.cc
+++ b/cros/platform_constants_chromeos.cc
@@ -32,7 +32,6 @@
const char kOmahaResponseDeadlineFile[] = "/tmp/update-check-response-deadline";
// This directory is wiped during powerwash.
const char kNonVolatileDirectory[] = "/var/lib/update_engine";
-const char kPostinstallMountOptions[] = "";
} // namespace constants
} // namespace chromeos_update_engine
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index e3e305b..5e42089 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -191,11 +191,12 @@
}
#endif // __ANDROID__
- if (!utils::MountFilesystem(mountable_device,
- fs_mount_dir_,
- MS_RDONLY,
- partition.filesystem_type,
- constants::kPostinstallMountOptions)) {
+ if (!utils::MountFilesystem(
+ mountable_device,
+ fs_mount_dir_,
+ MS_RDONLY,
+ partition.filesystem_type,
+ hardware_->GetPartitionMountOptions(partition.name))) {
return CompletePartitionPostinstall(
1, "Error mounting the device " + mountable_device);
}
diff --git a/payload_consumer/postinstall_runner_action_unittest.cc b/payload_consumer/postinstall_runner_action_unittest.cc
index a9ed5b1..5ee2989 100644
--- a/payload_consumer/postinstall_runner_action_unittest.cc
+++ b/payload_consumer/postinstall_runner_action_unittest.cc
@@ -403,7 +403,7 @@
}
#ifdef __ANDROID__
-// Check that the postinstall file is relabeled to the postinstall label.
+// Check that the postinstall file is labeled to the postinstall_exec label.
// SElinux labels are only set on Android.
TEST_F(PostinstallRunnerActionTest, RunAsRootCheckFileContextsTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
@@ -411,6 +411,15 @@
loop.dev(), "bin/self_check_context", false, false, false);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
}
+
+// Check that the postinstall file is relabeled to the default postinstall
+// label. SElinux labels are only set on Android.
+TEST_F(PostinstallRunnerActionTest, RunAsRootCheckDefaultFileContextsTest) {
+ ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
+ RunPostinstallAction(
+ loop.dev(), "bin/self_check_default_context", false, false, false);
+ EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
+}
#endif // __ANDROID__
// Check that you can suspend/resume postinstall actions.
diff --git a/sample_images/generate_images.sh b/sample_images/generate_images.sh
index e0b54ae..81a3296 100755
--- a/sample_images/generate_images.sh
+++ b/sample_images/generate_images.sh
@@ -186,14 +186,27 @@
exit 0
EOF
+ # An unlabeled postinstall bash program.
+ sudo tee "${mntdir}"/bin/self_check_default_context >/dev/null <<EOF
+#!/etc/../bin/sh
+echo "This is my context:"
+ls -lZ "\$0"
+ls -lZ "\$0" | grep -F ' u:object_r:postinstall_file:s0 ' || exit 5
+exit 0
+EOF
+
# A postinstall bash program.
sudo tee "${mntdir}"/bin/self_check_context >/dev/null <<EOF
#!/etc/../bin/sh
echo "This is my context:"
-ls -lZ "\$0" | grep -F ' u:object_r:postinstall_file:s0 ' || exit 5
+ls -lZ "\$0"
+ls -lZ "\$0" | grep -F ' u:object_r:postinstall_exec:s0 ' || exit 5
exit 0
EOF
+ # Give the test function the context we expect the postinstall-executable to have.
+ sudo setfattr -n security.selinux -v u:object_r:postinstall_exec:s0 "${mntdir}"/bin/self_check_context
+
sudo tee "${mntdir}"/postinst >/dev/null <<EOF
#!/etc/../bin/sh
echo "postinst"
diff --git a/sample_images/sample_images.tar.bz2 b/sample_images/sample_images.tar.bz2
index 5c80a51..7965d8b 100644
--- a/sample_images/sample_images.tar.bz2
+++ b/sample_images/sample_images.tar.bz2
Binary files differ
diff --git a/sample_images/sample_payloads.tar.xz b/sample_images/sample_payloads.tar.xz
index d0bf6d9..eb589ba 100644
--- a/sample_images/sample_payloads.tar.xz
+++ b/sample_images/sample_payloads.tar.xz
Binary files differ