@@ -35,15 +35,48 @@ efi_status_t check_platform_features(void)
35
35
}
36
36
37
37
/*
38
- * Although relocatable kernels can fix up the misalignment with respect to
39
- * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
40
- * sync with those recorded in the vmlinux when kaslr is disabled but the
41
- * image required relocation anyway. Therefore retain 2M alignment unless
42
- * KASLR is in use.
38
+ * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
39
+ * to provide space, and fail to zero it). Check for this condition by double
40
+ * checking that the first and the last byte of the image are covered by the
41
+ * same EFI memory map entry.
43
42
*/
44
- static u64 min_kimg_align ( void )
43
+ static bool check_image_region ( u64 base , u64 size )
45
44
{
46
- return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN ;
45
+ unsigned long map_size , desc_size , buff_size ;
46
+ efi_memory_desc_t * memory_map ;
47
+ struct efi_boot_memmap map ;
48
+ efi_status_t status ;
49
+ bool ret = false;
50
+ int map_offset ;
51
+
52
+ map .map = & memory_map ;
53
+ map .map_size = & map_size ;
54
+ map .desc_size = & desc_size ;
55
+ map .desc_ver = NULL ;
56
+ map .key_ptr = NULL ;
57
+ map .buff_size = & buff_size ;
58
+
59
+ status = efi_get_memory_map (& map );
60
+ if (status != EFI_SUCCESS )
61
+ return false;
62
+
63
+ for (map_offset = 0 ; map_offset < map_size ; map_offset += desc_size ) {
64
+ efi_memory_desc_t * md = (void * )memory_map + map_offset ;
65
+ u64 end = md -> phys_addr + md -> num_pages * EFI_PAGE_SIZE ;
66
+
67
+ /*
68
+ * Find the region that covers base, and return whether
69
+ * it covers base+size bytes.
70
+ */
71
+ if (base >= md -> phys_addr && base < end ) {
72
+ ret = (base + size ) <= end ;
73
+ break ;
74
+ }
75
+ }
76
+
77
+ efi_bs_call (free_pool , memory_map );
78
+
79
+ return ret ;
47
80
}
48
81
49
82
efi_status_t handle_kernel_image (unsigned long * image_addr ,
@@ -56,6 +89,16 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
56
89
unsigned long kernel_size , kernel_memsize = 0 ;
57
90
u32 phys_seed = 0 ;
58
91
92
+ /*
93
+ * Although relocatable kernels can fix up the misalignment with
94
+ * respect to MIN_KIMG_ALIGN, the resulting virtual text addresses are
95
+ * subtly out of sync with those recorded in the vmlinux when kaslr is
96
+ * disabled but the image required relocation anyway. Therefore retain
97
+ * 2M alignment if KASLR was explicitly disabled, even if it was not
98
+ * going to be activated to begin with.
99
+ */
100
+ u64 min_kimg_align = efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN ;
101
+
59
102
if (IS_ENABLED (CONFIG_RANDOMIZE_BASE )) {
60
103
if (!efi_nokaslr ) {
61
104
status = efi_get_random_bytes (sizeof (phys_seed ),
@@ -76,6 +119,10 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
76
119
if (image -> image_base != _text )
77
120
efi_err ("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n" );
78
121
122
+ if (!IS_ALIGNED ((u64 )_text , EFI_KIMG_ALIGN ))
123
+ efi_err ("FIRMWARE BUG: kernel image not aligned on %ldk boundary\n" ,
124
+ EFI_KIMG_ALIGN >> 10 );
125
+
79
126
kernel_size = _edata - _text ;
80
127
kernel_memsize = kernel_size + (_end - _edata );
81
128
* reserve_size = kernel_memsize ;
@@ -85,14 +132,18 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
85
132
* If KASLR is enabled, and we have some randomness available,
86
133
* locate the kernel at a randomized offset in physical memory.
87
134
*/
88
- status = efi_random_alloc (* reserve_size , min_kimg_align () ,
135
+ status = efi_random_alloc (* reserve_size , min_kimg_align ,
89
136
reserve_addr , phys_seed );
137
+ if (status != EFI_SUCCESS )
138
+ efi_warn ("efi_random_alloc() failed: 0x%lx\n" , status );
90
139
} else {
91
140
status = EFI_OUT_OF_RESOURCES ;
92
141
}
93
142
94
143
if (status != EFI_SUCCESS ) {
95
- if (IS_ALIGNED ((u64 )_text , min_kimg_align ())) {
144
+ if (!check_image_region ((u64 )_text , kernel_memsize )) {
145
+ efi_err ("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n" );
146
+ } else if (IS_ALIGNED ((u64 )_text , min_kimg_align )) {
96
147
/*
97
148
* Just execute from wherever we were loaded by the
98
149
* UEFI PE/COFF loader if the alignment is suitable.
@@ -103,7 +154,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
103
154
}
104
155
105
156
status = efi_allocate_pages_aligned (* reserve_size , reserve_addr ,
106
- ULONG_MAX , min_kimg_align () );
157
+ ULONG_MAX , min_kimg_align );
107
158
108
159
if (status != EFI_SUCCESS ) {
109
160
efi_err ("Failed to relocate kernel\n" );
0 commit comments