x86-64: Treat R_X86_64_PLT32 as R_X86_64_PC32
[grub.git] / util / grub-module-verifier.c
1 #include <stdio.h>
2 #include <string.h>
3
4 #include <grub/elf.h>
5 #include <grub/module_verifier.h>
6 #include <grub/misc.h>
7 #include <grub/util/misc.h>
8
9 struct grub_module_verifier_arch archs[] = {
10   { "i386", 4, 0, EM_386, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){
11       R_386_32,
12       R_386_PC32,
13       -1
14     } },
15   { "x86_64", 8, 0, EM_X86_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
16       R_X86_64_64,
17       R_X86_64_PC64,
18       /* R_X86_64_32, R_X86_64_32S are supported but shouldn't be used because of their limited range.  */
19       -1
20     }, (int[]){
21       R_X86_64_PC32,
22       R_X86_64_PLT32,
23       -1
24     }
25   },
26   { "powerpc", 4, 1, EM_PPC, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
27       GRUB_ELF_R_PPC_ADDR16_LO,
28       GRUB_ELF_R_PPC_REL24, /* It has limited range but GRUB adds trampolines when necessarry.  */
29       GRUB_ELF_R_PPC_ADDR16_HA,
30       GRUB_ELF_R_PPC_ADDR32,
31       GRUB_ELF_R_PPC_REL32,
32       -1
33     } },
34   { "sparc64", 8, 1, EM_SPARCV9, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
35       R_SPARC_WDISP30, /* It has limited range but GRUB adds trampolines when necessarry. */
36       R_SPARC_HH22,
37       R_SPARC_HM10,
38       R_SPARC_LM22,
39       R_SPARC_LO10,
40       R_SPARC_64,
41       R_SPARC_OLO10,
42       /* Following 2 relocations have limited range but unfortunately
43          clang generates them, as it doesn't implement mcmodel=large properly.
44          At least our heap and core are under 4G, so it's not a problem
45          usually. */
46       R_SPARC_HI22,
47       R_SPARC_32,
48       -1
49     } },
50   { "ia64", 8, 0, EM_IA_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
51       R_IA64_PCREL21B, /* We should verify that it's pointing either
52                           to a function or to a section in the same module.
53                           Checking that external symbol is a function is
54                           non-trivial and I have never seen this relocation used
55                           for anything else, so assume that it always points to a
56                           function.
57                        */
58       R_IA64_SEGREL64LSB,
59       R_IA64_FPTR64LSB,
60       R_IA64_DIR64LSB,
61       R_IA64_PCREL64LSB,
62       R_IA64_LTOFF22X,
63       R_IA64_LTOFF22,
64       R_IA64_GPREL64I,
65       R_IA64_LTOFF_FPTR22,
66       R_IA64_LDXMOV,
67       -1
68     }, (int[]){
69       R_IA64_GPREL22,
70       -1
71     } },
72   { "mipsel", 4, 0, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
73       R_MIPS_HI16,
74       R_MIPS_LO16,
75       R_MIPS_32,
76       R_MIPS_GPREL32,
77       R_MIPS_26,
78       R_MIPS_GOT16,
79       R_MIPS_CALL16,
80       R_MIPS_JALR,
81       -1
82     } },
83   { "mips", 4, 1, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
84       R_MIPS_HI16,
85       R_MIPS_LO16,
86       R_MIPS_32,
87       R_MIPS_GPREL32,
88       R_MIPS_26,
89       R_MIPS_GOT16,
90       R_MIPS_CALL16,
91       R_MIPS_JALR,
92       -1
93     } },
94   { "arm", 4, 0, EM_ARM, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){
95       /* Some relocations are range-limited but trampolines are added when necessarry. */
96       R_ARM_ABS32,
97       R_ARM_CALL,
98       R_ARM_JUMP24,
99       R_ARM_THM_CALL,
100       R_ARM_THM_JUMP24,
101       R_ARM_V4BX,
102       R_ARM_THM_MOVW_ABS_NC,
103       R_ARM_THM_MOVT_ABS,
104       R_ARM_THM_JUMP19,
105       -1
106     } },
107   { "arm64", 8, 0, EM_AARCH64, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
108       R_AARCH64_ABS64,
109       R_AARCH64_CALL26,
110       R_AARCH64_JUMP26,
111       R_AARCH64_ADR_GOT_PAGE,
112       R_AARCH64_LD64_GOT_LO12_NC,
113       -1
114     }, (int[]){
115       R_AARCH64_ADR_PREL_PG_HI21,
116       R_AARCH64_ADD_ABS_LO12_NC,
117       R_AARCH64_LDST64_ABS_LO12_NC,
118       R_AARCH64_PREL32,
119       -1
120     }
121   },
122 };
123
124 struct platform_whitelist {
125   const char *arch;
126   const char *platform;
127   const char **whitelist_empty;
128 };
129
130 static struct platform_whitelist whitelists[] = {
131   {"i386", "xen", (const char *[]) {"all_video", 0}},
132   {"x86_64", "xen", (const char *[]) {"all_video", 0}},
133   {"sparc64", "ieee1275", (const char *[]) {"all_video", 0}},
134
135   /* video is compiled-in on MIPS.  */
136   {"mipsel", "loongson", (const char *[]) {"all_video", 0}},
137   {"mipsel", "qemu_mips", (const char *[]) {"all_video", 0}},
138   {"mipsel", "arc", (const char *[]) {"all_video", 0}},
139   {"mips", "qemu_mips", (const char *[]) {"all_video", 0}},
140   {"mips", "arc", (const char *[]) {"all_video", 0}},
141 };
142
143
144 int
145 main (int argc, char **argv)
146 {
147   size_t module_size;
148   unsigned arch, whitelist;
149   const char **whitelist_empty = 0;
150   char *module_img;
151   if (argc != 4) {
152     fprintf (stderr, "usage: %s FILE ARCH PLATFORM\n", argv[0]);
153     return 1;
154   }
155
156   for (arch = 0; arch < ARRAY_SIZE(archs); arch++)
157     if (strcmp(archs[arch].name, argv[2]) == 0)
158       break;
159   if (arch == ARRAY_SIZE(archs))
160     grub_util_error("unknown arch: %s", argv[2]);
161
162   for (whitelist = 0; whitelist < ARRAY_SIZE(whitelists); whitelist++)
163     if (strcmp(whitelists[whitelist].arch, argv[2]) == 0
164         && strcmp(whitelists[whitelist].platform, argv[3]) == 0)
165       break;
166   if (whitelist != ARRAY_SIZE(whitelists))
167     whitelist_empty = whitelists[whitelist].whitelist_empty;
168
169   module_size = grub_util_get_image_size (argv[1]);
170   module_img = grub_util_read_image (argv[1]);
171   if (archs[arch].voidp_sizeof == 8)
172     grub_module_verify64(module_img, module_size, &archs[arch], whitelist_empty);
173   else
174     grub_module_verify32(module_img, module_size, &archs[arch], whitelist_empty);
175   return 0;
176 }