Skip to content

Commit ae7f22e

Browse files
committedJul 29, 2015
[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>
1 parent 1e4ff87 commit ae7f22e

File tree

3 files changed

+131
-52
lines changed

3 files changed

+131
-52
lines changed
 

‎src/arch/i386/image/elfboot.c

+32-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,27 @@ static int elfboot_exec ( struct image *image ) {
7878
return -ECANCELED; /* -EIMPOSSIBLE, anyone? */
7979
}
8080

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+
81102
/**
82103
* Probe ELF image
83104
*
@@ -95,14 +116,24 @@ static int elfboot_probe ( struct image *image ) {
95116
[EI_DATA] = ELFDATA2LSB,
96117
[EI_VERSION] = EV_CURRENT,
97118
};
119+
physaddr_t entry;
120+
physaddr_t max;
121+
int rc;
98122

99123
/* Read ELF header */
100124
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
101125
if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
102-
DBG ( "Invalid ELF identifier\n" );
126+
DBGC ( image, "Invalid ELF identifier\n" );
103127
return -ENOEXEC;
104128
}
105129

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+
106137
return 0;
107138
}
108139

‎src/image/elf.c

+88-51
Original file line numberDiff line numberDiff line change
@@ -40,27 +40,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4040
#include <ipxe/image.h>
4141
#include <ipxe/elf.h>
4242

43-
typedef Elf32_Ehdr Elf_Ehdr;
44-
typedef Elf32_Phdr Elf_Phdr;
45-
typedef Elf32_Off Elf_Off;
46-
#define ELFCLASS ELFCLASS32
47-
4843
/**
4944
* Load ELF segment into memory
5045
*
5146
* @v image ELF file
5247
* @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
5378
* @v ehdr ELF executable header
79+
* @v phdr ELF program header
80+
* @v process Segment processor
5481
* @ret entry Entry point, if found
5582
* @ret max Maximum used address
5683
* @ret rc Return status code
5784
*/
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 ) {
6189
physaddr_t dest;
6290
physaddr_t end;
63-
userptr_t buffer;
6491
unsigned long e_offset;
6592
int rc;
6693

@@ -86,28 +113,15 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
86113
image );
87114
return -ENOEXEC;
88115
}
89-
buffer = phys_to_user ( dest );
90116
end = ( dest + phdr->p_memsz );
91117

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-
105118
/* Update maximum used address, if applicable */
106119
if ( end > *max )
107120
*max = end;
108121

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;
111125

112126
/* Set execution address, if it lies within this segment */
113127
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,
128142
}
129143

130144
/**
131-
* Load ELF image into memory
145+
* Process ELF segments
132146
*
133147
* @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
135151
* @ret max Maximum used address
136152
* @ret rc Return status code
137153
*/
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 ) {
147158
Elf_Phdr phdr;
148159
Elf_Off phoff;
149160
unsigned int phnum;
150161
int rc;
151162

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-
160163
/* Initialise maximum used address */
161164
*max = 0;
162165

163166
/* Invalidate entry point */
164167
*entry = 0;
165168

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-- ) {
169172
if ( phoff > image->len ) {
170173
DBGC ( image, "ELF %p program header %d outside "
171174
"image\n", image, phnum );
172175
return -ENOEXEC;
173176
}
174177
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 )
177180
return rc;
178-
}
179181
}
180182

181183
/* Check for a valid execution address */
182184
if ( ! *entry ) {
183185
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 );
185217
return -ENOEXEC;
186218
}
187219

220+
/* Load ELF segments into memory */
221+
if ( ( rc = elf_segments ( image, &ehdr, elf_load_segment,
222+
entry, max ) ) != 0 )
223+
return rc;
224+
188225
return 0;
189226
}

‎src/include/ipxe/elf.h

+11
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,19 @@
1010

1111
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1212

13+
#include <stdint.h>
14+
#include <ipxe/image.h>
1315
#include <elf.h>
1416

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 );
1526
extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max );
1627

1728
#endif /* _IPXE_ELF_H */

0 commit comments

Comments
 (0)
Please sign in to comment.