Browse Source

[elf] Reject ELFBoot images requiring virtual addressing

We do not set up any kind of virtual addressing before invoking an
ELFBoot image.  Reject if the image's program headers indicate that
virtual addresses are not equal to physical addresses.

This avoids problems when loading some RHEL5 kernels, which seem to
include ELFBoot headers using virtual addressing.  With this change,
these kernels are no longer detected as ELFBoot, and so may be
(correctly) detected as bzImage instead.

Reported-by: Torgeir.Wulfsberg@kongsberg.com
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
ae7f22eb28
3 changed files with 131 additions and 52 deletions
  1. 32
    1
      src/arch/i386/image/elfboot.c
  2. 88
    51
      src/image/elf.c
  3. 11
    0
      src/include/ipxe/elf.h

+ 32
- 1
src/arch/i386/image/elfboot.c View File

@@ -78,6 +78,27 @@ static int elfboot_exec ( struct image *image ) {
78 78
 	return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
79 79
 }
80 80
 
81
+/**
82
+ * Check that ELF segment uses flat physical addressing
83
+ *
84
+ * @v image		ELF file
85
+ * @v phdr		ELF program header
86
+ * @v dest		Destination address
87
+ * @ret rc		Return status code
88
+ */
89
+static int elfboot_check_segment ( struct image *image, Elf_Phdr *phdr,
90
+				   physaddr_t dest ) {
91
+
92
+	/* Check that ELF segment uses flat physical addressing */
93
+	if ( phdr->p_vaddr != dest ) {
94
+		DBGC ( image, "ELF %p uses virtual addressing (phys %x, "
95
+		       "virt %x)\n", image, phdr->p_paddr, phdr->p_vaddr );
96
+		return -ENOEXEC;
97
+	}
98
+
99
+	return 0;
100
+}
101
+
81 102
 /**
82 103
  * Probe ELF image
83 104
  *
@@ -95,14 +116,24 @@ static int elfboot_probe ( struct image *image ) {
95 116
 		[EI_DATA]	= ELFDATA2LSB,
96 117
 		[EI_VERSION]	= EV_CURRENT,
97 118
 	};
119
+	physaddr_t entry;
120
+	physaddr_t max;
121
+	int rc;
98 122
 
99 123
 	/* Read ELF header */
100 124
 	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
101 125
 	if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
102
-		DBG ( "Invalid ELF identifier\n" );
126
+		DBGC ( image, "Invalid ELF identifier\n" );
103 127
 		return -ENOEXEC;
104 128
 	}
105 129
 
130
+	/* Check that this image uses flat physical addressing */
131
+	if ( ( rc = elf_segments ( image, &ehdr, elfboot_check_segment,
132
+				   &entry, &max ) ) != 0 ) {
133
+		DBGC ( image, "Unloadable ELF image\n" );
134
+		return rc;
135
+	}
136
+
106 137
 	return 0;
107 138
 }
108 139
 

+ 88
- 51
src/image/elf.c View File

@@ -40,27 +40,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
40 40
 #include <ipxe/image.h>
41 41
 #include <ipxe/elf.h>
42 42
 
43
-typedef Elf32_Ehdr	Elf_Ehdr;
44
-typedef Elf32_Phdr	Elf_Phdr;
45
-typedef Elf32_Off	Elf_Off;
46
-#define ELFCLASS	ELFCLASS32
47
-
48 43
 /**
49 44
  * Load ELF segment into memory
50 45
  *
51 46
  * @v image		ELF file
52 47
  * @v phdr		ELF program header
48
+ * @v dest		Destination address
49
+ * @ret rc		Return status code
50
+ */
51
+static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
52
+			      physaddr_t dest ) {
53
+	userptr_t buffer = phys_to_user ( dest );
54
+	int rc;
55
+
56
+	DBGC ( image, "ELF %p loading segment [%x,%x) to [%lx,%lx,%lx)\n",
57
+	       image, phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
58
+	       dest, ( dest + phdr->p_filesz ), ( dest + phdr->p_memsz ) );
59
+
60
+	/* Verify and prepare segment */
61
+	if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
62
+				   phdr->p_memsz ) ) != 0 ) {
63
+		DBGC ( image, "ELF %p could not prepare segment: %s\n",
64
+		       image, strerror ( rc ) );
65
+		return rc;
66
+	}
67
+
68
+	/* Copy image to segment */
69
+	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
70
+
71
+	return 0;
72
+}
73
+
74
+/**
75
+ * Process ELF segment
76
+ *
77
+ * @v image		ELF file
53 78
  * @v ehdr		ELF executable header
79
+ * @v phdr		ELF program header
80
+ * @v process		Segment processor
54 81
  * @ret entry		Entry point, if found
55 82
  * @ret max		Maximum used address
56 83
  * @ret rc		Return status code
57 84
  */
