Skip to content

Commit 7228918

Browse files
rossphilipsonsuryasaimadhu
authored andcommitted
x86/boot: Fix memremap of setup_indirect structures
As documented, the setup_indirect structure is nested inside the setup_data structures in the setup_data list. The code currently accesses the fields inside the setup_indirect structure but only the sizeof(struct setup_data) is being memremapped. No crash occurred but this is just due to how the area is remapped under the covers. Properly memremap both the setup_data and setup_indirect structures in these cases before accessing them. Fixes: b3c72fc ("x86/boot: Introduce setup_indirect") Signed-off-by: Ross Philipson <ross.philipson@oracle.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> Cc: <stable@vger.kernel.org> Link: https://lore.kernel.org/r/1645668456-22036-2-git-send-email-ross.philipson@oracle.com
1 parent 5adf349 commit 7228918

File tree

5 files changed

+166
-47
lines changed

5 files changed

+166
-47
lines changed

arch/x86/kernel/e820.c

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -995,15 +995,25 @@ early_param("memmap", parse_memmap_opt);
995995
*/
996996
void __init e820__reserve_setup_data(void)
997997
{
998+
struct setup_indirect *indirect;
998999
struct setup_data *data;
999-
u64 pa_data;
1000+
u64 pa_data, pa_next;
1001+
u32 len;
10001002

10011003
pa_data = boot_params.hdr.setup_data;
10021004
if (!pa_data)
10031005
return;
10041006

10051007
while (pa_data) {
10061008
data = early_memremap(pa_data, sizeof(*data));
1009+
if (!data) {
1010+
pr_warn("e820: failed to memremap setup_data entry\n");
1011+
return;
1012+
}
1013+
1014+
len = sizeof(*data);
1015+
pa_next = data->next;
1016+
10071017
e820__range_update(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
10081018

10091019
/*
@@ -1015,18 +1025,27 @@ void __init e820__reserve_setup_data(void)
10151025
sizeof(*data) + data->len,
10161026
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
10171027

1018-
if (data->type == SETUP_INDIRECT &&
1019-
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
1020-
e820__range_update(((struct setup_indirect *)data->data)->addr,
1021-
((struct setup_indirect *)data->data)->len,
1022-
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
1023-
e820__range_update_kexec(((struct setup_indirect *)data->data)->addr,
1024-
((struct setup_indirect *)data->data)->len,
1025-
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
1028+
if (data->type == SETUP_INDIRECT) {
1029+
len += data->len;
1030+
early_memunmap(data, sizeof(*data));
1031+
data = early_memremap(pa_data, len);
1032+
if (!data) {
1033+
pr_warn("e820: failed to memremap indirect setup_data\n");
1034+
return;
1035+
}
1036+
1037+
indirect = (struct setup_indirect *)data->data;
1038+
1039+
if (indirect->type != SETUP_INDIRECT) {
1040+
e820__range_update(indirect->addr, indirect->len,
1041+
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
1042+
e820__range_update_kexec(indirect->addr, indirect->len,
1043+
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
1044+
}
10261045
}
10271046

1028-
pa_data = data->next;
1029-
early_memunmap(data, sizeof(*data));
1047+
pa_data = pa_next;
1048+
early_memunmap(data, len);
10301049
}
10311050

10321051
e820__update_table(e820_table);

arch/x86/kernel/kdebugfs.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,13 @@ create_setup_data_node(struct dentry *parent, int no,
8888

8989
static int __init create_setup_data_nodes(struct dentry *parent)
9090
{
91+
struct setup_indirect *indirect;
9192
struct setup_data_node *node;
9293
struct setup_data *data;
93-
int error;
94+
u64 pa_data, pa_next;
9495
struct dentry *d;
95-
u64 pa_data;
96+
int error;
97+
u32 len;
9698
int no = 0;
9799

98100
d = debugfs_create_dir("setup_data", parent);
@@ -112,20 +114,37 @@ static int __init create_setup_data_nodes(struct dentry *parent)
112114
error = -ENOMEM;
113115
goto err_dir;
114116
}
115-
116-
if (data->type == SETUP_INDIRECT &&
117-
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
118-
node->paddr = ((struct setup_indirect *)data->data)->addr;
119-
node->type = ((struct setup_indirect *)data->data)->type;
120-
node->len = ((struct setup_indirect *)data->data)->len;
117+
pa_next = data->next;
118+
119+
if (data->type == SETUP_INDIRECT) {
120+
len = sizeof(*data) + data->len;
121+
memunmap(data);
122+
data = memremap(pa_data, len, MEMREMAP_WB);
123+
if (!data) {
124+
kfree(node);
125+
error = -ENOMEM;
126+
goto err_dir;
127+
}
128+
129+
indirect = (struct setup_indirect *)data->data;
130+
131+
if (indirect->type != SETUP_INDIRECT) {
132+
node->paddr = indirect->addr;
133+
node->type = indirect->type;
134+
node->len = indirect->len;
135+
} else {
136+
node->paddr = pa_data;
137+
node->type = data->type;
138+
node->len = data->len;
139+
}
121140
} else {
122141
node->paddr = pa_data;
123142
node->type = data->type;
124143
node->len = data->len;
125144
}
126145

127146
create_setup_data_node(d, no, node);
128-
pa_data = data->next;
147+
pa_data = pa_next;
129148

130149
memunmap(data);
131150
no++;

arch/x86/kernel/ksysfs.c

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,26 +91,41 @@ static int get_setup_data_paddr(int nr, u64 *paddr)
9191

9292
static int __init get_setup_data_size(int nr, size_t *size)
9393
{
94-
int i = 0;
94+
u64 pa_data = boot_params.hdr.setup_data, pa_next;
95+
struct setup_indirect *indirect;
9596
struct setup_data *data;
96-
u64 pa_data = boot_params.hdr.setup_data;
97+
int i = 0;
98+
u32 len;
9799

98100
while (pa_data) {
99101
data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
100102
if (!data)
101103
return -ENOMEM;
104+
pa_next = data->next;
105+
102106
if (nr == i) {
103-
if (data->type == SETUP_INDIRECT &&
104-
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT)
105-
*size = ((struct setup_indirect *)data->data)->len;
106-
else
107+
if (data->type == SETUP_INDIRECT) {
108+
len = sizeof(*data) + data->len;
109+
memunmap(data);
110+
data = memremap(pa_data, len, MEMREMAP_WB);
111+
if (!data)
112+
return -ENOMEM;
113+
114+
indirect = (struct setup_indirect *)data->data;
115+
116+
if (indirect->type != SETUP_INDIRECT)
117+
*size = indirect->len;
118+
else
119+
*size = data->len;
120+
} else {
107121
*size = data->len;
122+
}
108123

109124
memunmap(data);
110125
return 0;
111126
}
112127

113-
pa_data = data->next;
128+
pa_data = pa_next;
114129
memunmap(data);
115130
i++;
116131
}
@@ -120,9 +135,11 @@ static int __init get_setup_data_size(int nr, size_t *size)
120135
static ssize_t type_show(struct kobject *kobj,
121136
struct kobj_attribute *attr, char *buf)
122137
{
138+
struct setup_indirect *indirect;
139+
struct setup_data *data;
123140
int nr, ret;
124141
u64 paddr;
125-
struct setup_data *data;
142+
u32 len;
126143

127144
ret = kobj_to_setup_data_nr(kobj, &nr);
128145
if (ret)
@@ -135,10 +152,20 @@ static ssize_t type_show(struct kobject *kobj,
135152
if (!data)
136153
return -ENOMEM;
137154

138-
if (data->type == SETUP_INDIRECT)
139-
ret = sprintf(buf, "0x%x\n", ((struct setup_indirect *)data->data)->type);
140-
else
155+
if (data->type == SETUP_INDIRECT) {
156+
len = sizeof(*data) + data->len;
157+
memunmap(data);
158+
data = memremap(paddr, len, MEMREMAP_WB);
159+
if (!data)
160+
return -ENOMEM;
161+
162+
indirect = (struct setup_indirect *)data->data;
163+
164+
ret = sprintf(buf, "0x%x\n", indirect->type);
165+
} else {
141166
ret = sprintf(buf, "0x%x\n", data->type);
167+
}
168+
142169
memunmap(data);
143170
return ret;
144171
}
@@ -149,9 +176,10 @@ static ssize_t setup_data_data_read(struct file *fp,
149176
char *buf,
150177
loff_t off, size_t count)
151178
{
179+
struct setup_indirect *indirect;
180+
struct setup_data *data;
152181
int nr, ret = 0;
153182
u64 paddr, len;
154-
struct setup_data *data;
155183
void *p;
156184

157185
ret = kobj_to_setup_data_nr(kobj, &nr);
@@ -165,10 +193,27 @@ static ssize_t setup_data_data_read(struct file *fp,
165193
if (!data)
166194
return -ENOMEM;
167195

168-
if (data->type == SETUP_INDIRECT &&
169-
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
170-
paddr = ((struct setup_indirect *)data->data)->addr;
171-
len = ((struct setup_indirect *)data->data)->len;
196+
if (data->type == SETUP_INDIRECT) {
197+
len = sizeof(*data) + data->len;
198+
memunmap(data);
199+
data = memremap(paddr, len, MEMREMAP_WB);
200+
if (!data)
201+
return -ENOMEM;
202+
203+
indirect = (struct setup_indirect *)data->data;
204+
205+
if (indirect->type != SETUP_INDIRECT) {
206+
paddr = indirect->addr;
207+
len = indirect->len;
208+
} else {
209+
/*
210+
* Even though this is technically undefined, return
211+
* the data as though it is a normal setup_data struct.
212+
* This will at least allow it to be inspected.
213+
*/
214+
paddr += sizeof(*data);
215+
len = data->len;
216+
}
172217
} else {
173218
paddr += sizeof(*data);
174219
len = data->len;

arch/x86/kernel/setup.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,21 +369,41 @@ static void __init parse_setup_data(void)
369369

370370
static void __init memblock_x86_reserve_range_setup_data(void)
371371
{
372+
struct setup_indirect *indirect;
372373
struct setup_data *data;
373-
u64 pa_data;
374+
u64 pa_data, pa_next;
375+
u32 len;
374376

375377
pa_data = boot_params.hdr.setup_data;
376378
while (pa_data) {
377379
data = early_memremap(pa_data, sizeof(*data));
380+
if (!data) {
381+
pr_warn("setup: failed to memremap setup_data entry\n");
382+
return;
383+
}
384+
385+
len = sizeof(*data);
386+
pa_next = data->next;
387+
378388
memblock_reserve(pa_data, sizeof(*data) + data->len);
379389

380-
if (data->type == SETUP_INDIRECT &&
381-
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT)
382-
memblock_reserve(((struct setup_indirect *)data->data)->addr,
383-
((struct setup_indirect *)data->data)->len);
390+
if (data->type == SETUP_INDIRECT) {
391+
len += data->len;
392+
early_memunmap(data, sizeof(*data));
393+
data = early_memremap(pa_data, len);
394+
if (!data) {
395+
pr_warn("setup: failed to memremap indirect setup_data\n");
396+
return;
397+
}
384398

385-
pa_data = data->next;
386-
early_memunmap(data, sizeof(*data));
399+
indirect = (struct setup_indirect *)data->data;
400+
401+
if (indirect->type != SETUP_INDIRECT)
402+
memblock_reserve(indirect->addr, indirect->len);
403+
}
404+
405+
pa_data = pa_next;
406+
early_memunmap(data, len);
387407
}
388408
}
389409

arch/x86/mm/ioremap.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ static bool memremap_is_efi_data(resource_size_t phys_addr,
615615
static bool memremap_is_setup_data(resource_size_t phys_addr,
616616
unsigned long size)
617617
{
618+
struct setup_indirect *indirect;
618619
struct setup_data *data;
619620
u64 paddr, paddr_next;
620621

@@ -627,6 +628,10 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
627628

628629
data = memremap(paddr, sizeof(*data),
629630
MEMREMAP_WB | MEMREMAP_DEC);
631+
if (!data) {
632+
pr_warn("failed to memremap setup_data entry\n");
633+
return false;
634+
}
630635

631636
paddr_next = data->next;
632637
len = data->len;
@@ -636,10 +641,21 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
636641
return true;
637642
}
638643

639-
if (data->type == SETUP_INDIRECT &&
640-
((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) {
641-
paddr = ((struct setup_indirect *)data->data)->addr;
642-
len = ((struct setup_indirect *)data->data)->len;
644+
if (data->type == SETUP_INDIRECT) {
645+
memunmap(data);
646+
data = memremap(paddr, sizeof(*data) + len,
647+
MEMREMAP_WB | MEMREMAP_DEC);
648+
if (!data) {
649+
pr_warn("failed to memremap indirect setup_data\n");
650+
return false;
651+
}
652+
653+
indirect = (struct setup_indirect *)data->data;
654+
655+
if (indirect->type != SETUP_INDIRECT) {
656+
paddr = indirect->addr;
657+
len = indirect->len;
658+
}
643659
}
644660

645661
memunmap(data);

0 commit comments

Comments
 (0)