/src/upx/src/p_vmlinx.cpp
Line | Count | Source |
1 | | /* p_vmlinx.cpp -- pack vmlinux ET_EXEC file (before bootsect or setup) |
2 | | |
3 | | This file is part of the UPX executable compressor. |
4 | | |
5 | | Copyright (C) 2004-2025 John Reiser |
6 | | Copyright (C) 1996-2025 Markus Franz Xaver Johannes Oberhumer |
7 | | Copyright (C) 1996-2025 Laszlo Molnar |
8 | | All Rights Reserved. |
9 | | |
10 | | UPX and the UCL library are free software; you can redistribute them |
11 | | and/or modify them under the terms of the GNU General Public License as |
12 | | published by the Free Software Foundation; either version 2 of |
13 | | the License, or (at your option) any later version. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, |
16 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | GNU General Public License for more details. |
19 | | |
20 | | You should have received a copy of the GNU General Public License |
21 | | along with this program; see the file COPYING. |
22 | | If not, write to the Free Software Foundation, Inc., |
23 | | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
24 | | |
25 | | Markus F.X.J. Oberhumer Laszlo Molnar |
26 | | <markus@oberhumer.com> <ezerotven+github@gmail.com> |
27 | | |
28 | | John Reiser |
29 | | <jreiser@users.sourceforge.net> |
30 | | */ |
31 | | |
32 | | |
33 | | #define ALLOW_INT_PLUS_MEMBUFFER 1 |
34 | | #include "conf.h" |
35 | | |
36 | | #include "file.h" |
37 | | #include "filter.h" |
38 | | #include "packer.h" |
39 | | #include "p_vmlinx.h" |
40 | | #include "linker.h" |
41 | | |
42 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
43 | | #include "stub/i386-linux.kernel.vmlinux.h" |
44 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
45 | | #include "stub/amd64-linux.kernel.vmlinux.h" |
46 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
47 | | #include "stub/arm.v5a-linux.kernel.vmlinux.h" |
48 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
49 | | #include "stub/armeb.v5a-linux.kernel.vmlinux.h" |
50 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
51 | | #include "stub/powerpc-linux.kernel.vmlinux.h" |
52 | | |
53 | | |
54 | | /************************************************************************* |
55 | | // |
56 | | **************************************************************************/ |
57 | | |
58 | | template <class T> |
59 | | PackVmlinuxBase<T>::PackVmlinuxBase(InputFile *f, |
60 | | unsigned e_machine, unsigned elfclass, unsigned elfdata, |
61 | | char const *const boot_label) : |
62 | 137k | super(f), |
63 | 137k | my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata), |
64 | 137k | my_boot_label(boot_label), |
65 | 137k | n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr) |
66 | 137k | { |
67 | 137k | ElfClass::compileTimeAssertions(); |
68 | 137k | bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr); |
69 | 137k | } PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::PackVmlinuxBase(InputFile*, unsigned int, unsigned int, unsigned int, char const*) Line | Count | Source | 62 | 45.7k | super(f), | 63 | 45.7k | my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata), | 64 | 45.7k | my_boot_label(boot_label), | 65 | 45.7k | n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr) | 66 | 45.7k | { | 67 | 45.7k | ElfClass::compileTimeAssertions(); | 68 | 45.7k | bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr); | 69 | 45.7k | } |
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::PackVmlinuxBase(InputFile*, unsigned int, unsigned int, unsigned int, char const*) Line | Count | Source | 62 | 45.7k | super(f), | 63 | 45.7k | my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata), | 64 | 45.7k | my_boot_label(boot_label), | 65 | 45.7k | n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr) | 66 | 45.7k | { | 67 | 45.7k | ElfClass::compileTimeAssertions(); | 68 | 45.7k | bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr); | 69 | 45.7k | } |
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::PackVmlinuxBase(InputFile*, unsigned int, unsigned int, unsigned int, char const*) Line | Count | Source | 62 | 45.7k | super(f), | 63 | 45.7k | my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata), | 64 | 45.7k | my_boot_label(boot_label), | 65 | 45.7k | n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr) | 66 | 45.7k | { | 67 | 45.7k | ElfClass::compileTimeAssertions(); | 68 | 45.7k | bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr); | 69 | 45.7k | } |
|
70 | | |
71 | | template <class T> |
72 | | PackVmlinuxBase<T>::~PackVmlinuxBase() |
73 | 137k | { |
74 | 137k | delete [] phdri; |
75 | 137k | delete [] shdri; |
76 | 137k | delete [] shstrtab; |
77 | 137k | } PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::~PackVmlinuxBase() Line | Count | Source | 73 | 45.7k | { | 74 | 45.7k | delete [] phdri; | 75 | 45.7k | delete [] shdri; | 76 | 45.7k | delete [] shstrtab; | 77 | 45.7k | } |
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::~PackVmlinuxBase() Line | Count | Source | 73 | 45.7k | { | 74 | 45.7k | delete [] phdri; | 75 | 45.7k | delete [] shdri; | 76 | 45.7k | delete [] shstrtab; | 77 | 45.7k | } |
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::~PackVmlinuxBase() Line | Count | Source | 73 | 45.7k | { | 74 | 45.7k | delete [] phdri; | 75 | 45.7k | delete [] shdri; | 76 | 45.7k | delete [] shstrtab; | 77 | 45.7k | } |
|
78 | | |
79 | | template <class T> |
80 | | int PackVmlinuxBase<T>::getStrategy(Filter &/*ft*/) |
81 | 0 | { |
82 | | // Called just before reading and compressing each block. |
83 | | // Might want to adjust blocksize, etc. |
84 | | |
85 | | // If user specified the filter, then use it (-2==strategy). |
86 | | // Else try the first two filters, and pick the better (2==strategy). |
87 | 0 | return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2)); |
88 | 0 | } Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::getStrategy(Filter&) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::getStrategy(Filter&) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::getStrategy(Filter&) |
89 | | |
90 | | template <class T> |
91 | | int __acc_cdecl_qsort |
92 | | PackVmlinuxBase<T>::compare_Phdr(void const *aa, void const *bb) |
93 | 0 | { |
94 | 0 | Phdr const *const a = (Phdr const *)aa; |
95 | 0 | Phdr const *const b = (Phdr const *)bb; |
96 | 0 | unsigned const xa = a->p_type - Phdr::PT_LOAD; |
97 | 0 | unsigned const xb = b->p_type - Phdr::PT_LOAD; |
98 | 0 | if (xa < xb) return -1; // PT_LOAD first |
99 | 0 | if (xa > xb) return 1; |
100 | 0 | if (a->p_paddr < b->p_paddr) return -1; // ascending by .p_paddr |
101 | 0 | if (a->p_paddr > b->p_paddr) return 1; |
102 | | // What could remain? |
103 | | // try to make sort order deterministic and just compare more fields |
104 | 0 | #define CMP(field) \ |
105 | 0 | if (a->field != b->field) return a->field < b->field ? -1 : 1 |
106 | 0 | CMP(p_offset); |
107 | 0 | CMP(p_vaddr); |
108 | 0 | CMP(p_filesz); |
109 | 0 | CMP(p_memsz); |
110 | 0 | CMP(p_flags); |
111 | 0 | CMP(p_align); |
112 | 0 | #undef CMP |
113 | 0 | return 0; |
114 | 0 | } Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::compare_Phdr(void const*, void const*) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::compare_Phdr(void const*, void const*) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::compare_Phdr(void const*, void const*) |
115 | | |
116 | | template <class T> |
117 | | typename T::Shdr const *PackVmlinuxBase<T>::getElfSections() |
118 | 1.73k | { |
119 | 1.73k | unsigned const e_shnum = ehdri.e_shnum; |
120 | 1.73k | if (ehdri.e_shentsize != sizeof(*shdri) |
121 | 1.73k | || file_size_u < ehdri.e_shoff |
122 | 1.66k | || file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) { |
123 | 62 | infoWarning("bad ElfXX_Shdrs"); |
124 | 62 | return nullptr; |
125 | 62 | } |
126 | 1.66k | shdri = new Shdr[(unsigned) e_shnum]; |
127 | 1.66k | fi->seek(ehdri.e_shoff, SEEK_SET); |
128 | 1.66k | fi->readx(shdri, e_shnum * sizeof(*shdri)); |
129 | 1.66k | unsigned const e_shstrndx = ehdri.e_shstrndx; |
130 | 1.66k | if (e_shnum <= e_shstrndx) { |
131 | 52 | infoWarning("bad .e_shstrndx %#x", e_shstrndx); |
132 | 52 | return nullptr; |
133 | 52 | } |
134 | 1.61k | Shdr const *p = &shdri[e_shstrndx]; |
135 | 1.61k | if (Shdr::SHT_STRTAB==p->sh_type |
136 | 1.42k | && p->sh_offset <= (file_size_u - sizeof(*shdri)) |
137 | 1.21k | && p->sh_size <= (file_size_u - p->sh_offset) |
138 | 1.04k | && p->sh_name <= (file_size_u - p->sh_offset) |
139 | 970 | && 10 <= (file_size_u - p->sh_name) |
140 | | // 10 == (1+ strlen(".shstrtab")) |
141 | 1.61k | ) { |
142 | 956 | if (p->sh_size <= p->sh_name) { |
143 | 48 | infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx); |
144 | 48 | return nullptr; |
145 | 48 | } |
146 | 908 | shstrtab = new char[1+ p->sh_size]; |
147 | 908 | fi->seek(p->sh_offset, SEEK_SET); |
148 | 908 | fi->readx(shstrtab, p->sh_size); |
149 | 908 | shstrtab[p->sh_size] = '\0'; |
150 | 908 | if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) { |
151 | 653 | return p; |
152 | 653 | } |
153 | 908 | } |
154 | 916 | return nullptr; |
155 | 1.61k | } PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::getElfSections() Line | Count | Source | 118 | 462 | { | 119 | 462 | unsigned const e_shnum = ehdri.e_shnum; | 120 | 462 | if (ehdri.e_shentsize != sizeof(*shdri) | 121 | 462 | || file_size_u < ehdri.e_shoff | 122 | 462 | || file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) { | 123 | 0 | infoWarning("bad ElfXX_Shdrs"); | 124 | 0 | return nullptr; | 125 | 0 | } | 126 | 462 | shdri = new Shdr[(unsigned) e_shnum]; | 127 | 462 | fi->seek(ehdri.e_shoff, SEEK_SET); | 128 | 462 | fi->readx(shdri, e_shnum * sizeof(*shdri)); | 129 | 462 | unsigned const e_shstrndx = ehdri.e_shstrndx; | 130 | 462 | if (e_shnum <= e_shstrndx) { | 131 | 22 | infoWarning("bad .e_shstrndx %#x", e_shstrndx); | 132 | 22 | return nullptr; | 133 | 22 | } | 134 | 440 | Shdr const *p = &shdri[e_shstrndx]; | 135 | 440 | if (Shdr::SHT_STRTAB==p->sh_type | 136 | 369 | && p->sh_offset <= (file_size_u - sizeof(*shdri)) | 137 | 360 | && p->sh_size <= (file_size_u - p->sh_offset) | 138 | 325 | && p->sh_name <= (file_size_u - p->sh_offset) | 139 | 296 | && 10 <= (file_size_u - p->sh_name) | 140 | | // 10 == (1+ strlen(".shstrtab")) | 141 | 440 | ) { | 142 | 291 | if (p->sh_size <= p->sh_name) { | 143 | 16 | infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx); | 144 | 16 | return nullptr; | 145 | 16 | } | 146 | 275 | shstrtab = new char[1+ p->sh_size]; | 147 | 275 | fi->seek(p->sh_offset, SEEK_SET); | 148 | 275 | fi->readx(shstrtab, p->sh_size); | 149 | 275 | shstrtab[p->sh_size] = '\0'; | 150 | 275 | if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) { | 151 | 195 | return p; | 152 | 195 | } | 153 | 275 | } | 154 | 229 | return nullptr; | 155 | 440 | } |
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::getElfSections() Line | Count | Source | 118 | 442 | { | 119 | 442 | unsigned const e_shnum = ehdri.e_shnum; | 120 | 442 | if (ehdri.e_shentsize != sizeof(*shdri) | 121 | 442 | || file_size_u < ehdri.e_shoff | 122 | 442 | || file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) { | 123 | 0 | infoWarning("bad ElfXX_Shdrs"); | 124 | 0 | return nullptr; | 125 | 0 | } | 126 | 442 | shdri = new Shdr[(unsigned) e_shnum]; | 127 | 442 | fi->seek(ehdri.e_shoff, SEEK_SET); | 128 | 442 | fi->readx(shdri, e_shnum * sizeof(*shdri)); | 129 | 442 | unsigned const e_shstrndx = ehdri.e_shstrndx; | 130 | 442 | if (e_shnum <= e_shstrndx) { | 131 | 13 | infoWarning("bad .e_shstrndx %#x", e_shstrndx); | 132 | 13 | return nullptr; | 133 | 13 | } | 134 | 429 | Shdr const *p = &shdri[e_shstrndx]; | 135 | 429 | if (Shdr::SHT_STRTAB==p->sh_type | 136 | 361 | && p->sh_offset <= (file_size_u - sizeof(*shdri)) | 137 | 342 | && p->sh_size <= (file_size_u - p->sh_offset) | 138 | 331 | && p->sh_name <= (file_size_u - p->sh_offset) | 139 | 321 | && 10 <= (file_size_u - p->sh_name) | 140 | | // 10 == (1+ strlen(".shstrtab")) | 141 | 429 | ) { | 142 | 318 | if (p->sh_size <= p->sh_name) { | 143 | 11 | infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx); | 144 | 11 | return nullptr; | 145 | 11 | } | 146 | 307 | shstrtab = new char[1+ p->sh_size]; | 147 | 307 | fi->seek(p->sh_offset, SEEK_SET); | 148 | 307 | fi->readx(shstrtab, p->sh_size); | 149 | 307 | shstrtab[p->sh_size] = '\0'; | 150 | 307 | if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) { | 151 | 220 | return p; | 152 | 220 | } | 153 | 307 | } | 154 | 198 | return nullptr; | 155 | 429 | } |
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::getElfSections() Line | Count | Source | 118 | 827 | { | 119 | 827 | unsigned const e_shnum = ehdri.e_shnum; | 120 | 827 | if (ehdri.e_shentsize != sizeof(*shdri) | 121 | 827 | || file_size_u < ehdri.e_shoff | 122 | 765 | || file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) { | 123 | 62 | infoWarning("bad ElfXX_Shdrs"); | 124 | 62 | return nullptr; | 125 | 62 | } | 126 | 765 | shdri = new Shdr[(unsigned) e_shnum]; | 127 | 765 | fi->seek(ehdri.e_shoff, SEEK_SET); | 128 | 765 | fi->readx(shdri, e_shnum * sizeof(*shdri)); | 129 | 765 | unsigned const e_shstrndx = ehdri.e_shstrndx; | 130 | 765 | if (e_shnum <= e_shstrndx) { | 131 | 17 | infoWarning("bad .e_shstrndx %#x", e_shstrndx); | 132 | 17 | return nullptr; | 133 | 17 | } | 134 | 748 | Shdr const *p = &shdri[e_shstrndx]; | 135 | 748 | if (Shdr::SHT_STRTAB==p->sh_type | 136 | 693 | && p->sh_offset <= (file_size_u - sizeof(*shdri)) | 137 | 508 | && p->sh_size <= (file_size_u - p->sh_offset) | 138 | 385 | && p->sh_name <= (file_size_u - p->sh_offset) | 139 | 353 | && 10 <= (file_size_u - p->sh_name) | 140 | | // 10 == (1+ strlen(".shstrtab")) | 141 | 748 | ) { | 142 | 347 | if (p->sh_size <= p->sh_name) { | 143 | 21 | infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx); | 144 | 21 | return nullptr; | 145 | 21 | } | 146 | 326 | shstrtab = new char[1+ p->sh_size]; | 147 | 326 | fi->seek(p->sh_offset, SEEK_SET); | 148 | 326 | fi->readx(shstrtab, p->sh_size); | 149 | 326 | shstrtab[p->sh_size] = '\0'; | 150 | 326 | if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) { | 151 | 238 | return p; | 152 | 238 | } | 153 | 326 | } | 154 | 489 | return nullptr; | 155 | 748 | } |
|
156 | | |
157 | | template <class T> |
158 | | tribool PackVmlinuxBase<T>::canPack() |
159 | 0 | { |
160 | 0 | fi->seek(0, SEEK_SET); |
161 | 0 | fi->readx(&ehdri, sizeof(ehdri)); |
162 | | |
163 | | // now check the ELF header |
164 | 0 | if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4) |
165 | 0 | || ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass |
166 | 0 | || ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata |
167 | 0 | || ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT |
168 | 0 | || !memcmp(&ehdri.e_ident[8], "FreeBSD", 7) // branded |
169 | 0 | || ehdri.e_machine != my_e_machine |
170 | 0 | || ehdri.e_version != 1 // version |
171 | 0 | || ehdri.e_ehsize != sizeof(ehdri) // different <elf.h> ? |
172 | 0 | ) { |
173 | 0 | return false; |
174 | 0 | } |
175 | | |
176 | | // additional requirements for vmlinux |
177 | 0 | if (ehdri.e_type != Ehdr::ET_EXEC |
178 | 0 | || ehdri.e_phoff != sizeof(ehdri) // Phdr not contiguous with Ehdr |
179 | 0 | || ehdri.e_phentsize!=sizeof(Phdr) |
180 | 0 | || !is_valid_e_entry(ehdri.e_entry) |
181 | 0 | ) { |
182 | 0 | return false; |
183 | 0 | } |
184 | | |
185 | | // A Linux kernel must have a __ksymtab section. [??] |
186 | 0 | Shdr const *p, *const shstrsec = getElfSections(); |
187 | 0 | if (nullptr==shstrsec) { |
188 | 0 | return false; |
189 | 0 | } |
190 | 0 | { |
191 | 0 | int j; |
192 | 0 | for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) { |
193 | 0 | if (Shdr::SHT_PROGBITS==p->sh_type |
194 | 0 | && p->sh_name < shstrsec->sh_size |
195 | 0 | && 0==strcmp("__ksymtab", p->sh_name + shstrtab)) { |
196 | 0 | break; |
197 | 0 | } |
198 | 0 | } |
199 | 0 | if (j < 0) { |
200 | 0 | return false; |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | 0 | phdri = new Phdr[(unsigned) ehdri.e_phnum]; |
205 | 0 | fi->seek(ehdri.e_phoff, SEEK_SET); |
206 | 0 | fi->readx(phdri, ehdri.e_phnum * sizeof(*phdri)); |
207 | | |
208 | | // Put PT_LOAD together at the beginning, ascending by .p_paddr. |
209 | 0 | upx_qsort(phdri, ehdri.e_phnum, sizeof(*phdri), compare_Phdr); |
210 | | |
211 | | // Find convex hull of physical addresses, and count the PT_LOAD. |
212 | | // Ignore ".bss": .p_filesz < .p_memsz |
213 | 0 | unsigned phys_lo= ~0u, phys_hi= 0u; |
214 | 0 | for (unsigned j = 0; j < ehdri.e_phnum; ++j) { |
215 | 0 | if (Phdr::PT_LOAD==phdri[j].p_type) { |
216 | | // Check for general sanity (not necessarily required.) |
217 | 0 | if (0xfff & (phdri[j].p_offset | phdri[j].p_paddr |
218 | 0 | | phdri[j].p_align | phdri[j].p_vaddr) ) { |
219 | 0 | return false; |
220 | 0 | } |
221 | 0 | if (phys_lo > phdri[j].p_paddr) { |
222 | 0 | phys_lo = phdri[j].p_paddr; |
223 | 0 | } |
224 | 0 | if (phys_hi < (phdri[j].p_filesz + phdri[j].p_paddr)) { |
225 | 0 | phys_hi = (phdri[j].p_filesz + phdri[j].p_paddr); |
226 | 0 | } |
227 | 0 | ++n_ptload; |
228 | 0 | } |
229 | 0 | } |
230 | 0 | paddr_min = phys_lo; |
231 | 0 | sz_ptload = phys_hi - phys_lo; |
232 | 0 | return 0 < n_ptload; |
233 | 0 | } Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::canPack() Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::canPack() Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::canPack() |
234 | | |
235 | | #include "p_elf.h" |
236 | | |
237 | | template <class T> |
238 | | void PackVmlinuxBase<T>::pack(OutputFile *fo) |
239 | 0 | { |
240 | 0 | unsigned fo_off = 0; |
241 | 0 | Ehdr ehdro; |
242 | 0 | TE32 tmp_u32; |
243 | | |
244 | | // nullptr |
245 | | // .text(PT_LOADs) .note(1st page) .note(rest) |
246 | | // .shstrtab .symtab .strtab |
247 | 0 | Shdr shdro[1+3+3]; |
248 | 0 | memset(shdro, 0, sizeof(shdro)); |
249 | |
|
250 | 0 | ibuf.alloc(file_size); |
251 | 0 | obuf.allocForCompression(file_size); |
252 | | |
253 | | // .e_ident, .e_machine, .e_version, .e_flags |
254 | 0 | memcpy(&ehdro, &ehdri, sizeof(ehdro)); |
255 | 0 | ehdro.e_type = Ehdr::ET_REL; |
256 | 0 | ehdro.e_entry = 0; |
257 | 0 | ehdro.e_phoff = 0; |
258 | 0 | ehdro.e_shoff = sizeof(ehdro); |
259 | 0 | ehdro.e_phentsize = 0; |
260 | 0 | ehdro.e_phnum = 0; |
261 | 0 | ehdro.e_shnum = 1+3+3; |
262 | 0 | ehdro.e_shstrndx = 4; |
263 | 0 | fo->write(&ehdro, sizeof(ehdro)); fo_off+= sizeof(ehdro); |
264 | 0 | fo->write(shdro, sizeof(shdro)); fo_off+= sizeof(shdro); |
265 | | |
266 | | // Notice overlap [containment] of physical PT_LOAD[2] into PTLOAD[1] |
267 | | // in this vmlinux for x86_64 from Fedora Core 6 on 2007-01-07: |
268 | | //Program Headers: |
269 | | // Type Offset VirtAddr PhysAddr |
270 | | // FileSiz MemSiz Flags Align |
271 | | // LOAD 0x0000000000200000 0xffffffff80200000 0x0000000000200000 |
272 | | // 0x000000000034bce8 0x000000000034bce8 R E 200000 |
273 | | // LOAD 0x000000000054c000 0xffffffff8054c000 0x000000000054c000 |
274 | | // 0x00000000000ed004 0x00000000001702a4 RWE 200000 |
275 | | // LOAD 0x0000000000800000 0xffffffffff600000 0x00000000005f5000 |
276 | | // 0x0000000000000c08 0x0000000000000c08 RWE 200000 |
277 | | // NOTE 0x0000000000000000 0x0000000000000000 0x0000000000000000 |
278 | | // 0x0000000000000000 0x0000000000000000 R 8 |
279 | | // Therefore we must "compose" the convex hull to be loaded. |
280 | |
|
281 | 0 | ph.u_len = sz_ptload; |
282 | 0 | memset(ibuf, 0, sz_ptload); |
283 | 0 | for (unsigned j = 0; j < ehdri.e_phnum; ++j) { |
284 | 0 | if (Phdr::PT_LOAD==phdri[j].p_type) { |
285 | 0 | fi->seek(phdri[j].p_offset, SEEK_SET); |
286 | 0 | fi->readx(ibuf + ((unsigned) phdri[j].p_paddr - paddr_min), phdri[j].p_filesz); |
287 | 0 | } |
288 | 0 | } |
289 | 0 | checkAlreadyPacked(ibuf + (ph.u_len - 1024), 1024); |
290 | | |
291 | | // prepare filter |
292 | 0 | ph.filter = 0; |
293 | 0 | Filter ft(ph.level); |
294 | 0 | ft.buf_len = ph.u_len; |
295 | 0 | ft.addvalue = 0; // we are independent of actual runtime address; see ckt32 |
296 | |
|
297 | 0 | upx_compress_config_t cconf; cconf.reset(); |
298 | | // limit stack size needed for runtime decompression |
299 | 0 | cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack |
300 | |
|
301 | 0 | unsigned ppc32_extra = 0; |
302 | 0 | if (Ehdr::EM_PPC==my_e_machine) { |
303 | | // output layout: |
304 | | // .long UPX_MAGIC_LE32 |
305 | | // .long L20 - L10 |
306 | | // L10: |
307 | | // b_info for Ehdr; compressed Ehdr; .balign 4 // one block only |
308 | | // b_info for LOAD; compressed LOAD; .balign 4 // possibly many blocks |
309 | | // // This allows per-block filters! |
310 | | // L20: |
311 | | // b f_decompress |
312 | | // +4: f_unfilter(char *buf, unsigned len, unsigned cto8, unsigned ftid) |
313 | | // // Code for multiple filters can "daisy chain" on ftid. |
314 | | // f_decompress(char const *src, unsigned src_len, |
315 | | // char *dst, unsigned *dst_len, int method) |
316 | 0 | unsigned tmp; |
317 | 0 | tmp = UPX_MAGIC_LE32; fo->write(&tmp, sizeof(tmp)); fo_off += sizeof(tmp); |
318 | 0 | tmp = 0; fo->write(&tmp, sizeof(tmp)); fo_off += sizeof(tmp); |
319 | 0 | ppc32_extra += 2*sizeof(tmp); |
320 | 0 | unsigned const len_unc = sizeof(ehdri) + sizeof(Phdr) * ehdri.e_phnum; |
321 | 0 | MemBuffer unc_hdr(len_unc); |
322 | 0 | MemBuffer cpr_hdr; cpr_hdr.allocForCompression(len_unc); |
323 | 0 | memcpy(&unc_hdr[0], &ehdri, sizeof(ehdri)); |
324 | 0 | memcpy(&unc_hdr[sizeof(ehdri)], phdri, sizeof(Phdr) * ehdri.e_phnum); |
325 | 0 | unsigned len_cpr = 0; |
326 | 0 | int const r = upx_compress(unc_hdr, len_unc, cpr_hdr, &len_cpr, |
327 | 0 | nullptr, ph.method, 10, nullptr, nullptr ); |
328 | 0 | if (UPX_E_OK!=r || len_unc<=len_cpr) // FIXME: allow no compression |
329 | 0 | throwInternalError("Ehdr compression failed"); |
330 | | |
331 | 0 | packed_struct(b_info) { // 12-byte header before each compressed block |
332 | 0 | NE32 sz_unc; // uncompressed_size |
333 | 0 | NE32 sz_cpr; // compressed_size |
334 | 0 | unsigned char b_method; // compression algorithm |
335 | 0 | unsigned char b_ftid; // filter id |
336 | 0 | unsigned char b_cto8; // filter parameter |
337 | 0 | unsigned char b_unused; // FIXME: !=0 for partial-block unfilter |
338 | | // NE32 f_offset, f_len; // only if partial-block unfilter |
339 | 0 | }; |
340 | |
|
341 | 0 | struct b_info hdr_info; |
342 | 0 | set_be32(&hdr_info.sz_unc, len_unc); |
343 | 0 | set_be32(&hdr_info.sz_cpr, len_cpr); |
344 | 0 | hdr_info.b_method = ph.method; |
345 | 0 | hdr_info.b_ftid = 0; |
346 | 0 | hdr_info.b_cto8 = 0; |
347 | 0 | hdr_info.b_unused = 0; |
348 | 0 | fo->write(&hdr_info, sizeof(hdr_info)); fo_off += sizeof(hdr_info); |
349 | 0 | unsigned const frag = (3& (0u-len_cpr)); |
350 | 0 | ppc32_extra += sizeof(hdr_info) + len_cpr + frag; |
351 | 0 | fo_off += len_cpr + frag; |
352 | 0 | memset(&cpr_hdr[len_cpr], 0, frag); // valgrind only |
353 | 0 | fo->write(cpr_hdr, len_cpr + frag); |
354 | | |
355 | | // Partial filter: .text and following contiguous SHF_EXECINSTR |
356 | 0 | upx_bytep f_ptr = ibuf; |
357 | 0 | unsigned f_len = 0; |
358 | 0 | Shdr const *shdr = 1+ shdri; // skip empty shdr[0] |
359 | 0 | if (ft.buf_len==0 // not specified yet FIXME: was set near construction |
360 | 0 | && (Shdr::SHF_ALLOC & shdr->sh_flags) |
361 | 0 | && (Shdr::SHF_EXECINSTR & shdr->sh_flags)) { |
362 | | // shdr[1] is instructions (probably .text) |
363 | 0 | f_ptr = ibuf + (unsigned) (shdr->sh_offset - phdri[0].p_offset); |
364 | 0 | f_len = shdr->sh_size; |
365 | 0 | ++shdr; |
366 | 0 | for (int j= ehdri.e_shnum - 2; --j>=0; ++shdr) { |
367 | 0 | unsigned prev_end = shdr[-1].sh_size + shdr[-1].sh_offset; |
368 | 0 | prev_end += ~(0u-shdr[0].sh_addralign) & (0u-prev_end); // align_up |
369 | 0 | if ((Shdr::SHF_ALLOC & shdr->sh_flags) |
370 | 0 | && (Shdr::SHF_EXECINSTR & shdr->sh_flags) |
371 | 0 | && shdr[0].sh_offset==prev_end) { |
372 | 0 | f_len += shdr->sh_size; |
373 | 0 | } |
374 | 0 | else { |
375 | 0 | break; |
376 | 0 | } |
377 | 0 | } |
378 | 0 | } |
379 | 0 | else { // ft.buf_len already specified, or Shdr[1] not instructions |
380 | 0 | f_ptr = ibuf; |
381 | 0 | f_len = ph.u_len; |
382 | 0 | } |
383 | 0 | compressWithFilters(ibuf, ph.u_len, obuf, |
384 | 0 | f_ptr, f_len, // filter range |
385 | 0 | nullptr, 0, // hdr_ptr, hdr_len |
386 | 0 | &ft, 512, &cconf, getStrategy(ft)); |
387 | |
|
388 | 0 | set_be32(&hdr_info.sz_unc, ph.u_len); |
389 | 0 | set_be32(&hdr_info.sz_cpr, ph.c_len); |
390 | 0 | hdr_info.b_ftid = ft.id; |
391 | 0 | hdr_info.b_cto8 = ft.cto; |
392 | 0 | if (ph.u_len!=f_len) { |
393 | 0 | hdr_info.b_unused = 1; // flag for partial filter |
394 | 0 | } |
395 | 0 | fo->write(&hdr_info, sizeof(hdr_info)); fo_off += sizeof(hdr_info); |
396 | 0 | ppc32_extra += sizeof(hdr_info); |
397 | 0 | if (ph.u_len!=f_len) { |
398 | 0 | set_be32(&hdr_info.sz_unc, f_ptr - (upx_bytep) ibuf); |
399 | 0 | set_be32(&hdr_info.sz_cpr, f_len); |
400 | 0 | fo->write(&hdr_info, 2*sizeof(unsigned)); fo_off += 2*sizeof(unsigned); |
401 | 0 | ppc32_extra += 2*sizeof(unsigned); |
402 | 0 | } |
403 | 0 | } |
404 | 0 | else { |
405 | 0 | compressWithFilters(&ft, 512, &cconf, getStrategy(ft)); |
406 | 0 | } |
407 | 0 | unsigned const txt_c_len = ph.c_len; |
408 | |
|
409 | 0 | const unsigned lsize = getLoaderSize(); |
410 | |
|
411 | 0 | defineDecompressorSymbols(); |
412 | 0 | defineFilterSymbols(&ft); |
413 | 0 | relocateLoader(); |
414 | |
|
415 | 0 | MemBuffer loader(lsize); |
416 | 0 | memcpy(loader, getLoader(), lsize); |
417 | 0 | patchPackHeader(loader, lsize); |
418 | |
|
419 | 0 | #define shstrtab local_shstrtab // avoid -Wshadow warning |
420 | 0 | char const shstrtab[]= "\0.text\0.note\0.shstrtab\0.symtab\0.strtab"; |
421 | 0 | char const *p = shstrtab; |
422 | 0 | while (0!=*p++) ; |
423 | 0 | shdro[1].sh_name = ptr_diff(p, shstrtab); |
424 | 0 | shdro[1].sh_type = Shdr::SHT_PROGBITS; |
425 | 0 | shdro[1].sh_flags = Shdr::SHF_ALLOC | Shdr::SHF_EXECINSTR; |
426 | 0 | shdro[1].sh_offset = fo_off - ppc32_extra; |
427 | 0 | shdro[1].sh_size = ppc32_extra + txt_c_len + lsize; // plus more ... |
428 | 0 | shdro[1].sh_addralign = 1; // default |
429 | |
|
430 | 0 | fo_off += write_vmlinux_head(fo, &shdro[1]); |
431 | 0 | fo->write(obuf, txt_c_len); fo_off += txt_c_len; |
432 | 0 | unsigned const a = (shdro[1].sh_addralign -1) & (0u-(ppc32_extra + txt_c_len)); |
433 | 0 | if (0!=a) { // align |
434 | 0 | fo_off += a; |
435 | 0 | shdro[1].sh_size += a; |
436 | 0 | fo->seek(a, SEEK_CUR); |
437 | 0 | } |
438 | 0 | fo->write(loader, lsize); fo_off += lsize; |
439 | |
|
440 | | #if 0 |
441 | | printf("%-13s: compressed : %8u bytes\n", getName(), txt_c_len); |
442 | | printf("%-13s: decompressor : %8u bytes\n", getName(), lsize); |
443 | | #endif |
444 | 0 | verifyOverlappingDecompression(); |
445 | | |
446 | | // .note with 1st page -------------------------------- |
447 | 0 | ph.u_len = phdri[0].p_offset; |
448 | 0 | fi->seek(0, SEEK_SET); |
449 | 0 | fi->readx(ibuf, ph.u_len); |
450 | 0 | compress(ibuf, ph.u_len, obuf, &cconf); |
451 | |
|
452 | 0 | while (0!=*p++) ; |
453 | 0 | shdro[2].sh_name = ptr_diff(p, shstrtab); |
454 | 0 | shdro[2].sh_type = Shdr::SHT_NOTE; |
455 | 0 | shdro[2].sh_offset = fo_off; |
456 | 0 | shdro[2].sh_size = sizeof(ph.u_len) + ph.c_len; |
457 | 0 | shdro[2].sh_addralign = 1; |
458 | 0 | tmp_u32 = ph.u_len; fo->write(&tmp_u32, 4); |
459 | 0 | fo->write(obuf, ph.c_len); fo_off += shdro[2].sh_size; |
460 | | |
461 | | // .note with rest -------------------------------- |
462 | 0 | ph.u_len = file_size - (sz_ptload + phdri[0].p_offset); |
463 | 0 | fi->seek(sz_ptload + phdri[0].p_offset, SEEK_SET); |
464 | 0 | fi->readx(ibuf, ph.u_len); |
465 | | |
466 | | // Temporarily decrease ph.level by about (1+ log2(sz_rest / sz_ptload)) |
467 | | // to avoid spending unreasonable effort compressing large symbol tables |
468 | | // that are discarded 99.9% of the time anyway. |
469 | 0 | int const old_level = ph.level; |
470 | 0 | for (unsigned v = ((ph.u_len>>3) + ph.u_len) / sz_ptload; 0 < v; v>>=1) { |
471 | 0 | if (0== --ph.level) { |
472 | 0 | ph.level = 1; |
473 | 0 | } |
474 | 0 | } |
475 | 0 | compress(ibuf, ph.u_len, obuf, &cconf); |
476 | 0 | ph.level = old_level; |
477 | | |
478 | | // while (0!=*p++) ; // name is the same |
479 | 0 | shdro[3].sh_name = ptr_diff(p, shstrtab); |
480 | 0 | shdro[3].sh_type = Shdr::SHT_NOTE; |
481 | 0 | shdro[3].sh_offset = fo_off; |
482 | 0 | shdro[3].sh_size = sizeof(ph.u_len) + ph.c_len; |
483 | 0 | shdro[3].sh_addralign = 1; |
484 | 0 | tmp_u32 = ph.u_len; fo->write(&tmp_u32, 4); |
485 | 0 | fo->write(obuf, ph.c_len); fo_off += shdro[3].sh_size; |
486 | |
|
487 | 0 | while (0!=*p++) ; |
488 | 0 | shdro[4].sh_name = ptr_diff(p, shstrtab); |
489 | 0 | shdro[4].sh_type = Shdr::SHT_STRTAB; |
490 | 0 | shdro[4].sh_offset = fo_off; |
491 | 0 | shdro[4].sh_size = sizeof(shstrtab); // already includes terminating '\0' |
492 | 0 | shdro[4].sh_addralign = 1; |
493 | 0 | fo->write(shstrtab, shdro[4].sh_size); fo_off += shdro[4].sh_size; |
494 | |
|
495 | 0 | fo_off = ~3 & (3+ fo_off); fo->seek(fo_off, SEEK_SET); |
496 | 0 | while (0!=*p++) ; |
497 | 0 | shdro[5].sh_name = ptr_diff(p, shstrtab); |
498 | 0 | shdro[5].sh_type = Shdr::SHT_SYMTAB; |
499 | 0 | shdro[5].sh_offset = fo_off; |
500 | 0 | shdro[5].sh_size = ((Ehdr::EM_PPC==my_e_machine) + 5)*sizeof(Sym); |
501 | | //shdro[5].sh_flags = Shdr::SHF_INFO_LINK; |
502 | 0 | shdro[5].sh_link = 6; // to .strtab for symbols |
503 | 0 | shdro[5].sh_info = 1+3; // number of non-global symbols [binutils/bfd/elf.c] |
504 | 0 | shdro[5].sh_addralign = 4; |
505 | 0 | shdro[5].sh_entsize = sizeof(Sym); |
506 | |
|
507 | 0 | Sym sec_sym; |
508 | | |
509 | | // Symbol 0; no references, but bfd demands it. |
510 | 0 | memset(&sec_sym, 0, sizeof(sec_sym)); |
511 | 0 | fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym); |
512 | | |
513 | | // Each section before .shstrtab needs a symbol. |
514 | 0 | sec_sym.st_info = sec_sym.make_st_info(Sym::STB_LOCAL, Sym::STT_SECTION); |
515 | 0 | sec_sym.st_other = Sym::STV_DEFAULT; |
516 | 0 | sec_sym.st_shndx = 1; // .text |
517 | 0 | fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym); |
518 | 0 | sec_sym.st_shndx = 2; // .note |
519 | 0 | fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym); |
520 | 0 | sec_sym.st_shndx = 3; // .note |
521 | 0 | fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym); |
522 | | |
523 | | // the symbol we care about |
524 | 0 | Sym unc_ker; |
525 | 0 | unc_ker.st_name = 1; // 1 byte into strtab |
526 | 0 | unc_ker.st_value = 0; |
527 | 0 | unc_ker.st_size = ppc32_extra + txt_c_len; |
528 | 0 | unc_ker.st_info = unc_ker.make_st_info(Sym::STB_GLOBAL, Sym::STT_FUNC); |
529 | 0 | unc_ker.st_other = Sym::STV_DEFAULT; |
530 | 0 | unc_ker.st_shndx = 1; // .text |
531 | 0 | fo->write(&unc_ker, sizeof(unc_ker)); fo_off += sizeof(unc_ker); |
532 | |
|
533 | 0 | unsigned const lablen = strlen(my_boot_label); |
534 | 0 | if (Ehdr::EM_PPC==my_e_machine) { |
535 | 0 | unc_ker.st_name += 1+ lablen; |
536 | 0 | unc_ker.st_value = unc_ker.st_size; |
537 | 0 | unc_ker.st_size = 0; |
538 | 0 | fo->write(&unc_ker, sizeof(unc_ker)); fo_off += sizeof(unc_ker); |
539 | 0 | } |
540 | 0 | while (0!=*p++) ; |
541 | 0 | shdro[6].sh_name = ptr_diff(p, shstrtab); |
542 | 0 | shdro[6].sh_type = Shdr::SHT_STRTAB; |
543 | 0 | shdro[6].sh_offset = fo_off; |
544 | 0 | shdro[6].sh_size = 2+ lablen + (Ehdr::EM_PPC==my_e_machine)*(1+ 12); // '\0' before and after |
545 | 0 | shdro[6].sh_addralign = 1; |
546 | 0 | fo->seek(1, SEEK_CUR); // the '\0' before |
547 | 0 | fo->write(my_boot_label, 1+ lablen); // include the '\0' terminator |
548 | 0 | if (Ehdr::EM_PPC==my_e_machine) { |
549 | 0 | fo->write("_vmlinux_end", 1+ 12); fo_off += 1+ 12; |
550 | 0 | } |
551 | 0 | fo_off += 2+ lablen; |
552 | |
|
553 | 0 | fo->seek(0, SEEK_SET); |
554 | 0 | fo->write(&ehdro, sizeof(ehdro)); |
555 | 0 | fo->write(&shdro[0], sizeof(shdro)); |
556 | 0 | if (Ehdr::EM_PPC==my_e_machine) { |
557 | 0 | fo->seek(sizeof(unsigned), SEEK_CUR); |
558 | 0 | set_be32(&ppc32_extra, ppc32_extra - 2*sizeof(unsigned) + txt_c_len); |
559 | 0 | fo->write(&ppc32_extra, sizeof(ppc32_extra)); |
560 | 0 | } |
561 | |
|
562 | 0 | if (!checkFinalCompressionRatio(fo)) |
563 | 0 | throwNotCompressible(); |
564 | 0 | #undef shstrtab |
565 | 0 | } Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::pack(OutputFile*) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::pack(OutputFile*) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::pack(OutputFile*) |
566 | | |
567 | | template <class T> |
568 | | tribool PackVmlinuxBase<T>::canUnpack() |
569 | 137k | { |
570 | 137k | fi->seek(0, SEEK_SET); |
571 | 137k | fi->readx(&ehdri, sizeof(ehdri)); |
572 | | |
573 | | // now check the ELF header |
574 | 137k | if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4) |
575 | 81.4k | || ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass |
576 | 40.1k | || ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata |
577 | 19.5k | || ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT |
578 | 18.5k | || !memcmp(&ehdri.e_ident[8], "FreeBSD", 7) // branded |
579 | 18.4k | || ehdri.e_machine != my_e_machine |
580 | 6.81k | || ehdri.e_version != 1 // version |
581 | 6.08k | || ehdri.e_ehsize != sizeof(ehdri) // different <elf.h> ? |
582 | 137k | ) |
583 | 131k | return false; |
584 | | |
585 | 5.44k | if (ehdri.e_type != Ehdr::ET_REL |
586 | | //i386 fails || ehdri.e_shoff != sizeof(ehdri) // Shdr not contiguous with Ehdr |
587 | 2.04k | || ehdri.e_shentsize!=sizeof(Shdr) |
588 | 1.99k | || ehdri.e_shnum < 4 |
589 | 1.97k | || (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff) |
590 | 5.44k | ) |
591 | 3.71k | return false; |
592 | | |
593 | | // find the .shstrtab section |
594 | 1.73k | Shdr const *const shstrsec = getElfSections(); |
595 | 1.73k | if (nullptr==shstrsec) { |
596 | 1.07k | return false; |
597 | 1.07k | } |
598 | | |
599 | | // check for .text .note .note and sane (.sh_size + .sh_offset) |
600 | 653 | p_note0 = p_note1 = p_text = nullptr; |
601 | 653 | int j; |
602 | 653 | Shdr *p; |
603 | 103k | for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) { |
604 | 103k | if ((unsigned)file_size < (p->sh_size + p->sh_offset) |
605 | 35.2k | || (5+ p->sh_name) < p->sh_name // wrap: ignore malformed |
606 | 80.1k | || shstrsec->sh_size < (5+ p->sh_name) ) { |
607 | 80.1k | continue; |
608 | 80.1k | } |
609 | 23.1k | if (0==strcmp(".text", shstrtab + p->sh_name)) { |
610 | 1.21k | p_text = p; |
611 | 1.21k | } |
612 | 23.1k | if (0==strcmp(".note", shstrtab + p->sh_name)) { |
613 | 1.15k | if (nullptr==p_note0) { |
614 | 108 | p_note0 = p; |
615 | 108 | } else |
616 | 1.04k | if (nullptr==p_note1) { |
617 | 82 | p_note1 = p; |
618 | 82 | } |
619 | 1.15k | } |
620 | 23.1k | } |
621 | 653 | if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) { |
622 | 621 | return false; |
623 | 621 | } |
624 | | |
625 | 32 | char buf[1024]; |
626 | 32 | fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET); |
627 | 32 | fi->readx(buf, sizeof(buf)); |
628 | 32 | if (!getPackHeader(buf, sizeof(buf))) |
629 | 12 | return -1; // format is known, but definitely is not packed |
630 | | |
631 | 20 | return true; |
632 | 32 | } PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::canUnpack() Line | Count | Source | 569 | 45.7k | { | 570 | 45.7k | fi->seek(0, SEEK_SET); | 571 | 45.7k | fi->readx(&ehdri, sizeof(ehdri)); | 572 | | | 573 | | // now check the ELF header | 574 | 45.7k | if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4) | 575 | 27.1k | || ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass | 576 | 13.1k | || ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata | 577 | 4.91k | || ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT | 578 | 4.59k | || !memcmp(&ehdri.e_ident[8], "FreeBSD", 7) // branded | 579 | 4.57k | || ehdri.e_machine != my_e_machine | 580 | 1.33k | || ehdri.e_version != 1 // version | 581 | 1.17k | || ehdri.e_ehsize != sizeof(ehdri) // different <elf.h> ? | 582 | 45.7k | ) | 583 | 44.6k | return false; | 584 | | | 585 | 1.04k | if (ehdri.e_type != Ehdr::ET_REL | 586 | | //i386 fails || ehdri.e_shoff != sizeof(ehdri) // Shdr not contiguous with Ehdr | 587 | 531 | || ehdri.e_shentsize!=sizeof(Shdr) | 588 | 524 | || ehdri.e_shnum < 4 | 589 | 519 | || (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff) | 590 | 1.04k | ) | 591 | 587 | return false; | 592 | | | 593 | | // find the .shstrtab section | 594 | 462 | Shdr const *const shstrsec = getElfSections(); | 595 | 462 | if (nullptr==shstrsec) { | 596 | 267 | return false; | 597 | 267 | } | 598 | | | 599 | | // check for .text .note .note and sane (.sh_size + .sh_offset) | 600 | 195 | p_note0 = p_note1 = p_text = nullptr; | 601 | 195 | int j; | 602 | 195 | Shdr *p; | 603 | 25.1k | for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) { | 604 | 24.9k | if ((unsigned)file_size < (p->sh_size + p->sh_offset) | 605 | 10.2k | || (5+ p->sh_name) < p->sh_name // wrap: ignore malformed | 606 | 18.0k | || shstrsec->sh_size < (5+ p->sh_name) ) { | 607 | 18.0k | continue; | 608 | 18.0k | } | 609 | 6.87k | if (0==strcmp(".text", shstrtab + p->sh_name)) { | 610 | 450 | p_text = p; | 611 | 450 | } | 612 | 6.87k | if (0==strcmp(".note", shstrtab + p->sh_name)) { | 613 | 369 | if (nullptr==p_note0) { | 614 | 39 | p_note0 = p; | 615 | 39 | } else | 616 | 330 | if (nullptr==p_note1) { | 617 | 32 | p_note1 = p; | 618 | 32 | } | 619 | 369 | } | 620 | 6.87k | } | 621 | 195 | if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) { | 622 | 182 | return false; | 623 | 182 | } | 624 | | | 625 | 13 | char buf[1024]; | 626 | 13 | fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET); | 627 | 13 | fi->readx(buf, sizeof(buf)); | 628 | 13 | if (!getPackHeader(buf, sizeof(buf))) | 629 | 5 | return -1; // format is known, but definitely is not packed | 630 | | | 631 | 8 | return true; | 632 | 13 | } |
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::canUnpack() Line | Count | Source | 569 | 45.7k | { | 570 | 45.7k | fi->seek(0, SEEK_SET); | 571 | 45.7k | fi->readx(&ehdri, sizeof(ehdri)); | 572 | | | 573 | | // now check the ELF header | 574 | 45.7k | if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4) | 575 | 27.1k | || ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass | 576 | 13.1k | || ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata | 577 | 7.04k | || ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT | 578 | 6.76k | || !memcmp(&ehdri.e_ident[8], "FreeBSD", 7) // branded | 579 | 6.74k | || ehdri.e_machine != my_e_machine | 580 | 2.80k | || ehdri.e_version != 1 // version | 581 | 2.50k | || ehdri.e_ehsize != sizeof(ehdri) // different <elf.h> ? | 582 | 45.7k | ) | 583 | 43.6k | return false; | 584 | | | 585 | 2.12k | if (ehdri.e_type != Ehdr::ET_REL | 586 | | //i386 fails || ehdri.e_shoff != sizeof(ehdri) // Shdr not contiguous with Ehdr | 587 | 488 | || ehdri.e_shentsize!=sizeof(Shdr) | 588 | 467 | || ehdri.e_shnum < 4 | 589 | 460 | || (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff) | 590 | 2.12k | ) | 591 | 1.68k | return false; | 592 | | | 593 | | // find the .shstrtab section | 594 | 442 | Shdr const *const shstrsec = getElfSections(); | 595 | 442 | if (nullptr==shstrsec) { | 596 | 222 | return false; | 597 | 222 | } | 598 | | | 599 | | // check for .text .note .note and sane (.sh_size + .sh_offset) | 600 | 220 | p_note0 = p_note1 = p_text = nullptr; | 601 | 220 | int j; | 602 | 220 | Shdr *p; | 603 | 39.0k | for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) { | 604 | 38.8k | if ((unsigned)file_size < (p->sh_size + p->sh_offset) | 605 | 16.2k | || (5+ p->sh_name) < p->sh_name // wrap: ignore malformed | 606 | 28.3k | || shstrsec->sh_size < (5+ p->sh_name) ) { | 607 | 28.3k | continue; | 608 | 28.3k | } | 609 | 10.4k | if (0==strcmp(".text", shstrtab + p->sh_name)) { | 610 | 596 | p_text = p; | 611 | 596 | } | 612 | 10.4k | if (0==strcmp(".note", shstrtab + p->sh_name)) { | 613 | 470 | if (nullptr==p_note0) { | 614 | 46 | p_note0 = p; | 615 | 46 | } else | 616 | 424 | if (nullptr==p_note1) { | 617 | 29 | p_note1 = p; | 618 | 29 | } | 619 | 470 | } | 620 | 10.4k | } | 621 | 220 | if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) { | 622 | 208 | return false; | 623 | 208 | } | 624 | | | 625 | 12 | char buf[1024]; | 626 | 12 | fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET); | 627 | 12 | fi->readx(buf, sizeof(buf)); | 628 | 12 | if (!getPackHeader(buf, sizeof(buf))) | 629 | 5 | return -1; // format is known, but definitely is not packed | 630 | | | 631 | 7 | return true; | 632 | 12 | } |
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::canUnpack() Line | Count | Source | 569 | 45.7k | { | 570 | 45.7k | fi->seek(0, SEEK_SET); | 571 | 45.7k | fi->readx(&ehdri, sizeof(ehdri)); | 572 | | | 573 | | // now check the ELF header | 574 | 45.7k | if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4) | 575 | 27.1k | || ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass | 576 | 13.7k | || ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata | 577 | 7.59k | || ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT | 578 | 7.20k | || !memcmp(&ehdri.e_ident[8], "FreeBSD", 7) // branded | 579 | 7.17k | || ehdri.e_machine != my_e_machine | 580 | 2.68k | || ehdri.e_version != 1 // version | 581 | 2.39k | || ehdri.e_ehsize != sizeof(ehdri) // different <elf.h> ? | 582 | 45.7k | ) | 583 | 43.4k | return false; | 584 | | | 585 | 2.27k | if (ehdri.e_type != Ehdr::ET_REL | 586 | | //i386 fails || ehdri.e_shoff != sizeof(ehdri) // Shdr not contiguous with Ehdr | 587 | 1.02k | || ehdri.e_shentsize!=sizeof(Shdr) | 588 | 1.00k | || ehdri.e_shnum < 4 | 589 | 998 | || (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff) | 590 | 2.27k | ) | 591 | 1.44k | return false; | 592 | | | 593 | | // find the .shstrtab section | 594 | 827 | Shdr const *const shstrsec = getElfSections(); | 595 | 827 | if (nullptr==shstrsec) { | 596 | 589 | return false; | 597 | 589 | } | 598 | | | 599 | | // check for .text .note .note and sane (.sh_size + .sh_offset) | 600 | 238 | p_note0 = p_note1 = p_text = nullptr; | 601 | 238 | int j; | 602 | 238 | Shdr *p; | 603 | 39.6k | for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) { | 604 | 39.4k | if ((unsigned)file_size < (p->sh_size + p->sh_offset) | 605 | 8.78k | || (5+ p->sh_name) < p->sh_name // wrap: ignore malformed | 606 | 33.6k | || shstrsec->sh_size < (5+ p->sh_name) ) { | 607 | 33.6k | continue; | 608 | 33.6k | } | 609 | 5.75k | if (0==strcmp(".text", shstrtab + p->sh_name)) { | 610 | 164 | p_text = p; | 611 | 164 | } | 612 | 5.75k | if (0==strcmp(".note", shstrtab + p->sh_name)) { | 613 | 311 | if (nullptr==p_note0) { | 614 | 23 | p_note0 = p; | 615 | 23 | } else | 616 | 288 | if (nullptr==p_note1) { | 617 | 21 | p_note1 = p; | 618 | 21 | } | 619 | 311 | } | 620 | 5.75k | } | 621 | 238 | if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) { | 622 | 231 | return false; | 623 | 231 | } | 624 | | | 625 | 7 | char buf[1024]; | 626 | 7 | fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET); | 627 | 7 | fi->readx(buf, sizeof(buf)); | 628 | 7 | if (!getPackHeader(buf, sizeof(buf))) | 629 | 2 | return -1; // format is known, but definitely is not packed | 630 | | | 631 | 5 | return true; | 632 | 7 | } |
|
633 | | |
634 | | template <class T> |
635 | | void PackVmlinuxBase<T>::unpack(OutputFile *fo) |
636 | 0 | { |
637 | 0 | TE32 word; |
638 | 0 | PackHeader const ph_tmp(ph); |
639 | |
|
640 | 0 | fi->seek(p_note0->sh_offset, SEEK_SET); |
641 | 0 | fi->readx(&word, sizeof(word)); |
642 | 0 | ph.u_len = word; |
643 | 0 | ph.c_len = p_note0->sh_size - sizeof(word); |
644 | 0 | ibuf.alloc(ph.c_len); |
645 | 0 | fi->readx(ibuf, ph.c_len); |
646 | 0 | obuf.allocForDecompression(ph.u_len); |
647 | 0 | decompress(ibuf, obuf, false); |
648 | 0 | fo->write(obuf, ph.u_len); |
649 | 0 | obuf.dealloc(); |
650 | 0 | ibuf.dealloc(); |
651 | |
|
652 | 0 | ph = ph_tmp; |
653 | 0 | if (!has_valid_vmlinux_head()) { |
654 | 0 | throwCantUnpack(".text corrupted"); |
655 | 0 | } |
656 | 0 | ibuf.alloc(ph.c_len); |
657 | 0 | fi->readx(ibuf, ph.c_len); |
658 | 0 | obuf.allocForDecompression(ph.u_len); |
659 | 0 | decompress(ibuf, obuf); |
660 | |
|
661 | 0 | Filter ft(ph.level); |
662 | 0 | ft.init(ph.filter, 0); |
663 | 0 | ft.cto = (unsigned char) ph.filter_cto; |
664 | 0 | ft.unfilter(obuf, ph.u_len); |
665 | 0 | fo->write(obuf, ph.u_len); |
666 | 0 | obuf.dealloc(); |
667 | 0 | ibuf.dealloc(); |
668 | |
|
669 | 0 | fi->seek(p_note1->sh_offset, SEEK_SET); |
670 | 0 | fi->readx(&word, sizeof(word)); |
671 | 0 | ph.u_len = word; |
672 | 0 | ph.c_len = p_note1->sh_size - sizeof(word); |
673 | 0 | ibuf.alloc(ph.c_len); |
674 | 0 | fi->readx(ibuf, p_note1->sh_size - sizeof(ph.u_len)); |
675 | 0 | obuf.allocForDecompression(ph.u_len); |
676 | 0 | decompress(ibuf, obuf, false); |
677 | 0 | fo->write(obuf, ph.u_len); |
678 | 0 | obuf.dealloc(); |
679 | 0 | ibuf.dealloc(); |
680 | |
|
681 | 0 | ph = ph_tmp; |
682 | 0 | } Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::unpack(OutputFile*) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::unpack(OutputFile*) Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::unpack(OutputFile*) |
683 | | |
684 | | |
685 | | /************************************************************************* |
686 | | // |
687 | | **************************************************************************/ |
688 | | |
689 | | const int *PackVmlinuxI386::getCompressionMethods(int method, int level) const |
690 | 0 | { |
691 | 0 | return Packer::getDefaultCompressionMethods_le32(method, level); |
692 | 0 | } |
693 | | |
694 | | |
695 | | const int *PackVmlinuxI386::getFilters() const |
696 | 0 | { |
697 | 0 | static const int filters[] = { |
698 | 0 | 0x49, 0x46, |
699 | 0 | FT_END }; |
700 | 0 | return filters; |
701 | 0 | } |
702 | | |
703 | | const int *PackVmlinuxARMEL::getCompressionMethods(int method, int level) const |
704 | 0 | { |
705 | 0 | return Packer::getDefaultCompressionMethods_8(method, level); |
706 | 0 | } |
707 | | |
708 | | const int *PackVmlinuxARMEB::getCompressionMethods(int method, int level) const |
709 | 0 | { |
710 | 0 | return Packer::getDefaultCompressionMethods_8(method, level); |
711 | 0 | } |
712 | | |
713 | | const int *PackVmlinuxPPC32::getCompressionMethods(int method, int level) const |
714 | 0 | { |
715 | | // No real dependency on LE32. |
716 | 0 | return Packer::getDefaultCompressionMethods_le32(method, level); |
717 | 0 | } |
718 | | |
719 | | const int *PackVmlinuxPPC64LE::getCompressionMethods(int method, int level) const |
720 | 0 | { |
721 | | // No real dependency on LE32. |
722 | 0 | return Packer::getDefaultCompressionMethods_le32(method, level); |
723 | 0 | } |
724 | | |
725 | | |
726 | | const int *PackVmlinuxARMEL::getFilters() const |
727 | 0 | { |
728 | 0 | static const int f50[] = { 0x50, FT_END }; |
729 | 0 | return f50; |
730 | 0 | } |
731 | | |
732 | | const int *PackVmlinuxARMEB::getFilters() const |
733 | 0 | { |
734 | 0 | static const int f51[] = { 0x51, FT_END }; |
735 | 0 | return f51; |
736 | 0 | } |
737 | | |
738 | | const int *PackVmlinuxPPC32::getFilters() const |
739 | 0 | { |
740 | 0 | static const int fd0[] = { 0xd0, FT_END }; |
741 | 0 | return fd0; |
742 | 0 | } |
743 | | |
744 | | const int *PackVmlinuxPPC64LE::getFilters() const |
745 | 0 | { |
746 | 0 | static const int fd0[] = { 0xd0, FT_END }; |
747 | 0 | return fd0; |
748 | 0 | } |
749 | | |
750 | | // |
751 | | // Examples as of 2004-07-16 [readelf --segments vmlinux # before fiddling]: |
752 | | // |
753 | | //----- kernel-2.6.7 plain [defconfig?] |
754 | | //Program Headers(2): |
755 | | // Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
756 | | // LOAD 0x001000 0x00100000 0x00100000 0x1c7e61 0x1c7e61 R E 0x1000 |
757 | | // LOAD 0x1c8e64 0x002c8e64 0x002c8e64 0x00000 0x00000 RW 0x1000 |
758 | | // |
759 | | //----- kernel-2.6.7-1.488 Fedora Core 3 test 1 |
760 | | //Program Headers(5): |
761 | | // Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
762 | | // LOAD 0x001000 0x02100000 0x02100000 0x202246 0x202246 R E 0x1000 |
763 | | // LOAD 0x204000 0xffff3000 0x02303000 0x00664 0x00664 R E 0x1000 |
764 | | // LOAD 0x205000 0x02304000 0x02304000 0x43562 0x43562 R 0x1000 |
765 | | // LOAD 0x249000 0x02348000 0x02348000 0x81800 0xcb0fc RWE 0x1000 |
766 | | // STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 |
767 | | // |
768 | | //----- kernel-2.6.18-1.2778 Fedora Core 6 test 3 |
769 | | //Program Headers(3) |
770 | | // Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
771 | | // LOAD 0x001000 0xc0400000 0x00400000 0x279820 0x279820 R E 0x1000 |
772 | | // LOAD 0x27b000 0xc067a000 0x0067a000 0x10ee64 0x1b07e8 RWE 0x1000 |
773 | | // NOTE 0x000000 0x00000000 0x00000000 0x00000 0x00000 R 0x4 |
774 | | |
775 | | bool PackVmlinuxI386::is_valid_e_entry(Addr e_entry) |
776 | 0 | { |
777 | 0 | return 0==(0x000fffff & e_entry); // entry on whole 1 MiB |
778 | 0 | } |
779 | | |
780 | | |
781 | | Linker* PackVmlinuxI386::newLinker() const |
782 | 0 | { |
783 | 0 | return new ElfLinkerX86; |
784 | 0 | } |
785 | | |
786 | | |
787 | | void PackVmlinuxI386::buildLoader(const Filter *ft) |
788 | 0 | { |
789 | | // prepare loader |
790 | 0 | initLoader(stub_i386_linux_kernel_vmlinux, sizeof(stub_i386_linux_kernel_vmlinux)); |
791 | 0 | addLoader("LINUX000", |
792 | 0 | (0x40==(0xf0 & ft->id)) ? "LXCKLLT1" : (ft->id ? "LXCALLT1" : ""), |
793 | 0 | "LXMOVEUP", |
794 | 0 | getDecompressorSections(), |
795 | 0 | nullptr |
796 | 0 | ); |
797 | 0 | if (ft->id) { |
798 | 0 | assert(ft->calls > 0); |
799 | 0 | if (0x40==(0xf0 & ft->id)) { |
800 | 0 | addLoader("LXCKLLT9", nullptr); |
801 | 0 | } |
802 | 0 | else { |
803 | 0 | addLoader("LXCALLT9", nullptr); |
804 | 0 | } |
805 | 0 | addFilter32(ft->id); |
806 | 0 | } |
807 | 0 | addLoader("LINUX990", |
808 | 0 | ((ph.first_offset_found == 1) ? "LINUX991" : ""), |
809 | 0 | "LINUX992,IDENTSTR,UPX1HEAD", nullptr); |
810 | 0 | } |
811 | | |
812 | | void PackVmlinuxAMD64::buildLoader(const Filter *ft) |
813 | 0 | { |
814 | | // prepare loader |
815 | 0 | initLoader(stub_amd64_linux_kernel_vmlinux, sizeof(stub_amd64_linux_kernel_vmlinux)); |
816 | 0 | addLoader("LINUX000", |
817 | 0 | (0x40==(0xf0 & ft->id)) ? "LXCKLLT1" : (ft->id ? "LXCALLT1" : ""), |
818 | 0 | "LXMOVEUP", |
819 | 0 | getDecompressorSections(), |
820 | 0 | nullptr |
821 | 0 | ); |
822 | 0 | if (ft->id) { |
823 | 0 | assert(ft->calls > 0); |
824 | 0 | if (0x40==(0xf0 & ft->id)) { |
825 | 0 | addLoader("LXCKLLT9", nullptr); |
826 | 0 | } |
827 | 0 | else { |
828 | 0 | addLoader("LXCALLT9", nullptr); |
829 | 0 | } |
830 | 0 | addFilter32(ft->id); |
831 | 0 | } |
832 | 0 | addLoader("LINUX990", |
833 | 0 | ((ph.first_offset_found == 1) ? "LINUX991" : ""), |
834 | 0 | "LINUX992,IDENTSTR,UPX1HEAD", nullptr); |
835 | 0 | } |
836 | | |
837 | | bool PackVmlinuxARMEL::is_valid_e_entry(Addr e_entry) |
838 | 0 | { |
839 | 0 | return 0xc0008000==e_entry; |
840 | 0 | } |
841 | | |
842 | | bool PackVmlinuxARMEB::is_valid_e_entry(Addr e_entry) |
843 | 0 | { |
844 | 0 | return 0xc0008000==e_entry; |
845 | 0 | } |
846 | | |
847 | | bool PackVmlinuxPPC32::is_valid_e_entry(Addr e_entry) |
848 | 0 | { |
849 | 0 | return 0xc0000000==e_entry; |
850 | 0 | } |
851 | | |
852 | | bool PackVmlinuxPPC64LE::is_valid_e_entry(Addr e_entry) |
853 | 0 | { |
854 | 0 | return 0xc0000000==e_entry; |
855 | 0 | } |
856 | | |
857 | | Linker* PackVmlinuxARMEL::newLinker() const |
858 | 0 | { |
859 | 0 | return new ElfLinkerArmLE; |
860 | 0 | } |
861 | | |
862 | | Linker* PackVmlinuxARMEB::newLinker() const |
863 | 0 | { |
864 | 0 | return new ElfLinkerArmBE; |
865 | 0 | } |
866 | | |
867 | | Linker* PackVmlinuxPPC32::newLinker() const |
868 | 0 | { |
869 | 0 | return new ElfLinkerPpc32; |
870 | 0 | } |
871 | | |
872 | | Linker* PackVmlinuxPPC64LE::newLinker() const |
873 | 0 | { |
874 | 0 | return new ElfLinkerPpc64le; |
875 | 0 | } |
876 | | |
877 | | |
878 | | void PackVmlinuxARMEL::buildLoader(const Filter *ft) |
879 | 0 | { |
880 | | // prepare loader |
881 | 0 | initLoader(stub_arm_v5a_linux_kernel_vmlinux, sizeof(stub_arm_v5a_linux_kernel_vmlinux)); |
882 | 0 | addLoader("LINUX000", nullptr); |
883 | 0 | if (ft->id) { |
884 | 0 | assert(ft->calls > 0); |
885 | 0 | addLoader("LINUX010", nullptr); |
886 | 0 | } |
887 | 0 | addLoader("LINUX020", nullptr); |
888 | 0 | if (ft->id) { |
889 | 0 | addFilter32(ft->id); |
890 | 0 | } |
891 | 0 | addLoader("LINUX030", nullptr); |
892 | 0 | if (ph.method == M_NRV2E_8) addLoader("NRV2E", nullptr); |
893 | 0 | else if (ph.method == M_NRV2B_8) addLoader("NRV2B", nullptr); |
894 | 0 | else if (ph.method == M_NRV2D_8) addLoader("NRV2D", nullptr); |
895 | 0 | else if (M_IS_LZMA(ph.method)) addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr); |
896 | 0 | else throwBadLoader(); |
897 | 0 | addLoader("IDENTSTR,UPX1HEAD", nullptr); |
898 | 0 | } |
899 | | |
900 | | void PackVmlinuxARMEB::buildLoader(const Filter *ft) |
901 | 0 | { |
902 | | // prepare loader |
903 | 0 | initLoader(stub_armeb_v5a_linux_kernel_vmlinux, sizeof(stub_armeb_v5a_linux_kernel_vmlinux)); |
904 | 0 | addLoader("LINUX000", nullptr); |
905 | 0 | if (ft->id) { |
906 | 0 | assert(ft->calls > 0); |
907 | 0 | addLoader("LINUX010", nullptr); |
908 | 0 | } |
909 | 0 | addLoader("LINUX020", nullptr); |
910 | 0 | if (ft->id) { |
911 | 0 | addFilter32(ft->id); |
912 | 0 | } |
913 | 0 | addLoader("LINUX030", nullptr); |
914 | 0 | if (ph.method == M_NRV2E_8) addLoader("NRV2E", nullptr); |
915 | 0 | else if (ph.method == M_NRV2B_8) addLoader("NRV2B", nullptr); |
916 | 0 | else if (ph.method == M_NRV2D_8) addLoader("NRV2D", nullptr); |
917 | 0 | else if (M_IS_LZMA(ph.method)) addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr); |
918 | 0 | else throwBadLoader(); |
919 | 0 | addLoader("IDENTSTR,UPX1HEAD", nullptr); |
920 | 0 | } |
921 | | |
922 | | void PackVmlinuxPPC32::buildLoader(const Filter *ft) |
923 | 0 | { |
924 | | // prepare loader |
925 | 0 | initLoader(stub_powerpc_linux_kernel_vmlinux, sizeof(stub_powerpc_linux_kernel_vmlinux)); |
926 | 0 | addLoader("LINUX000", nullptr); |
927 | 0 | if (ft->id) { |
928 | 0 | assert(ft->calls > 0); |
929 | 0 | addLoader("LINUX010", nullptr); |
930 | 0 | } |
931 | 0 | addLoader("LINUX020", nullptr); |
932 | 0 | if (ft->id) { |
933 | 0 | addFilter32(ft->id); |
934 | 0 | } |
935 | 0 | addLoader("LINUX030", nullptr); |
936 | 0 | if (ph.method == M_NRV2E_LE32) addLoader("NRV2E,NRV_TAIL", nullptr); |
937 | 0 | else if (ph.method == M_NRV2B_LE32) addLoader("NRV2B,NRV_TAIL", nullptr); |
938 | 0 | else if (ph.method == M_NRV2D_LE32) addLoader("NRV2D,NRV_TAIL", nullptr); |
939 | 0 | else if (M_IS_LZMA(ph.method)) addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr); |
940 | 0 | else throwBadLoader(); |
941 | 0 | if (hasLoaderSection("CFLUSH")) |
942 | 0 | addLoader("CFLUSH"); |
943 | |
|
944 | 0 | addLoader("IDENTSTR,UPX1HEAD", nullptr); |
945 | 0 | } |
946 | | |
947 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
948 | | #include "stub/powerpc64le-linux.kernel.vmlinux.h" |
949 | | void PackVmlinuxPPC64LE::buildLoader(const Filter *ft) |
950 | 0 | { |
951 | | // prepare loader |
952 | 0 | initLoader(stub_powerpc64le_linux_kernel_vmlinux, sizeof(stub_powerpc64le_linux_kernel_vmlinux)); |
953 | 0 | addLoader("LINUX000", nullptr); |
954 | 0 | if (ft->id) { |
955 | 0 | assert(ft->calls > 0); |
956 | 0 | addLoader("LINUX010", nullptr); |
957 | 0 | } |
958 | 0 | addLoader("LINUX020", nullptr); |
959 | 0 | if (ft->id) { |
960 | 0 | addFilter32(ft->id); |
961 | 0 | } |
962 | 0 | addLoader("LINUX030", nullptr); |
963 | 0 | if (ph.method == M_NRV2E_LE32) addLoader("NRV2E,NRV_TAIL", nullptr); |
964 | 0 | else if (ph.method == M_NRV2B_LE32) addLoader("NRV2B,NRV_TAIL", nullptr); |
965 | 0 | else if (ph.method == M_NRV2D_LE32) addLoader("NRV2D,NRV_TAIL", nullptr); |
966 | 0 | else if (M_IS_LZMA(ph.method)) addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr); |
967 | 0 | else throwBadLoader(); |
968 | 0 | if (hasLoaderSection("CFLUSH")) |
969 | 0 | addLoader("CFLUSH"); |
970 | |
|
971 | 0 | addLoader("IDENTSTR,UPX1HEAD", nullptr); |
972 | 0 | } |
973 | | |
974 | | |
975 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
976 | | #include "stub/i386-linux.kernel.vmlinux-head.h" |
977 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
978 | | #include "stub/amd64-linux.kernel.vmlinux-head.h" |
979 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
980 | | #include "stub/arm.v5a-linux.kernel.vmlinux-head.h" |
981 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
982 | | #include "stub/armeb.v5a-linux.kernel.vmlinux-head.h" |
983 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
984 | | #include "stub/powerpc-linux.kernel.vmlinux-head.h" |
985 | | |
986 | | unsigned PackVmlinuxI386::write_vmlinux_head( |
987 | | OutputFile *fo, |
988 | | Shdr *stxt |
989 | | ) |
990 | 0 | { |
991 | | // COMPRESSED_LENGTH |
992 | 0 | fo->write(&stub_i386_linux_kernel_vmlinux_head[0], |
993 | 0 | sizeof(stub_i386_linux_kernel_vmlinux_head)-(1+ 4) +1); |
994 | 0 | TE32 tmp_u32; tmp_u32 = ph.c_len; fo->write(&tmp_u32, 4); |
995 | |
|
996 | 0 | stxt->sh_size += sizeof(stub_i386_linux_kernel_vmlinux_head); |
997 | |
|
998 | 0 | return sizeof(stub_i386_linux_kernel_vmlinux_head); |
999 | 0 | } |
1000 | | |
1001 | | unsigned PackVmlinuxAMD64::write_vmlinux_head( |
1002 | | OutputFile *fo, |
1003 | | Shdr *stxt |
1004 | | ) |
1005 | 0 | { |
1006 | | // COMPRESSED_LENGTH |
1007 | 0 | fo->write(&stub_amd64_linux_kernel_vmlinux_head[0], |
1008 | 0 | sizeof(stub_amd64_linux_kernel_vmlinux_head)-(1+ 4) +1); |
1009 | 0 | TE32 tmp_u32; tmp_u32 = ph.c_len; fo->write(&tmp_u32, 4); |
1010 | 0 | printf(" Compressed length=0x%x\n", ph.c_len); |
1011 | 0 | printf("UnCompressed length=0x%x\n", ph.u_len); |
1012 | |
|
1013 | 0 | stxt->sh_size += sizeof(stub_amd64_linux_kernel_vmlinux_head); |
1014 | |
|
1015 | 0 | return sizeof(stub_amd64_linux_kernel_vmlinux_head); |
1016 | 0 | } |
1017 | | |
1018 | | void PackVmlinuxARMEL::defineDecompressorSymbols() |
1019 | 0 | { |
1020 | 0 | super::defineDecompressorSymbols(); |
1021 | 0 | linker->defineSymbol( "COMPRESSED_LENGTH", ph.c_len); |
1022 | 0 | linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len); |
1023 | 0 | linker->defineSymbol("METHOD", ph.method); |
1024 | 0 | } |
1025 | | |
1026 | | void PackVmlinuxARMEB::defineDecompressorSymbols() |
1027 | 0 | { |
1028 | 0 | super::defineDecompressorSymbols(); |
1029 | 0 | linker->defineSymbol( "COMPRESSED_LENGTH", ph.c_len); |
1030 | 0 | linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len); |
1031 | 0 | linker->defineSymbol("METHOD", ph.method); |
1032 | 0 | } |
1033 | | |
1034 | | void PackVmlinuxPPC32::defineDecompressorSymbols() |
1035 | 0 | { |
1036 | 0 | super::defineDecompressorSymbols(); |
1037 | | // linker->defineSymbol( "COMPRESSED_LENGTH", ph.c_len); |
1038 | | // linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len); |
1039 | | // linker->defineSymbol("METHOD", ph.method); |
1040 | 0 | } |
1041 | | |
1042 | | void PackVmlinuxPPC64LE::defineDecompressorSymbols() |
1043 | 0 | { |
1044 | 0 | super::defineDecompressorSymbols(); |
1045 | | // linker->defineSymbol( "COMPRESSED_LENGTH", ph.c_len); |
1046 | | // linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len); |
1047 | | // linker->defineSymbol("METHOD", ph.method); |
1048 | 0 | } |
1049 | | |
1050 | | void PackVmlinuxI386::defineDecompressorSymbols() |
1051 | 0 | { |
1052 | 0 | super::defineDecompressorSymbols(); |
1053 | 0 | linker->defineSymbol("ENTRY_POINT", phdri[0].p_paddr); |
1054 | 0 | linker->defineSymbol("PHYSICAL_START", phdri[0].p_paddr); |
1055 | 0 | } |
1056 | | |
1057 | | void PackVmlinuxAMD64::defineDecompressorSymbols() |
1058 | 0 | { |
1059 | 0 | super::defineDecompressorSymbols(); |
1060 | | // We assume a 32-bit boot loader, so we use the 32-bit convention |
1061 | | // of "enter at the beginning" (startup_32). The 64-bit convention |
1062 | | // would be to use ehdri.e_entry (startup_64). |
1063 | 0 | linker->defineSymbol("ENTRY_POINT", (unsigned) phdri[0].p_paddr); |
1064 | 0 | linker->defineSymbol("PHYSICAL_START", (unsigned) phdri[0].p_paddr); |
1065 | 0 | } |
1066 | | |
1067 | | unsigned PackVmlinuxARMEL::write_vmlinux_head( |
1068 | | OutputFile *fo, |
1069 | | Shdr *stxt |
1070 | | ) |
1071 | 0 | { |
1072 | | // First word from vmlinux-head.S |
1073 | 0 | fo->write(&stub_arm_v5a_linux_kernel_vmlinux_head[0], 4); |
1074 | | |
1075 | | // Second word |
1076 | 0 | TE32 tmp_u32; |
1077 | 0 | unsigned const t = (0xff000000 & |
1078 | 0 | BeLePolicy::get32(&stub_arm_v5a_linux_kernel_vmlinux_head[4])) |
1079 | 0 | | (0x00ffffff & (0u - 1 + ((3+ ph.c_len)>>2))); |
1080 | 0 | tmp_u32 = t; |
1081 | 0 | fo->write(&tmp_u32, 4); |
1082 | |
|
1083 | 0 | stxt->sh_addralign = 4; |
1084 | 0 | stxt->sh_size += sizeof(stub_arm_v5a_linux_kernel_vmlinux_head); |
1085 | |
|
1086 | 0 | return sizeof(stub_arm_v5a_linux_kernel_vmlinux_head); |
1087 | 0 | } |
1088 | | |
1089 | | unsigned PackVmlinuxARMEB::write_vmlinux_head( |
1090 | | OutputFile *fo, |
1091 | | Shdr *stxt |
1092 | | ) |
1093 | 0 | { |
1094 | | // First word from vmlinux-head.S |
1095 | 0 | fo->write(&stub_armeb_v5a_linux_kernel_vmlinux_head[0], 4); |
1096 | | |
1097 | | // Second word |
1098 | 0 | TE32 tmp_u32; |
1099 | 0 | unsigned const t = (0xff000000 & |
1100 | 0 | BeLePolicy::get32(&stub_armeb_v5a_linux_kernel_vmlinux_head[4])) |
1101 | 0 | | (0x00ffffff & (0u - 1 + ((3+ ph.c_len)>>2))); |
1102 | 0 | tmp_u32 = t; |
1103 | 0 | fo->write(&tmp_u32, 4); |
1104 | |
|
1105 | 0 | stxt->sh_addralign = 4; |
1106 | 0 | stxt->sh_size += sizeof(stub_armeb_v5a_linux_kernel_vmlinux_head); |
1107 | |
|
1108 | 0 | return sizeof(stub_armeb_v5a_linux_kernel_vmlinux_head); |
1109 | 0 | } |
1110 | | |
1111 | | unsigned PackVmlinuxPPC32::write_vmlinux_head( |
1112 | | OutputFile * /*fo*/, |
1113 | | Shdr * /*stxt*/ |
1114 | | ) |
1115 | 0 | { |
1116 | 0 | return 0; |
1117 | 0 | } |
1118 | | |
1119 | | unsigned PackVmlinuxPPC64LE::write_vmlinux_head( |
1120 | | OutputFile * /*const fo*/, |
1121 | | Shdr * /*const stxt*/ |
1122 | | ) |
1123 | 0 | { |
1124 | 0 | return 0; |
1125 | 0 | } |
1126 | | |
1127 | | |
1128 | | bool PackVmlinuxARMEL::has_valid_vmlinux_head() |
1129 | 0 | { |
1130 | 0 | TE32 buf[2]; |
1131 | 0 | fi->seek(p_text->sh_offset + sizeof(stub_arm_v5a_linux_kernel_vmlinux_head) -8, SEEK_SET); |
1132 | 0 | fi->readx(buf, sizeof(buf)); |
1133 | | //unsigned const word0 = buf[0]; |
1134 | 0 | unsigned const word1 = buf[1]; |
1135 | 0 | if (0xeb==(word1>>24) |
1136 | 0 | && (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) { |
1137 | 0 | return true; |
1138 | 0 | } |
1139 | 0 | return false; |
1140 | 0 | } |
1141 | | |
1142 | | bool PackVmlinuxARMEB::has_valid_vmlinux_head() |
1143 | 0 | { |
1144 | 0 | TE32 buf[2]; |
1145 | 0 | fi->seek(p_text->sh_offset + sizeof(stub_armeb_v5a_linux_kernel_vmlinux_head) -8, SEEK_SET); |
1146 | 0 | fi->readx(buf, sizeof(buf)); |
1147 | | //unsigned const word0 = buf[0]; |
1148 | 0 | unsigned const word1 = buf[1]; |
1149 | 0 | if (0xeb==(word1>>24) |
1150 | 0 | && (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) { |
1151 | 0 | return true; |
1152 | 0 | } |
1153 | 0 | return false; |
1154 | 0 | } |
1155 | | |
1156 | | bool PackVmlinuxPPC32::has_valid_vmlinux_head() |
1157 | 0 | { |
1158 | 0 | TE32 buf[2]; |
1159 | 0 | fi->seek(p_text->sh_offset + sizeof(stub_powerpc_linux_kernel_vmlinux_head) -8, SEEK_SET); |
1160 | 0 | fi->readx(buf, sizeof(buf)); |
1161 | | //unsigned const word0 = buf[0]; |
1162 | 0 | unsigned const word1 = buf[1]; |
1163 | 0 | if (0xeb==(word1>>24) |
1164 | 0 | && (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) { |
1165 | 0 | return true; |
1166 | 0 | } |
1167 | 0 | return false; |
1168 | 0 | } |
1169 | | |
1170 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1171 | | #include "stub/powerpc64le-linux.kernel.vmlinux-head.h" |
1172 | | bool PackVmlinuxPPC64LE::has_valid_vmlinux_head() |
1173 | 0 | { |
1174 | 0 | TE64 buf[2]; |
1175 | 0 | fi->seek(p_text->sh_offset + sizeof(stub_powerpc64le_linux_kernel_vmlinux_head) -8, SEEK_SET); |
1176 | 0 | fi->readx(buf, sizeof(buf)); |
1177 | | //unsigned const word0 = buf[0]; |
1178 | 0 | unsigned const word1 = buf[1]; |
1179 | 0 | if (0xeb==(word1>>24) |
1180 | 0 | && (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) { |
1181 | 0 | return true; |
1182 | 0 | } |
1183 | 0 | return false; |
1184 | 0 | } |
1185 | | |
1186 | | bool PackVmlinuxI386::has_valid_vmlinux_head() |
1187 | 0 | { |
1188 | 0 | unsigned char buf[5]; |
1189 | 0 | fi->seek(p_text->sh_offset + sizeof(stub_i386_linux_kernel_vmlinux_head) -5, SEEK_SET); |
1190 | 0 | fi->readx(&buf[0], 5); |
1191 | 0 | if (0xE8!=buf[0] || BeLePolicy::get32(&buf[1]) != ph.c_len) |
1192 | 0 | { |
1193 | 0 | return false; |
1194 | 0 | } |
1195 | 0 | return true; |
1196 | 0 | } |
1197 | | |
1198 | | bool PackVmlinuxAMD64::has_valid_vmlinux_head() |
1199 | 0 | { |
1200 | 0 | unsigned char buf[5]; |
1201 | 0 | fi->seek(p_text->sh_offset + sizeof(stub_amd64_linux_kernel_vmlinux_head) -5, SEEK_SET); |
1202 | 0 | fi->readx(&buf[0], 5); |
1203 | 0 | if (0xE8!=buf[0] || BeLePolicy::get32(&buf[1]) != ph.c_len) |
1204 | 0 | { |
1205 | 0 | return false; |
1206 | 0 | } |
1207 | 0 | return true; |
1208 | 0 | } |
1209 | | |
1210 | | |
1211 | | /************************************************************************* |
1212 | | // |
1213 | | **************************************************************************/ |
1214 | | |
1215 | | const int *PackVmlinuxAMD64::getCompressionMethods(int method, int level) const |
1216 | 0 | { |
1217 | 0 | return Packer::getDefaultCompressionMethods_le32(method, level); |
1218 | 0 | } |
1219 | | |
1220 | | |
1221 | | const int *PackVmlinuxAMD64::getFilters() const |
1222 | 0 | { |
1223 | 0 | static const int filters[] = { |
1224 | 0 | 0x49, 0x46, |
1225 | 0 | -1 }; |
1226 | 0 | return filters; |
1227 | 0 | } |
1228 | | |
1229 | | bool PackVmlinuxAMD64::is_valid_e_entry(Addr e_entry) |
1230 | 0 | { |
1231 | 0 | return 0x200000<=e_entry; // 2 MiB |
1232 | 0 | } |
1233 | | |
1234 | | Linker* PackVmlinuxAMD64::newLinker() const |
1235 | 0 | { |
1236 | 0 | return new ElfLinkerX86; |
1237 | 0 | } |
1238 | | |
1239 | | |
1240 | | |
1241 | | // instantiate instances |
1242 | | template class PackVmlinuxBase<ElfClass_BE32>; |
1243 | | // template class PackVmlinuxBase<ElfClass_BE64>; // currently not used |
1244 | | template class PackVmlinuxBase<ElfClass_LE32>; |
1245 | | template class PackVmlinuxBase<ElfClass_LE64>; |
1246 | | |
1247 | | /* vim:set ts=4 sw=4 et: */ |