58
-static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
59
-			      Elf_Ehdr *ehdr, physaddr_t *entry,
60
-			      physaddr_t *max ) {
85
+static int elf_segment ( struct image *image, Elf_Ehdr *ehdr, Elf_Phdr *phdr,
86
+			 int ( * process ) ( struct image *image,
87
+					     Elf_Phdr *phdr, physaddr_t dest ),
88
+			 physaddr_t *entry, physaddr_t *max ) {
61 89
 	physaddr_t dest;
62 90
 	physaddr_t end;
63
-	userptr_t buffer;
64 91
 	unsigned long e_offset;
65 92
 	int rc;
66 93
 
@@ -86,28 +113,15 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
86 113
 		       image );
87 114
 		return -ENOEXEC;
88 115
 	}
89
-	buffer = phys_to_user ( dest );
90 116
 	end = ( dest + phdr->p_memsz );
91 117
 
92
-	DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
93
-	       phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
94
-	       phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
95
-	       ( phdr->p_paddr + phdr->p_memsz ) );
96
-
97
-	/* Verify and prepare segment */
98
-	if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
99
-				   phdr->p_memsz ) ) != 0 ) {
100
-		DBGC ( image, "ELF %p could not prepare segment: %s\n",
101
-		       image, strerror ( rc ) );
102
-		return rc;
103
-	}
104
-
105 118
 	/* Update maximum used address, if applicable */
106 119
 	if ( end > *max )
107 120
 		*max = end;
108 121
 
109
-	/* Copy image to segment */
110
-	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
122
+	/* Process segment */
123
+	if ( ( rc = process ( image, phdr, dest ) ) != 0 )
124
+		return rc;
111 125
 
112 126
 	/* Set execution address, if it lies within this segment */
113 127
 	if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
@@ -128,62 +142,85 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
128 142
 }
129 143
 
130 144
 /**
131
- * Load ELF image into memory
145
+ * Process ELF segments
132 146
  *
133 147
  * @v image		ELF file
134
- * @ret entry		Entry point
148
+ * @v ehdr		ELF executable header
149
+ * @v process		Segment processor
150
+ * @ret entry		Entry point, if found
135 151
  * @ret max		Maximum used address
136 152
  * @ret rc		Return status code
137 153
  */
138
-int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
139
-	static const uint8_t e_ident[] = {
140
-		[EI_MAG0]	= ELFMAG0,
141
-		[EI_MAG1]	= ELFMAG1,
142
-		[EI_MAG2]	= ELFMAG2,
143
-		[EI_MAG3]	= ELFMAG3,
144
-		[EI_CLASS]	= ELFCLASS,
145
-	};
146
-	Elf_Ehdr ehdr;
154
+int elf_segments ( struct image *image, Elf_Ehdr *ehdr,
155
+		   int ( * process ) ( struct image *image, Elf_Phdr *phdr,
156
+				       physaddr_t dest ),
157
+		   physaddr_t *entry, physaddr_t *max ) {
147 158
 	Elf_Phdr phdr;
148 159
 	Elf_Off phoff;
149 160
 	unsigned int phnum;
150 161
 	int rc;
151 162
 
152
-	/* Read ELF header */
153
-	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
154
-	if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident,
155
-		      sizeof ( e_ident ) ) != 0 ) {
156
-		DBGC ( image, "ELF %p has invalid signature\n", image );
157
-		return -ENOEXEC;
158
-	}
159
-
160 163
 	/* Initialise maximum used address */
