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