#!/bin/bash # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # Usage: make_more_helpers.sh # # This script creates additional helper .app bundles for Chromium, based on # the existing helper .app bundle, changing their Mach-O header's flags to # enable and disable various features. Based on Chromium Helper.app, it will # create Chromium Helper EH.app, which has the MH_NO_HEAP_EXECUTION bit # cleared to support Chromium child processes that require an executable heap, # and Chromium Helper NP.app, which has the MH_PIE bit cleared to support # Chromium child processes that cannot tolerate ASLR. # # This script expects to be called from the chrome_exe target as a postbuild, # and operates directly within the built-up browser app's versioned directory. # # Each helper is adjusted by giving it the proper bundle name, renaming the # executable, adjusting several Info.plist keys, and changing the executable's # Mach-O flags. set -eu proc make_helper { var containing_dir = $(1) var app_name = $(2) var feature = $(3) var flags = $(4) var helper_name = ""$(app_name) Helper"" var helper_stem = ""$(containing_dir)/$(helper_name)"" var original_helper = ""$(helper_stem).app"" if [[ ! -d "${original_helper}" ]] { echo "$(0): error: $(original_helper) is a required directory" > !2 exit 1 } var original_helper_exe = ""$(original_helper)/Contents/MacOS/$(helper_name)"" if [[ ! -f "${original_helper_exe}" ]] { echo "$(0): error: $(original_helper_exe) is a required file" > !2 exit 1 } var feature_helper = ""$(helper_stem) $(feature).app"" rsync -acC --delete --include '*.so' "$(original_helper)/" $(feature_helper) var helper_feature = ""$(helper_name) $(feature)"" var helper_feature_exe = ""$(feature_helper)/Contents/MacOS/$(helper_feature)"" mv "$(feature_helper)/Contents/MacOS/$(helper_name)" $(helper_feature_exe) var change_flags = ""$[dirname $(0)]/change_mach_o_flags.py"" $(change_flags) $(flags) $(helper_feature_exe) var feature_info = ""$(feature_helper)/Contents/Info"" var feature_info_plist = ""$(feature_info).plist"" defaults write $(feature_info) "CFBundleDisplayName" $(helper_feature) defaults write $(feature_info) "CFBundleExecutable" $(helper_feature) global cfbundleid := $[defaults read $(feature_info) "CFBundleIdentifier] global feature_cfbundleid := ""$(cfbundleid).$(feature)"" defaults write $(feature_info) "CFBundleIdentifier" $(feature_cfbundleid) global cfbundlename := $[defaults read $(feature_info) "CFBundleName] global feature_cfbundlename := ""$(cfbundlename) $(feature)"" defaults write $(feature_info) "CFBundleName" $(feature_cfbundlename) # As usual, defaults might have put the plist into whatever format excites # it, but Info.plists get converted back to the expected XML format. plutil -convert xml1 $(feature_info_plist) # `defaults` also changes the file permissions, so make the file # world-readable again. chmod a+r $(feature_info_plist) } if [[ ${#} -ne 2 ]] { echo "usage: $(0) " > !2 exit 1 } global DIRECTORY_WITHIN_CONTENTS := $(1) global APP_NAME := $(2) global CONTENTS_DIR := ""$(BUILT_PRODUCTS_DIR)/$(CONTENTS_FOLDER_PATH)"" global CONTAINING_DIR := ""$(CONTENTS_DIR)/$(DIRECTORY_WITHIN_CONTENTS)"" make_helper $(CONTAINING_DIR) $(APP_NAME) "EH" "--executable-heap" make_helper $(CONTAINING_DIR) $(APP_NAME) "NP" "--no-pie" (CommandList children: [ (C {(set)} {(-eu)}) (FuncDef name: make_helper body: (BraceGroup children: [ (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:containing_dir) op: Equal rhs: {(DQ (${ VSub_Number 1))} spids: [77] ) ] spids: [75] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:app_name) op: Equal rhs: {(DQ (${ VSub_Number 2))} spids: [87] ) ] spids: [85] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:feature) op: Equal rhs: {(DQ (${ VSub_Number 3))} spids: [97] ) ] spids: [95] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:flags) op: Equal rhs: {(DQ (${ VSub_Number 4))} spids: [107] ) ] spids: [105] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:helper_name) op: Equal rhs: {(DQ (${ VSub_Name app_name) (" Helper"))} spids: [118] ) ] spids: [116] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:helper_stem) op: Equal rhs: {(DQ (${ VSub_Name containing_dir) (/) (${ VSub_Name helper_name))} spids: [129] ) ] spids: [127] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:original_helper) op: Equal rhs: {(DQ (${ VSub_Name helper_stem) (.app))} spids: [143] ) ] spids: [141] ) (If arms: [ (if_arm cond: [ (Sentence child: (DBracket expr: (LogicalNot child: (BoolUnary op_id: BoolUnary_d child: {(DQ (${ VSub_Name original_helper))} ) ) ) terminator: ) ] action: [ (SimpleCommand words: [ {(echo)} { (DQ (${ VSub_Number 0) (": error: ") (${ VSub_Name original_helper) (" is a required directory") ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[185])] ) (C {(exit)} {(1)}) ] spids: [-1 169] ) ] spids: [-1 195] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:original_helper_exe) op: Equal rhs: { (DQ (${ VSub_Name original_helper) (/Contents/MacOS/) (${ VSub_Name helper_name)) } spids: [200] ) ] spids: [198] ) (If arms: [ (if_arm cond: [ (Sentence child: (DBracket expr: (LogicalNot child: (BoolUnary op_id: BoolUnary_f child: {(DQ (${ VSub_Name original_helper_exe))} ) ) ) terminator: ) ] action: [ (SimpleCommand words: [ {(echo)} { (DQ (${ VSub_Number 0) (": error: ") (${ VSub_Name original_helper_exe) (" is a required file") ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[245])] ) (C {(exit)} {(1)}) ] spids: [-1 229] ) ] spids: [-1 255] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:feature_helper) op: Equal rhs: {(DQ (${ VSub_Name helper_stem) (" ") (${ VSub_Name feature) (.app))} spids: [261] ) ] spids: [259] ) (C {(rsync)} {(-acC)} {(--delete)} {(--include)} {(SQ <"*.so">)} {(DQ (${ VSub_Name original_helper) (/))} {(DQ (${ VSub_Name feature_helper))} ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:helper_feature) op: Equal rhs: {(DQ (${ VSub_Name helper_name) (" ") (${ VSub_Name feature))} spids: [304] ) ] spids: [302] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:helper_feature_exe) op: Equal rhs: { (DQ (${ VSub_Name feature_helper) (/Contents/MacOS/) (${ VSub_Name helper_feature) ) } spids: [318] ) ] spids: [316] ) (C {(mv)} {(DQ (${ VSub_Name feature_helper) (/Contents/MacOS/) (${ VSub_Name helper_name))} {(DQ (${ VSub_Name helper_feature_exe))} ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:change_flags) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children: [(C {(dirname)} {(DQ (${ VSub_Number 0))})] ) left_token: spids: [354 362] ) (/change_mach_o_flags.py) ) } spids: [352] ) ] spids: [350] ) (C {(DQ (${ VSub_Name change_flags))} {(${ VSub_Name flags)} {(DQ (${ VSub_Name helper_feature_exe))} ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:feature_info) op: Equal rhs: {(DQ (${ VSub_Name feature_helper) (/Contents/Info))} spids: [387] ) ] spids: [385] ) (Assignment keyword: Assign_Local pairs: [ (assign_pair lhs: (LhsName name:feature_info_plist) op: Equal rhs: {(DQ (${ VSub_Name feature_info) (.plist))} spids: [398] ) ] spids: [396] ) (C {(defaults)} {(write)} {(DQ (${ VSub_Name feature_info))} {(DQ (CFBundleDisplayName))} {(DQ (${ VSub_Name helper_feature))} ) (C {(defaults)} {(write)} {(DQ (${ VSub_Name feature_info))} {(DQ (CFBundleExecutable))} {(DQ (${ VSub_Name helper_feature))} ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:cfbundleid) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children: [ (C {(defaults)} {(read)} {(DQ (${ VSub_Name feature_info))} {(DQ (CFBundleIdentifier))} ) ] ) left_token: spids: [453 467] ) ) } spids: [451] ) ] spids: [451] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:feature_cfbundleid) op: Equal rhs: {(DQ (${ VSub_Name cfbundleid) (.) (${ VSub_Name feature))} spids: [471] ) ] spids: [471] ) (C {(defaults)} {(write)} {(DQ (${ VSub_Name feature_info))} {(DQ (CFBundleIdentifier))} {(DQ (${ VSub_Name feature_cfbundleid))} ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:cfbundlename) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children: [ (C {(defaults)} {(read)} {(DQ (${ VSub_Name feature_info))} {(DQ (CFBundleName))} ) ] ) left_token: spids: [507 521] ) ) } spids: [505] ) ] spids: [505] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:feature_cfbundlename) op: Equal rhs: {(DQ (${ VSub_Name cfbundlename) (" ") (${ VSub_Name feature))} spids: [525] ) ] spids: [525] ) (C {(defaults)} {(write)} {(DQ (${ VSub_Name feature_info))} {(DQ (CFBundleName))} {(DQ (${ VSub_Name feature_cfbundlename))} ) (C {(plutil)} {(-convert)} {(xml1)} {(DQ (${ VSub_Name feature_info_plist))}) (C {(chmod)} {(a) (Lit_Other "+") (r)} {(DQ (${ VSub_Name feature_info_plist))}) ] spids: [72] ) spids: [68 71] ) (If arms: [ (if_arm cond: [ (Sentence child: (DBracket expr: (BoolBinary op_id:BoolBinary_ne left:{(${ VSub_Pound "#")} right:{(2)}) ) terminator: ) ] action: [ (SimpleCommand words: [ {(echo)} {(DQ ("usage: ") (${ VSub_Number 0) (" "))} ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[632])] ) (C {(exit)} {(1)}) ] spids: [-1 619] ) ] spids: [-1 641] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:DIRECTORY_WITHIN_CONTENTS) op: Equal rhs: {(DQ (${ VSub_Number 1))} spids: [644] ) ] spids: [644] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:APP_NAME) op: Equal rhs: {(DQ (${ VSub_Number 2))} spids: [651] ) ] spids: [651] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:CONTENTS_DIR) op: Equal rhs: {(DQ (${ VSub_Name BUILT_PRODUCTS_DIR) (/) (${ VSub_Name CONTENTS_FOLDER_PATH))} spids: [659] ) ] spids: [659] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:CONTAINING_DIR) op: Equal rhs: {(DQ (${ VSub_Name CONTENTS_DIR) (/) (${ VSub_Name DIRECTORY_WITHIN_CONTENTS))} spids: [670] ) ] spids: [670] ) (C {(make_helper)} {(DQ (${ VSub_Name CONTAINING_DIR))} {(DQ (${ VSub_Name APP_NAME))} {(DQ (EH))} {(DQ (--executable-heap))} ) (C {(make_helper)} {(DQ (${ VSub_Name CONTAINING_DIR))} {(DQ (${ VSub_Name APP_NAME))} {(DQ (NP))} {(DQ (--no-pie))} ) ] )