161 164
 	*max = 0;
162 165
 
163 166
 	/* Invalidate entry point */
164 167
 	*entry = 0;
165 168
 
166
-	/* Read ELF program headers */
167
-	for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
168
-	      phoff += ehdr.e_phentsize, phnum-- ) {
169
+	/* Read and process ELF program headers */
170
+	for ( phoff = ehdr->e_phoff , phnum = ehdr->e_phnum ; phnum ;
171
+	      phoff += ehdr->e_phentsize, phnum-- ) {
169 172
 		if ( phoff > image->len ) {
170 173
 			DBGC ( image, "ELF %p program header %d outside "
171 174
 			       "image\n", image, phnum );
172 175
 			return -ENOEXEC;
173 176
 		}
174 177
 		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
175
-		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
176
-					       entry, max ) ) != 0 ) {
178
+		if ( ( rc = elf_segment ( image, ehdr, &phdr, process,
179
+					  entry, max ) ) != 0 )
177 180
 			return rc;
178
-		}
179 181
 	}
180 182
 
181 183
 	/* Check for a valid execution address */
182 184
 	if ( ! *entry ) {
183 185
 		DBGC ( image, "ELF %p entry point %lx outside image\n",
184
-		       image, ( ( unsigned long ) ehdr.e_entry ) );
186
+		       image, ( ( unsigned long ) ehdr->e_entry ) );
187
+		return -ENOEXEC;
188
+	}
189
+
190
+	return 0;
191
+}
192
+
193
+/**
194
+ * Load ELF image into memory
195
+ *
196
+ * @v image		ELF file
197
+ * @ret entry		Entry point
198
+ * @ret max		Maximum used address
199
+ * @ret rc		Return status code
200
+ */
201
+int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
202
+	static const uint8_t e_ident[] = {
203
+		[EI_MAG0]	= ELFMAG0,
204
+		[EI_MAG1]	= ELFMAG1,
205
+		[EI_MAG2]	= ELFMAG2,
206
+		[EI_MAG3]	= ELFMAG3,
207
+		[EI_CLASS]	= ELFCLASS,
208
+	};
209
+	Elf_Ehdr ehdr;
210
+	int rc;
211
+
212
+	/* Read ELF header */
213
+	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
214
+	if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident,
215
+		      sizeof ( e_ident ) ) != 0 ) {
216
+		DBGC ( image, "ELF %p has invalid signature\n", image );
185 217
 		return -ENOEXEC;
186 218
 	}
187 219
 
220
+	/* Load ELF segments into memory */
221
+	if ( ( rc = elf_segments ( image, &ehdr, elf_load_segment,
222
+				   entry, max ) ) != 0 )
223
+		return rc;
224
+
188 225
 	return 0;
189 226
 }

+ 11
- 0
src/include/ipxe/elf.h View File

@@ -10,8 +10,19 @@
10 10
 
11 11
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
12 12
 
13
+#include <stdint.h>
14
+#include <ipxe/image.h>
13 15
 #include <elf.h>
14 16
 
17
+typedef Elf32_Ehdr	Elf_Ehdr;
18
+typedef Elf32_Phdr	Elf_Phdr;
19
+typedef Elf32_Off	Elf_Off;
20
+#define ELFCLASS	ELFCLASS32
21
+
22
+extern int elf_segments ( struct image *image, Elf_Ehdr *ehdr,
23
+			  int ( * process ) ( struct image *image,
24
+					      Elf_Phdr *phdr, physaddr_t dest ),
25
+			  physaddr_t *entry, physaddr_t *max );
15 26
 extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max );
16 27
 
17 28
 #endif /* _IPXE_ELF_H */

Loading…
Cancel
Save