Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 2 | # |
| 3 | # Copyright (c) 2012 Intel Corporation |
| 4 | # |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 5 | # SPDX-License-Identifier: GPL-2.0-only |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 6 | # |
| 7 | # DESCRIPTION |
| 8 | # This script is called by the SDK installer script. It replaces the dynamic |
| 9 | # loader path in all binaries and also fixes the SYSDIR paths/lengths and the |
| 10 | # location of ld.so.cache in the dynamic loader binary |
| 11 | # |
| 12 | # AUTHORS |
| 13 | # Laurentiu Palcu <laurentiu.palcu@intel.com> |
| 14 | # |
| 15 | |
| 16 | import struct |
| 17 | import sys |
| 18 | import stat |
| 19 | import os |
| 20 | import re |
| 21 | import errno |
| 22 | |
| 23 | if sys.version < '3': |
| 24 | def b(x): |
| 25 | return x |
| 26 | else: |
| 27 | def b(x): |
| 28 | return x.encode(sys.getfilesystemencoding()) |
| 29 | |
| 30 | old_prefix = re.compile(b("##DEFAULT_INSTALL_DIR##")) |
| 31 | |
| 32 | def get_arch(): |
| 33 | f.seek(0) |
| 34 | e_ident =f.read(16) |
| 35 | ei_mag0,ei_mag1_3,ei_class = struct.unpack("<B3sB11x", e_ident) |
| 36 | |
| 37 | if (ei_mag0 != 0x7f and ei_mag1_3 != "ELF") or ei_class == 0: |
| 38 | return 0 |
| 39 | |
| 40 | if ei_class == 1: |
| 41 | return 32 |
| 42 | elif ei_class == 2: |
| 43 | return 64 |
| 44 | |
| 45 | def parse_elf_header(): |
| 46 | global e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\ |
| 47 | e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx |
| 48 | |
| 49 | f.seek(0) |
| 50 | elf_header = f.read(64) |
| 51 | |
| 52 | if arch == 32: |
| 53 | # 32bit |
| 54 | hdr_fmt = "<HHILLLIHHHHHH" |
| 55 | hdr_size = 52 |
| 56 | else: |
| 57 | # 64bit |
| 58 | hdr_fmt = "<HHIQQQIHHHHHH" |
| 59 | hdr_size = 64 |
| 60 | |
| 61 | e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags,\ |
| 62 | e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx =\ |
| 63 | struct.unpack(hdr_fmt, elf_header[16:hdr_size]) |
| 64 | |
| 65 | def change_interpreter(elf_file_name): |
| 66 | if arch == 32: |
| 67 | ph_fmt = "<IIIIIIII" |
| 68 | else: |
| 69 | ph_fmt = "<IIQQQQQQ" |
| 70 | |
| 71 | """ look for PT_INTERP section """ |
| 72 | for i in range(0,e_phnum): |
| 73 | f.seek(e_phoff + i * e_phentsize) |
| 74 | ph_hdr = f.read(e_phentsize) |
| 75 | if arch == 32: |
| 76 | # 32bit |
| 77 | p_type, p_offset, p_vaddr, p_paddr, p_filesz,\ |
| 78 | p_memsz, p_flags, p_align = struct.unpack(ph_fmt, ph_hdr) |
| 79 | else: |
| 80 | # 64bit |
| 81 | p_type, p_flags, p_offset, p_vaddr, p_paddr, \ |
| 82 | p_filesz, p_memsz, p_align = struct.unpack(ph_fmt, ph_hdr) |
| 83 | |
| 84 | """ change interpreter """ |
| 85 | if p_type == 3: |
| 86 | # PT_INTERP section |
| 87 | f.seek(p_offset) |
| 88 | # External SDKs with mixed pre-compiled binaries should not get |
| 89 | # relocated so look for some variant of /lib |
| 90 | fname = f.read(11) |
| 91 | if fname.startswith(b("/lib/")) or fname.startswith(b("/lib64/")) or \ |
| 92 | fname.startswith(b("/lib32/")) or fname.startswith(b("/usr/lib32/")) or \ |
| 93 | fname.startswith(b("/usr/lib32/")) or fname.startswith(b("/usr/lib64/")): |
| 94 | break |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 95 | if p_filesz == 0: |
| 96 | break |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 97 | if (len(new_dl_path) >= p_filesz): |
| 98 | print("ERROR: could not relocate %s, interp size = %i and %i is needed." \ |
| 99 | % (elf_file_name, p_memsz, len(new_dl_path) + 1)) |
| 100 | break |
| 101 | dl_path = new_dl_path + b("\0") * (p_filesz - len(new_dl_path)) |
| 102 | f.seek(p_offset) |
| 103 | f.write(dl_path) |
| 104 | break |
| 105 | |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 106 | def change_dl_sysdirs(elf_file_name): |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 107 | if arch == 32: |
| 108 | sh_fmt = "<IIIIIIIIII" |
| 109 | else: |
| 110 | sh_fmt = "<IIQQQQIIQQ" |
| 111 | |
| 112 | """ read section string table """ |
| 113 | f.seek(e_shoff + e_shstrndx * e_shentsize) |
| 114 | sh_hdr = f.read(e_shentsize) |
| 115 | if arch == 32: |
| 116 | sh_offset, sh_size = struct.unpack("<16xII16x", sh_hdr) |
| 117 | else: |
| 118 | sh_offset, sh_size = struct.unpack("<24xQQ24x", sh_hdr) |
| 119 | |
| 120 | f.seek(sh_offset) |
| 121 | sh_strtab = f.read(sh_size) |
| 122 | |
| 123 | sysdirs = sysdirs_len = "" |
| 124 | |
| 125 | """ change ld.so.cache path and default libs path for dynamic loader """ |
| 126 | for i in range(0,e_shnum): |
| 127 | f.seek(e_shoff + i * e_shentsize) |
| 128 | sh_hdr = f.read(e_shentsize) |
| 129 | |
| 130 | sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size, sh_link,\ |
| 131 | sh_info, sh_addralign, sh_entsize = struct.unpack(sh_fmt, sh_hdr) |
| 132 | |
| 133 | name = sh_strtab[sh_name:sh_strtab.find(b("\0"), sh_name)] |
| 134 | |
| 135 | """ look only into SHT_PROGBITS sections """ |
| 136 | if sh_type == 1: |
| 137 | f.seek(sh_offset) |
| 138 | """ default library paths cannot be changed on the fly because """ |
| 139 | """ the string lengths have to be changed too. """ |
| 140 | if name == b(".sysdirs"): |
| 141 | sysdirs = f.read(sh_size) |
| 142 | sysdirs_off = sh_offset |
| 143 | sysdirs_sect_size = sh_size |
| 144 | elif name == b(".sysdirslen"): |
| 145 | sysdirslen = f.read(sh_size) |
| 146 | sysdirslen_off = sh_offset |
| 147 | elif name == b(".ldsocache"): |
| 148 | ldsocache_path = f.read(sh_size) |
| 149 | new_ldsocache_path = old_prefix.sub(new_prefix, ldsocache_path) |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 150 | new_ldsocache_path = new_ldsocache_path.rstrip(b("\0")) |
| 151 | if (len(new_ldsocache_path) >= sh_size): |
| 152 | print("ERROR: could not relocate %s, .ldsocache section size = %i and %i is needed." \ |
| 153 | % (elf_file_name, sh_size, len(new_ldsocache_path))) |
| 154 | sys.exit(-1) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 155 | # pad with zeros |
| 156 | new_ldsocache_path += b("\0") * (sh_size - len(new_ldsocache_path)) |
| 157 | # write it back |
| 158 | f.seek(sh_offset) |
| 159 | f.write(new_ldsocache_path) |
| 160 | elif name == b(".gccrelocprefix"): |
| 161 | offset = 0 |
| 162 | while (offset + 4096) <= sh_size: |
| 163 | path = f.read(4096) |
| 164 | new_path = old_prefix.sub(new_prefix, path) |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 165 | new_path = new_path.rstrip(b("\0")) |
| 166 | if (len(new_path) >= 4096): |
| 167 | print("ERROR: could not relocate %s, max path size = 4096 and %i is needed." \ |
| 168 | % (elf_file_name, len(new_path))) |
| 169 | sys.exit(-1) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 170 | # pad with zeros |
| 171 | new_path += b("\0") * (4096 - len(new_path)) |
| 172 | #print "Changing %s to %s at %s" % (str(path), str(new_path), str(offset)) |
| 173 | # write it back |
| 174 | f.seek(sh_offset + offset) |
| 175 | f.write(new_path) |
| 176 | offset = offset + 4096 |
| 177 | if sysdirs != "" and sysdirslen != "": |
| 178 | paths = sysdirs.split(b("\0")) |
| 179 | sysdirs = b("") |
| 180 | sysdirslen = b("") |
| 181 | for path in paths: |
| 182 | """ exit the loop when we encounter first empty string """ |
| 183 | if path == b(""): |
| 184 | break |
| 185 | |
| 186 | new_path = old_prefix.sub(new_prefix, path) |
| 187 | sysdirs += new_path + b("\0") |
| 188 | |
| 189 | if arch == 32: |
| 190 | sysdirslen += struct.pack("<L", len(new_path)) |
| 191 | else: |
| 192 | sysdirslen += struct.pack("<Q", len(new_path)) |
| 193 | |
| 194 | """ pad with zeros """ |
| 195 | sysdirs += b("\0") * (sysdirs_sect_size - len(sysdirs)) |
| 196 | |
| 197 | """ write the sections back """ |
| 198 | f.seek(sysdirs_off) |
| 199 | f.write(sysdirs) |
| 200 | f.seek(sysdirslen_off) |
| 201 | f.write(sysdirslen) |
| 202 | |
| 203 | # MAIN |
| 204 | if len(sys.argv) < 4: |
| 205 | sys.exit(-1) |
| 206 | |
| 207 | # In python > 3, strings may also contain Unicode characters. So, convert |
| 208 | # them to bytes |
| 209 | if sys.version_info < (3,): |
| 210 | new_prefix = sys.argv[1] |
| 211 | new_dl_path = sys.argv[2] |
| 212 | else: |
| 213 | new_prefix = sys.argv[1].encode() |
| 214 | new_dl_path = sys.argv[2].encode() |
| 215 | |
| 216 | executables_list = sys.argv[3:] |
| 217 | |
| 218 | for e in executables_list: |
| 219 | perms = os.stat(e)[stat.ST_MODE] |
| 220 | if os.access(e, os.W_OK|os.R_OK): |
| 221 | perms = None |
| 222 | else: |
| 223 | os.chmod(e, perms|stat.S_IRWXU) |
| 224 | |
| 225 | try: |
| 226 | f = open(e, "r+b") |
| 227 | except IOError: |
| 228 | exctype, ioex = sys.exc_info()[:2] |
| 229 | if ioex.errno == errno.ETXTBSY: |
| 230 | print("Could not open %s. File used by another process.\nPlease "\ |
| 231 | "make sure you exit all processes that might use any SDK "\ |
| 232 | "binaries." % e) |
| 233 | else: |
| 234 | print("Could not open %s: %s(%d)" % (e, ioex.strerror, ioex.errno)) |
| 235 | sys.exit(-1) |
| 236 | |
| 237 | # Save old size and do a size check at the end. Just a safety measure. |
| 238 | old_size = os.path.getsize(e) |
| 239 | if old_size >= 64: |
| 240 | arch = get_arch() |
| 241 | if arch: |
| 242 | parse_elf_header() |
| 243 | change_interpreter(e) |
Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 244 | change_dl_sysdirs(e) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 245 | |
| 246 | """ change permissions back """ |
| 247 | if perms: |
| 248 | os.chmod(e, perms) |
| 249 | |
| 250 | f.close() |
| 251 | |
| 252 | if old_size != os.path.getsize(e): |
| 253 | print("New file size for %s is different. Looks like a relocation error!", e) |
| 254 | sys.exit(-1) |
| 255 | |