diff mbox series

hw/elf_ops: clear uninitialized segment space

Message ID 20210414105838.205019-1-laurent@vivier.eu (mailing list archive)
State New, archived
Headers show
Series hw/elf_ops: clear uninitialized segment space | expand

Commit Message

Laurent Vivier April 14, 2021, 10:58 a.m. UTC
When the mem_size of the segment is bigger than the file_size,
and if this space doesn't overlap another segment, it needs
to be cleared.

This bug is very similar to the one we had for linux-user,
22d113b52f41 ("linux-user: Fix loading of BSS segments"),
where .bss section is encoded as an extension of the the data
one by setting the segment p_memsz > p_filesz.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 include/hw/elf_ops.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

Comments

Philippe Mathieu-Daudé April 14, 2021, 12:16 p.m. UTC | #1
On 4/14/21 12:58 PM, Laurent Vivier wrote:
> When the mem_size of the segment is bigger than the file_size,
> and if this space doesn't overlap another segment, it needs
> to be cleared.
> 
> This bug is very similar to the one we had for linux-user,
> 22d113b52f41 ("linux-user: Fix loading of BSS segments"),
> where .bss section is encoded as an extension of the the data
> one by setting the segment p_memsz > p_filesz.
> 
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
>  include/hw/elf_ops.h | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
> index 6ee458e7bc3c..e3dcee3ee349 100644
> --- a/include/hw/elf_ops.h
> +++ b/include/hw/elf_ops.h
> @@ -562,6 +562,23 @@ static int glue(load_elf, SZ)(const char *name, int fd,
>                      if (res != MEMTX_OK) {
>                          goto fail;
>                      }
> +                    /*
> +                     * We need to zero'ify the space that is not copied
> +                     * from file
> +                     */
> +                    if (file_size < mem_size) {
> +                        static uint8_t zero[4096];

Given it is unlikely, maybe better use:

              g_autofree uint8_t *zero = g_new0(uint8_t, 4096);

> +                        uint64_t i;
> +                        for (i = file_size; i < mem_size; i += sizeof(zero)) {
> +                            res = address_space_write(
> +                                         as ? as : &address_space_memory,
> +                                         addr + i, MEMTXATTRS_UNSPECIFIED,
> +                                         zero, MIN(sizeof(zero), mem_size - i));
> +                            if (res != MEMTX_OK) {
> +                                goto fail;
> +                            }
> +                        }
> +                    }
>                  }
>              }
>  
>
Laurent Vivier April 14, 2021, 12:41 p.m. UTC | #2
Le 14/04/2021 à 14:16, Philippe Mathieu-Daudé a écrit :
> On 4/14/21 12:58 PM, Laurent Vivier wrote:
>> When the mem_size of the segment is bigger than the file_size,
>> and if this space doesn't overlap another segment, it needs
>> to be cleared.
>>
>> This bug is very similar to the one we had for linux-user,
>> 22d113b52f41 ("linux-user: Fix loading of BSS segments"),
>> where .bss section is encoded as an extension of the the data
>> one by setting the segment p_memsz > p_filesz.
>>
>> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
>> ---
>>  include/hw/elf_ops.h | 17 +++++++++++++++++
>>  1 file changed, 17 insertions(+)
>>
>> diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
>> index 6ee458e7bc3c..e3dcee3ee349 100644
>> --- a/include/hw/elf_ops.h
>> +++ b/include/hw/elf_ops.h
>> @@ -562,6 +562,23 @@ static int glue(load_elf, SZ)(const char *name, int fd,
>>                      if (res != MEMTX_OK) {
>>                          goto fail;
>>                      }
>> +                    /*
>> +                     * We need to zero'ify the space that is not copied
>> +                     * from file
>> +                     */
>> +                    if (file_size < mem_size) {
>> +                        static uint8_t zero[4096];
> 
> Given it is unlikely, maybe better use:
> 
>               g_autofree uint8_t *zero = g_new0(uint8_t, 4096);
> 
>

I don't know what is the best solution but this seems to introduce a lot of complexity only to have
a page of 0s.

Thanks,
Laurent
Philippe Mathieu-Daudé April 15, 2021, 8:44 a.m. UTC | #3
On 4/14/21 2:41 PM, Laurent Vivier wrote:
> Le 14/04/2021 à 14:16, Philippe Mathieu-Daudé a écrit :
>> On 4/14/21 12:58 PM, Laurent Vivier wrote:
>>> When the mem_size of the segment is bigger than the file_size,
>>> and if this space doesn't overlap another segment, it needs
>>> to be cleared.
>>>
>>> This bug is very similar to the one we had for linux-user,
>>> 22d113b52f41 ("linux-user: Fix loading of BSS segments"),
>>> where .bss section is encoded as an extension of the the data
>>> one by setting the segment p_memsz > p_filesz.
>>>
>>> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
>>> ---
>>>  include/hw/elf_ops.h | 17 +++++++++++++++++
>>>  1 file changed, 17 insertions(+)
>>>
>>> diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
>>> index 6ee458e7bc3c..e3dcee3ee349 100644
>>> --- a/include/hw/elf_ops.h
>>> +++ b/include/hw/elf_ops.h
>>> @@ -562,6 +562,23 @@ static int glue(load_elf, SZ)(const char *name, int fd,
>>>                      if (res != MEMTX_OK) {
>>>                          goto fail;
>>>                      }
>>> +                    /*
>>> +                     * We need to zero'ify the space that is not copied
>>> +                     * from file
>>> +                     */
>>> +                    if (file_size < mem_size) {
>>> +                        static uint8_t zero[4096];
>>
>> Given it is unlikely, maybe better use:
>>
>>               g_autofree uint8_t *zero = g_new0(uint8_t, 4096);
> 
> I don't know what is the best solution but this seems to introduce a lot of complexity only to have
> a page of 0s.

Less complex alternative is to use dma_memory_set():

   dma_memory_set(as, file_size, 0, mem_size - file_size);

Actually we should extract address_space_set() from it, keeping
the dma_barrier() call in dma_memory_set(), and use address_space_set()
here.

What do you think?

Phil.
Philippe Mathieu-Daudé April 15, 2021, 9:57 a.m. UTC | #4
On 4/15/21 10:44 AM, Philippe Mathieu-Daudé wrote:
> On 4/14/21 2:41 PM, Laurent Vivier wrote:
>> Le 14/04/2021 à 14:16, Philippe Mathieu-Daudé a écrit :
>>> On 4/14/21 12:58 PM, Laurent Vivier wrote:
>>>> When the mem_size of the segment is bigger than the file_size,
>>>> and if this space doesn't overlap another segment, it needs
>>>> to be cleared.
>>>>
>>>> This bug is very similar to the one we had for linux-user,
>>>> 22d113b52f41 ("linux-user: Fix loading of BSS segments"),
>>>> where .bss section is encoded as an extension of the the data
>>>> one by setting the segment p_memsz > p_filesz.
>>>>
>>>> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
>>>> ---
>>>>  include/hw/elf_ops.h | 17 +++++++++++++++++
>>>>  1 file changed, 17 insertions(+)
>>>>
>>>> diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
>>>> index 6ee458e7bc3c..e3dcee3ee349 100644
>>>> --- a/include/hw/elf_ops.h
>>>> +++ b/include/hw/elf_ops.h
>>>> @@ -562,6 +562,23 @@ static int glue(load_elf, SZ)(const char *name, int fd,
>>>>                      if (res != MEMTX_OK) {
>>>>                          goto fail;
>>>>                      }
>>>> +                    /*
>>>> +                     * We need to zero'ify the space that is not copied
>>>> +                     * from file
>>>> +                     */
>>>> +                    if (file_size < mem_size) {
>>>> +                        static uint8_t zero[4096];
>>>
>>> Given it is unlikely, maybe better use:
>>>
>>>               g_autofree uint8_t *zero = g_new0(uint8_t, 4096);
>>
>> I don't know what is the best solution but this seems to introduce a lot of complexity only to have
>> a page of 0s.
> 
> Less complex alternative is to use dma_memory_set():
> 
>    dma_memory_set(as, file_size, 0, mem_size - file_size);
> 
> Actually we should extract address_space_set() from it, keeping
> the dma_barrier() call in dma_memory_set(), and use address_space_set()
> here.
> 
> What do you think?

I'll post a patch.
diff mbox series

Patch

diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index 6ee458e7bc3c..e3dcee3ee349 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -562,6 +562,23 @@  static int glue(load_elf, SZ)(const char *name, int fd,
                     if (res != MEMTX_OK) {
                         goto fail;
                     }
+                    /*
+                     * We need to zero'ify the space that is not copied
+                     * from file
+                     */
+                    if (file_size < mem_size) {
+                        static uint8_t zero[4096];
+                        uint64_t i;
+                        for (i = file_size; i < mem_size; i += sizeof(zero)) {
+                            res = address_space_write(
+                                         as ? as : &address_space_memory,
+                                         addr + i, MEMTXATTRS_UNSPECIFIED,
+                                         zero, MIN(sizeof(zero), mem_size - i));
+                            if (res != MEMTX_OK) {
+                                goto fail;
+                            }
+                        }
+                    }
                 }
             }