1#!/bin/bash 2 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# This script modifies the original GSI to match the vendor version and 18# the security patch level. 19# 20# Usage: change_security_patch_ver.sh <system.img> [<output_system.img> \ 21# [<new_security_patch_level> [<input_file_contexts.bin>]]] \ 22# [-v <vendor_version>] 23# 24# Examples: 25# change_security_patch_ver.sh system.img 26# - Shows current version information. 27# change_security_patch_ver.sh system.img new_system.img 2018-04-05 28# - Make new_system.img that has replaced SPL with 2018-04-05. 29# change_security_patch_ver.sh system.img new_system.img -v 8.1.0 30# - Make new_system.img that includes the patches for vendor version 8.1.0. 31# change_security_patch_ver.sh system.img new_system.img 2018-04-05 -v 8.1.0 32# - Make new_system.img that has both new SPL and vendor version. 33 34function unmount() { 35 echo "Unmounting..." 36 sudo umount "${MOUNT_POINT}/" 37} 38 39SCRIPT_NAME=$(basename $0) 40 41declare -a SUPPORTED_VENDOR_VERSIONS=( 42 8.1.0 43 9 44) 45SUPPORTED_VENDOR_VERSIONS="${SUPPORTED_VENDOR_VERSIONS[@]}" 46 47param_count=0 48while [[ $# -gt 0 ]] 49do 50case $1 in 51-v|--vendor) # set vendor version 52 VENDOR_VERSION=$2 53 shift 54 shift 55 ;; 56*) # set the ordered parameters 57 ((param_count++)) 58 case $param_count in 59 1) # The input file name for original GSI 60 SYSTEM_IMG=$1 61 shift 62 ;; 63 2) # The output file name for modified GSI 64 OUTPUT_SYSTEM_IMG=$1 65 shift 66 ;; 67 3) # New Security Patch Level to be written. It must be YYYY-MM-DD format. 68 NEW_SPL=$1 69 shift 70 ;; 71 4) # Selinux file context 72 FILE_CONTEXTS_BIN=$1 73 shift 74 ;; 75 *) 76 ERROR=true 77 break 78 ;; 79 esac 80 ;; 81esac 82done 83 84if ((param_count == 0)) || [ "$ERROR" == "true" ]; then 85 echo "Usage: $SCRIPT_NAME <system.img> [<output_system.img> [<new_security_patch_level> [<input_file_contexts.bin>]]] [-v <vendor_version>]" 86 exit 1 87fi 88 89# SPL must have YYYY-MM-DD format 90if ((param_count >= 3)) && [[ ! ${NEW_SPL} =~ ^[0-9]{4}-(0[0-9]|1[012])-([012][0-9]|3[01])$ ]]; then 91 echo "<new_security_patch_level> must have YYYY-MM-DD format" 92 exit 1 93fi 94 95if [ "$VENDOR_VERSION" != "" ] && [[ ! ${VENDOR_VERSION} =~ ^(${SUPPORTED_VENDOR_VERSIONS// /\|})$ ]]; then 96 echo "Available vendor_version: $SUPPORTED_VENDOR_VERSIONS" 97 exit 1 98fi 99 100if [ "$VENDOR_VERSION" != "" ] && [ "$OUTPUT_SYSTEM_IMG" == "" ]; then 101 echo "<output_system.img> must be provided to set vendor version" 102 exit 1 103fi 104 105REQUIRED_BINARIES_LIST=( 106 "img2simg" 107 "simg2img" 108) 109if [ ! -z "${FILE_CONTEXTS_BIN}" ]; then 110 REQUIRED_BINARIES_LIST+=("mkuserimg_mke2fs") 111fi 112 113# number of binaries to find. 114BIN_COUNT=${#REQUIRED_BINARIES_LIST[@]} 115 116# use an associative array to store binary path 117declare -A BIN_PATH 118for bin in ${REQUIRED_BINARIES_LIST[@]}; do 119 BIN_PATH[${bin}]="" 120done 121 122# check current PATH environment first 123for bin in ${REQUIRED_BINARIES_LIST[@]}; do 124 if command -v ${bin} >/dev/null 2>&1; then 125 echo "found ${bin} in PATH." 126 BIN_PATH[${bin}]=${bin} 127 ((BIN_COUNT--)) 128 fi 129done 130 131if [ ${BIN_COUNT} -gt 0 ]; then 132 # listed in the recommended order. 133 PATH_LIST=("${PWD}") 134 if [ "${PWD##*/}" == "testcases" ] && [ -d "${PWD}/../bin" ]; then 135 PATH_LIST+=("${PWD}/../bin") 136 fi 137 if [ -d "${ANDROID_HOST_OUT}" ]; then 138 PATH_LIST+=("${ANDROID_HOST_OUT}/bin") 139 fi 140 141 for dir in ${PATH_LIST[@]}; do 142 for bin in ${REQUIRED_BINARIES_LIST[@]}; do 143 if [ -z "${BIN_PATH[${bin}]}" ] && [ -f "${dir}/${bin}" ]; then 144 echo "found ${bin} in ${dir}." 145 BIN_PATH[${bin}]=${dir}/${bin} 146 ((BIN_COUNT--)) 147 if [ ${BIN_COUNT} -eq 0 ]; then break; fi 148 fi 149 done 150 done 151fi 152 153if [ ${BIN_COUNT} -gt 0 ]; then 154 echo "Cannot find the required binaries. Need lunch; or run in a correct path." 155 exit 1 156fi 157echo "Found all binaries." 158 159MOUNT_POINT="${PWD}/temp_mnt" 160SPL_PROPERTY_NAME="ro.build.version.security_patch" 161RELEASE_VERSION_PROPERTY_NAME="ro.build.version.release" 162VNDK_VERSION_PROPERTY="ro.vndk.version" 163VNDK_VERSION_PROPERTY_OMR1="${VNDK_VERSION_PROPERTY}=27" 164 165UNSPARSED_SYSTEM_IMG="${SYSTEM_IMG}.raw" 166SYSTEM_IMG_MAGIC="$(xxd -g 4 -l 4 "$SYSTEM_IMG" | head -n1 | awk '{print $2}')" 167if [ "$SYSTEM_IMG_MAGIC" = "3aff26ed" ]; then 168 echo "Unsparsing ${SYSTEM_IMG}..." 169 ${BIN_PATH["simg2img"]} "$SYSTEM_IMG" "$UNSPARSED_SYSTEM_IMG" 170else 171 echo "Copying unsparse input system image ${SYSTEM_IMG}..." 172 cp "$SYSTEM_IMG" "$UNSPARSED_SYSTEM_IMG" 173fi 174 175IMG_SIZE=$(stat -c%s "$UNSPARSED_SYSTEM_IMG") 176 177echo "Mounting..." 178mkdir -p "$MOUNT_POINT" 179sudo mount -t ext4 -o loop "$UNSPARSED_SYSTEM_IMG" "${MOUNT_POINT}/" 180 181# check the property file path 182BUILD_PROP_PATH_LIST=( 183 "/system/build.prop" # layout of A/B support 184 "/build.prop" # layout of non-A/B support 185) 186BUILD_PROP_MOUNT_PATH="" 187BUILD_PROP_PATH="" 188 189echo "Finding build.prop..." 190for path in ${BUILD_PROP_PATH_LIST[@]}; do 191 if [ -f "${MOUNT_POINT}${path}" ]; then 192 BUILD_PROP_MOUNT_PATH="${MOUNT_POINT}${path}" 193 BUILD_PROP_PATH=${path} 194 echo " ${path}" 195 break 196 fi 197done 198 199PROP_DEFAULT_PATH_LIST=( 200 "/system/etc/prop.default" # layout of A/B support 201 "/etc/prop.default" # layout of non-A/B support 202) 203 204if [ "$BUILD_PROP_MOUNT_PATH" != "" ]; then 205 if [ "$OUTPUT_SYSTEM_IMG" != "" ]; then 206 echo "Replacing..." 207 fi 208 CURRENT_SPL=`sudo sed -n -r "s/^${SPL_PROPERTY_NAME}=(.*)$/\1/p" ${BUILD_PROP_MOUNT_PATH}` 209 CURRENT_VERSION=`sudo sed -n -r "s/^${RELEASE_VERSION_PROPERTY_NAME}=(.*)$/\1/p" ${BUILD_PROP_MOUNT_PATH}` 210 echo " Current security patch level: ${CURRENT_SPL}" 211 echo " Current release version: ${CURRENT_VERSION}" 212 213 # Update SPL to <new_security_patch_level> 214 if [[ "$OUTPUT_SYSTEM_IMG" != "" && "$NEW_SPL" != "" ]]; then 215 if [[ "$CURRENT_SPL" == "" ]]; then 216 echo "ERROR: Cannot find ${SPL_PROPERTY_NAME} in ${BUILD_PROP_PATH}" 217 else 218 echo " New security patch level: ${NEW_SPL}" 219 seek=$(sudo grep --byte-offset "${SPL_PROPERTY_NAME}=" "${BUILD_PROP_MOUNT_PATH}" | cut -d':' -f 1) 220 seek=$(($seek + ${#SPL_PROPERTY_NAME} + 1)) # 1 is for '=' 221 echo "${NEW_SPL}" | sudo dd of="${BUILD_PROP_MOUNT_PATH}" seek="$seek" bs=1 count=10 conv=notrunc 222 fi 223 fi 224 225 # Update release version to <vendor_version> 226 if [[ "$OUTPUT_SYSTEM_IMG" != "" && "$VENDOR_VERSION" != "" ]]; then 227 if [[ "$CURRENT_VERSION" == "" ]]; then 228 echo "ERROR: Cannot find ${RELEASE_VERSION_PROPERTY_NAME} in ${BUILD_PROP_PATH}" 229 else 230 echo " New release version for vendor.img: ${VENDOR_VERSION}" 231 sudo sed -i -e "s/^${RELEASE_VERSION_PROPERTY_NAME}=.*$/${RELEASE_VERSION_PROPERTY_NAME}=${VENDOR_VERSION}/" ${BUILD_PROP_MOUNT_PATH} 232 fi 233 234 if [[ "$VENDOR_VERSION" == "8.1.0" ]]; then 235 # add ro.vndk.version for O-MR1 236 echo "Finding prop.default..." 237 for path in ${PROP_DEFAULT_PATH_LIST[@]}; do 238 if [ -f "${MOUNT_POINT}${path}" ]; then 239 PROP_DEFAULT_PATH=${path} 240 echo " ${path}" 241 break 242 fi 243 done 244 245 if [[ "$PROP_DEFAULT_PATH" != "" ]]; then 246 CURRENT_VNDK_VERSION=`sudo sed -n -r "s/^${VNDK_VERSION_PROPERTY}=(.*)$/\1/p" ${MOUNT_POINT}${PROP_DEFAULT_PATH}` 247 if [[ "$CURRENT_VNDK_VERSION" != "" ]]; then 248 echo "WARNING: ${VNDK_VERSION_PROPERTY} is already set to ${CURRENT_VNDK_VERSION} in ${PROP_DEFAULT_PATH}" 249 else 250 echo " Add \"${VNDK_VERSION_PROPERTY_OMR1}\" to ${PROP_DEFAULT_PATH} for O-MR1 vendor image." 251 sudo sed -i -e "\$a\#\n\# FOR O-MR1 DEVICES\n\#\n${VNDK_VERSION_PROPERTY_OMR1}" ${MOUNT_POINT}${PROP_DEFAULT_PATH} 252 fi 253 else 254 echo "ERROR: Cannot find prop.default." 255 fi 256 fi 257 fi 258else 259 echo "ERROR: Cannot find build.prop." 260fi 261 262if [ "$OUTPUT_SYSTEM_IMG" != "" ]; then 263 if [ "$FILE_CONTEXTS_BIN" != "" ]; then 264 echo "Writing ${OUTPUT_SYSTEM_IMG}..." 265 266 (cd $ANDROID_BUILD_TOP 267 if [[ "$(whereis mkuserimg_mke2fs | wc -w)" < 2 ]]; then 268 make mkuserimg_mke2fs -j 269 fi 270 NON_AB=$(expr "$BUILD_PROP_PATH" == "/build.prop") 271 if [ $NON_AB -eq 1 ]; then 272 sudo /bin/bash -c "PATH=out/host/linux-x86/bin/:\$PATH mkuserimg_mke2fs -s ${MOUNT_POINT} $OUTPUT_SYSTEM_IMG ext4 system $IMG_SIZE -D ${MOUNT_POINT} -L system $FILE_CONTEXTS_BIN" 273 else 274 sudo /bin/bash -c "PATH=out/host/linux-x86/bin/:\$PATH mkuserimg_mke2fs -s ${MOUNT_POINT} $OUTPUT_SYSTEM_IMG ext4 / $IMG_SIZE -D ${MOUNT_POINT}/system -L / $FILE_CONTEXTS_BIN" 275 fi) 276 277 unmount 278 else 279 unmount 280 281 echo "Writing ${OUTPUT_SYSTEM_IMG}..." 282 ${BIN_PATH["img2simg"]} "$UNSPARSED_SYSTEM_IMG" "$OUTPUT_SYSTEM_IMG" 283 fi 284else 285 unmount 286fi 287 288echo "Done." 289