#!/bin/bash # Copyright 2016 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. . "$(dirname "$0")/common.sh" . "$(dirname "$0")/lib/sign_android_lib.sh" set -e # Print usage string usage() { cat < /dev/null # Copy the content instead of mv to avoid owner/mode changes. sudo cp "${signed_apk}" "${apk}" && rm -f "${signed_apk}" # Set timestamp rounded to second since squash file system has resolution # in seconds. Required in order for the packages cache generator output is # compatible with the packed file system. sudo touch "${apk}" -t "$(date +%m%d%H%M.%S)" : $(( counter_${keyname} += 1 )) : $(( counter_total += 1 )) done < <(find "${system_mnt}/system" -type f -name '*.apk' -print0) info "Found ${counter_platform} platform APKs." info "Found ${counter_media} media APKs." info "Found ${counter_shared} shared APKs." info "Found ${counter_releasekey} release APKs." info "Found ${counter_total} total APKs." # Sanity check. if [[ ${counter_platform} -lt 2 || ${counter_media} -lt 2 || ${counter_shared} -lt 2 || ${counter_releasekey} -lt 2 || ${counter_total} -lt 25 ]]; then die "Number of re-signed package seems to be wrong" fi } # Platform key is part of the SELinux policy. Since we are re-signing framework # apks, we need to replace the key in the policy as well. update_sepolicy() { local system_mnt=$1 local key_dir=$2 # Only platform is used at this time. local public_platform_key="${key_dir}/platform.x509.pem" info "Start updating sepolicy" local new_cert=$(sed -E '/(BEGIN|END) CERTIFICATE/d' \ "${public_platform_key}" | tr -d '\n' \ | base64 --decode | hexdump -v -e '/1 "%02x"') if [[ -z "${new_cert}" ]]; then die "Unable to get the public platform key" fi shopt -s nullglob local xml_list=( "${system_mnt}"/system/etc/**/*mac_permissions.xml ) shopt -u nullglob if [[ "${#xml_list[@]}" -ne 1 ]]; then die "Unexpected number of *mac_permissions.xml: ${#xml_list[@]}\n \ ${xml_list[*]}" fi local xml="${xml_list[0]}" local orig=$(make_temp_file) local pattern='( /dev/null cp "${release_cert}" . local temp_zip=$(make_temp_file) zip -q -r "${temp_zip}.zip" . # Copy the content instead of mv to avoid owner/mode changes. sudo cp "${temp_zip}.zip" "${ota_zip}" popd > /dev/null } # Restore SELinux context. This has to run after all file changes, before # creating the new squashfs image. reapply_file_security_context() { local system_mnt=$1 local root_fs_dir=$2 info "Reapplying file security context" sudo /sbin/setfiles -v -r "${system_mnt}" \ "${root_fs_dir}/etc/selinux/arc/contexts/files/android_file_contexts" \ "${system_mnt}" } # Snapshot file properties in a directory recursively. snapshot_file_properties() { local dir=$1 sudo find "${dir}" -exec stat -c '%n:%u:%g:%a:%C' {} + | sort } main() { local root_fs_dir=$1 local key_dir=$2 local android_dir="${root_fs_dir}/opt/google/containers/android" local system_img="${android_dir}/system.raw.img" # Use the versions in $PATH rather than the system ones. local unsquashfs=$(which unsquashfs) local mksquashfs=$(which mksquashfs) if [[ $# -ne 2 ]]; then usage "command takes exactly 2 args" fi if [[ ! -f "${system_img}" ]]; then die "System image does not exist: ${system_img}" fi if ! type -P zipalign &>/dev/null || ! type -P signapk &>/dev/null; then # TODO(victorhsieh): Make this an error. This is not treating as error # just to make an unrelated test pass by skipping this signing. warn "Skip signing Android apks (some of executables are not found)." exit 0 fi local working_dir=$(make_temp_dir) local system_mnt="${working_dir}/mnt" local compression_method=$(sudo unsquashfs -s "${system_img}" | \ awk '$1 == "Compression" { print $2 }') info "Unpacking squashfs system image to ${system_mnt}" sudo "${unsquashfs}" -x -f -no-progress -d "${system_mnt}" "${system_img}" snapshot_file_properties "${system_mnt}" > "${working_dir}/properties.orig" sign_framework_apks "${system_mnt}" "${key_dir}" update_sepolicy "${system_mnt}" "${key_dir}" replace_ota_cert "${system_mnt}" "${key_dir}/releasekey.x509.pem" reapply_file_security_context "${system_mnt}" "${root_fs_dir}" # Sanity check. snapshot_file_properties "${system_mnt}" > "${working_dir}/properties.new" local d if ! d=$(diff "${working_dir}"/properties.{orig,new}); then die "Unexpected change of file property, diff\n${d}" fi # Packages cache needs to be regenerated when the key and timestamp are # changed for apks. local packages_cache="${system_mnt}/system/etc/packages_cache.xml" if [[ -f "${packages_cache}" ]]; then if type -P aapt &>/dev/null; then info "Regenerating packages cache ${packages_cache}" # For the sanity check. local packages_before=$(grep " ${new_size}" } main "$@"