diff mbox series

[v2,2/2] livepatch: refuse to resolve symbols that belong to init sections

Message ID 20240419100217.12072-3-roger.pau@citrix.com (mailing list archive)
State New
Headers show
Series livepatch: make symbol resolution more robust | expand

Commit Message

Roger Pau Monné April 19, 2024, 10:02 a.m. UTC
Livepatch payloads containing symbols that belong to init sections can only
lead to page faults later on, as by the time the livepatch is loaded init
sections have already been freed.

Refuse to resolve such symbols and return an error instead.

Note such resolutions are only relevant for symbols that point to undefined
sections (SHN_UNDEF), as that implies the symbol is not in the current payload
and hence must either be a Xen or a different livepatch payload symbol.

Do not allow to resolve symbols that point to __init_begin, as that address is
also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
resolutions against it.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v1:
 - Fix off-by-one in range checking.
---
 xen/common/livepatch_elf.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Andrew Cooper April 19, 2024, 10:10 a.m. UTC | #1
On 19/04/2024 11:02 am, Roger Pau Monne wrote:
> Livepatch payloads containing symbols that belong to init sections can only
> lead to page faults later on, as by the time the livepatch is loaded init
> sections have already been freed.
>
> Refuse to resolve such symbols and return an error instead.
>
> Note such resolutions are only relevant for symbols that point to undefined
> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
> and hence must either be a Xen or a different livepatch payload symbol.
>
> Do not allow to resolve symbols that point to __init_begin, as that address is
> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
> resolutions against it.
>
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>, although ...

> ---
> Changes since v1:
>  - Fix off-by-one in range checking.
> ---
>  xen/common/livepatch_elf.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/xen/common/livepatch_elf.c b/xen/common/livepatch_elf.c
> index 45d73912a3cd..a67101eadc02 100644
> --- a/xen/common/livepatch_elf.c
> +++ b/xen/common/livepatch_elf.c
> @@ -4,6 +4,7 @@
>  
>  #include <xen/errno.h>
>  #include <xen/lib.h>
> +#include <xen/sections.h>
>  #include <xen/symbols.h>
>  #include <xen/livepatch_elf.h>
>  #include <xen/livepatch.h>
> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
>                      break;
>                  }
>              }
> +
> +            /*
> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
> +             * livepatch payloads don't have init sections or equivalent.
> +             */
> +            else if ( st_value >= (uintptr_t)&__init_begin &&
> +                      st_value < (uintptr_t)&__init_end )

... I normally vertically the (casts) in cases like this for improved
legibility.  Happy to fold on commit.

~Andrew
Jan Beulich April 19, 2024, 10:15 a.m. UTC | #2
On 19.04.2024 12:02, Roger Pau Monne wrote:
> Livepatch payloads containing symbols that belong to init sections can only
> lead to page faults later on, as by the time the livepatch is loaded init
> sections have already been freed.
> 
> Refuse to resolve such symbols and return an error instead.
> 
> Note such resolutions are only relevant for symbols that point to undefined
> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
> and hence must either be a Xen or a different livepatch payload symbol.
> 
> Do not allow to resolve symbols that point to __init_begin, as that address is
> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
> resolutions against it.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> ---
> Changes since v1:
>  - Fix off-by-one in range checking.

Which means you addressed Andrew's comment while at the same time extending
the scope of ...

> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
>                      break;
>                  }
>              }
> +
> +            /*
> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
> +             * livepatch payloads don't have init sections or equivalent.
> +             */
> +            else if ( st_value >= (uintptr_t)&__init_begin &&
> +                      st_value < (uintptr_t)&__init_end )
> +            {
> +                printk(XENLOG_ERR LIVEPATCH
> +                       "%s: symbol %s is in init section, not resolving\n",
> +                       elf->name, elf->sym[i].name);

... what I raised concern about (and I had not seen any verbal reply to that,
I don't think).

Jan
Roger Pau Monné April 19, 2024, 10:48 a.m. UTC | #3
On Fri, Apr 19, 2024 at 11:10:33AM +0100, Andrew Cooper wrote:
> On 19/04/2024 11:02 am, Roger Pau Monne wrote:
> > Livepatch payloads containing symbols that belong to init sections can only
> > lead to page faults later on, as by the time the livepatch is loaded init
> > sections have already been freed.
> >
> > Refuse to resolve such symbols and return an error instead.
> >
> > Note such resolutions are only relevant for symbols that point to undefined
> > sections (SHN_UNDEF), as that implies the symbol is not in the current payload
> > and hence must either be a Xen or a different livepatch payload symbol.
> >
> > Do not allow to resolve symbols that point to __init_begin, as that address is
> > also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
> > resolutions against it.
> >
> > Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> 
> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>, although ...
> 
> > ---
> > Changes since v1:
> >  - Fix off-by-one in range checking.
> > ---
> >  xen/common/livepatch_elf.c | 16 ++++++++++++++++
> >  1 file changed, 16 insertions(+)
> >
> > diff --git a/xen/common/livepatch_elf.c b/xen/common/livepatch_elf.c
> > index 45d73912a3cd..a67101eadc02 100644
> > --- a/xen/common/livepatch_elf.c
> > +++ b/xen/common/livepatch_elf.c
> > @@ -4,6 +4,7 @@
> >  
> >  #include <xen/errno.h>
> >  #include <xen/lib.h>
> > +#include <xen/sections.h>
> >  #include <xen/symbols.h>
> >  #include <xen/livepatch_elf.h>
> >  #include <xen/livepatch.h>
> > @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
> >                      break;
> >                  }
> >              }
> > +
> > +            /*
> > +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
> > +             * livepatch payloads don't have init sections or equivalent.
> > +             */
> > +            else if ( st_value >= (uintptr_t)&__init_begin &&
> > +                      st_value < (uintptr_t)&__init_end )
> 
> ... I normally vertically the (casts) in cases like this for improved
> legibility.  Happy to fold on commit.

Did this, but reverted afterwards because I wasn't sure whether it
would go against the coding style.  Aligning would be my preference
also.

Thanks, Roger.
Roger Pau Monné April 19, 2024, 10:50 a.m. UTC | #4
On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
> On 19.04.2024 12:02, Roger Pau Monne wrote:
> > Livepatch payloads containing symbols that belong to init sections can only
> > lead to page faults later on, as by the time the livepatch is loaded init
> > sections have already been freed.
> > 
> > Refuse to resolve such symbols and return an error instead.
> > 
> > Note such resolutions are only relevant for symbols that point to undefined
> > sections (SHN_UNDEF), as that implies the symbol is not in the current payload
> > and hence must either be a Xen or a different livepatch payload symbol.
> > 
> > Do not allow to resolve symbols that point to __init_begin, as that address is
> > also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
> > resolutions against it.
> > 
> > Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> > ---
> > Changes since v1:
> >  - Fix off-by-one in range checking.
> 
> Which means you addressed Andrew's comment while at the same time extending
> the scope of ...
> 
> > @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
> >                      break;
> >                  }
> >              }
> > +
> > +            /*
> > +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
> > +             * livepatch payloads don't have init sections or equivalent.
> > +             */
> > +            else if ( st_value >= (uintptr_t)&__init_begin &&
> > +                      st_value < (uintptr_t)&__init_end )
> > +            {
> > +                printk(XENLOG_ERR LIVEPATCH
> > +                       "%s: symbol %s is in init section, not resolving\n",
> > +                       elf->name, elf->sym[i].name);
> 
> ... what I raised concern about (and I had not seen any verbal reply to that,
> I don't think).

I've extended the commit message to explicitly mention the handling of
bounds for __init_{begin,end} checks.  Let me know if you are not fine
with it (or maybe you expected something else?).

Thanks, Roger.
Jan Beulich April 19, 2024, 2:34 p.m. UTC | #5
On 19.04.2024 12:50, Roger Pau Monné wrote:
> On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
>> On 19.04.2024 12:02, Roger Pau Monne wrote:
>>> Livepatch payloads containing symbols that belong to init sections can only
>>> lead to page faults later on, as by the time the livepatch is loaded init
>>> sections have already been freed.
>>>
>>> Refuse to resolve such symbols and return an error instead.
>>>
>>> Note such resolutions are only relevant for symbols that point to undefined
>>> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
>>> and hence must either be a Xen or a different livepatch payload symbol.
>>>
>>> Do not allow to resolve symbols that point to __init_begin, as that address is
>>> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
>>> resolutions against it.
>>>
>>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
>>> ---
>>> Changes since v1:
>>>  - Fix off-by-one in range checking.
>>
>> Which means you addressed Andrew's comment while at the same time extending
>> the scope of ...
>>
>>> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
>>>                      break;
>>>                  }
>>>              }
>>> +
>>> +            /*
>>> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
>>> +             * livepatch payloads don't have init sections or equivalent.
>>> +             */
>>> +            else if ( st_value >= (uintptr_t)&__init_begin &&
>>> +                      st_value < (uintptr_t)&__init_end )
>>> +            {
>>> +                printk(XENLOG_ERR LIVEPATCH
>>> +                       "%s: symbol %s is in init section, not resolving\n",
>>> +                       elf->name, elf->sym[i].name);
>>
>> ... what I raised concern about (and I had not seen any verbal reply to that,
>> I don't think).
> 
> I've extended the commit message to explicitly mention the handling of
> bounds for __init_{begin,end} checks.  Let me know if you are not fine
> with it (or maybe you expected something else?).

Well, you mention the two symbols you care about, but you don't mention
at all that these two may alias other symbols which might be legal to
reference from a livepatch.

Jan
Roger Pau Monné April 22, 2024, 7:54 a.m. UTC | #6
On Fri, Apr 19, 2024 at 04:34:41PM +0200, Jan Beulich wrote:
> On 19.04.2024 12:50, Roger Pau Monné wrote:
> > On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
> >> On 19.04.2024 12:02, Roger Pau Monne wrote:
> >>> Livepatch payloads containing symbols that belong to init sections can only
> >>> lead to page faults later on, as by the time the livepatch is loaded init
> >>> sections have already been freed.
> >>>
> >>> Refuse to resolve such symbols and return an error instead.
> >>>
> >>> Note such resolutions are only relevant for symbols that point to undefined
> >>> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
> >>> and hence must either be a Xen or a different livepatch payload symbol.
> >>>
> >>> Do not allow to resolve symbols that point to __init_begin, as that address is
> >>> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
> >>> resolutions against it.
> >>>
> >>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> >>> ---
> >>> Changes since v1:
> >>>  - Fix off-by-one in range checking.
> >>
> >> Which means you addressed Andrew's comment while at the same time extending
> >> the scope of ...
> >>
> >>> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
> >>>                      break;
> >>>                  }
> >>>              }
> >>> +
> >>> +            /*
> >>> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
> >>> +             * livepatch payloads don't have init sections or equivalent.
> >>> +             */
> >>> +            else if ( st_value >= (uintptr_t)&__init_begin &&
> >>> +                      st_value < (uintptr_t)&__init_end )
> >>> +            {
> >>> +                printk(XENLOG_ERR LIVEPATCH
> >>> +                       "%s: symbol %s is in init section, not resolving\n",
> >>> +                       elf->name, elf->sym[i].name);
> >>
> >> ... what I raised concern about (and I had not seen any verbal reply to that,
> >> I don't think).
> > 
> > I've extended the commit message to explicitly mention the handling of
> > bounds for __init_{begin,end} checks.  Let me know if you are not fine
> > with it (or maybe you expected something else?).
> 
> Well, you mention the two symbols you care about, but you don't mention
> at all that these two may alias other symbols which might be legal to
> reference from a livepatch.

I'm having a hard time understanding why a livepatch would want to
reference those, or any symbol in the .init sections for that matter.
__init_{begin,end} are exclusively used to unmap the init region after
boot.  What's the point in livepatch referencing data that's no
longer there?  The only application I would think of is to calculate
some kind of offsets, but that would better be done using other
symbols instead.

Please bear with me, it would be easier for me to understand if you
could provide a concrete example.

Thanks, Roger.
Jan Beulich April 22, 2024, 8:25 a.m. UTC | #7
On 22.04.2024 09:54, Roger Pau Monné wrote:
> On Fri, Apr 19, 2024 at 04:34:41PM +0200, Jan Beulich wrote:
>> On 19.04.2024 12:50, Roger Pau Monné wrote:
>>> On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
>>>> On 19.04.2024 12:02, Roger Pau Monne wrote:
>>>>> Livepatch payloads containing symbols that belong to init sections can only
>>>>> lead to page faults later on, as by the time the livepatch is loaded init
>>>>> sections have already been freed.
>>>>>
>>>>> Refuse to resolve such symbols and return an error instead.
>>>>>
>>>>> Note such resolutions are only relevant for symbols that point to undefined
>>>>> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
>>>>> and hence must either be a Xen or a different livepatch payload symbol.
>>>>>
>>>>> Do not allow to resolve symbols that point to __init_begin, as that address is
>>>>> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
>>>>> resolutions against it.
>>>>>
>>>>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
>>>>> ---
>>>>> Changes since v1:
>>>>>  - Fix off-by-one in range checking.
>>>>
>>>> Which means you addressed Andrew's comment while at the same time extending
>>>> the scope of ...
>>>>
>>>>> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
>>>>>                      break;
>>>>>                  }
>>>>>              }
>>>>> +
>>>>> +            /*
>>>>> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
>>>>> +             * livepatch payloads don't have init sections or equivalent.
>>>>> +             */
>>>>> +            else if ( st_value >= (uintptr_t)&__init_begin &&
>>>>> +                      st_value < (uintptr_t)&__init_end )
>>>>> +            {
>>>>> +                printk(XENLOG_ERR LIVEPATCH
>>>>> +                       "%s: symbol %s is in init section, not resolving\n",
>>>>> +                       elf->name, elf->sym[i].name);
>>>>
>>>> ... what I raised concern about (and I had not seen any verbal reply to that,
>>>> I don't think).
>>>
>>> I've extended the commit message to explicitly mention the handling of
>>> bounds for __init_{begin,end} checks.  Let me know if you are not fine
>>> with it (or maybe you expected something else?).
>>
>> Well, you mention the two symbols you care about, but you don't mention
>> at all that these two may alias other symbols which might be legal to
>> reference from a livepatch.
> 
> I'm having a hard time understanding why a livepatch would want to
> reference those, or any symbol in the .init sections for that matter.
> __init_{begin,end} are exclusively used to unmap the init region after
> boot.  What's the point in livepatch referencing data that's no
> longer there?  The only application I would think of is to calculate
> some kind of offsets, but that would better be done using other
> symbols instead.
> 
> Please bear with me, it would be easier for me to understand if you
> could provide a concrete example.

The issue is that you do comparison by address, not by name. Let's assume
that .rodata ends exactly where .init.* starts. Then &__init_begin ==
&_erodata == &__2M_rodata_end. Access to the latter two symbols wants to
be permitted; only __init_begin and whatever ends up being the very first
symbol in .init.* ought to not be referenced.

Worse (but contrived) would be cases of "constructed" symbols derived from
ones ahead of __init_begin, with an offset large enough to actually point
into .init.*. Such are _still_ valid to be used in calculations, as long
as no deref occurs for anything at or past __init_begin.

Jan
Roger Pau Monné April 22, 2024, 10:49 a.m. UTC | #8
On Mon, Apr 22, 2024 at 10:25:40AM +0200, Jan Beulich wrote:
> On 22.04.2024 09:54, Roger Pau Monné wrote:
> > On Fri, Apr 19, 2024 at 04:34:41PM +0200, Jan Beulich wrote:
> >> On 19.04.2024 12:50, Roger Pau Monné wrote:
> >>> On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
> >>>> On 19.04.2024 12:02, Roger Pau Monne wrote:
> >>>>> Livepatch payloads containing symbols that belong to init sections can only
> >>>>> lead to page faults later on, as by the time the livepatch is loaded init
> >>>>> sections have already been freed.
> >>>>>
> >>>>> Refuse to resolve such symbols and return an error instead.
> >>>>>
> >>>>> Note such resolutions are only relevant for symbols that point to undefined
> >>>>> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
> >>>>> and hence must either be a Xen or a different livepatch payload symbol.
> >>>>>
> >>>>> Do not allow to resolve symbols that point to __init_begin, as that address is
> >>>>> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
> >>>>> resolutions against it.
> >>>>>
> >>>>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> >>>>> ---
> >>>>> Changes since v1:
> >>>>>  - Fix off-by-one in range checking.
> >>>>
> >>>> Which means you addressed Andrew's comment while at the same time extending
> >>>> the scope of ...
> >>>>
> >>>>> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
> >>>>>                      break;
> >>>>>                  }
> >>>>>              }
> >>>>> +
> >>>>> +            /*
> >>>>> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
> >>>>> +             * livepatch payloads don't have init sections or equivalent.
> >>>>> +             */
> >>>>> +            else if ( st_value >= (uintptr_t)&__init_begin &&
> >>>>> +                      st_value < (uintptr_t)&__init_end )
> >>>>> +            {
> >>>>> +                printk(XENLOG_ERR LIVEPATCH
> >>>>> +                       "%s: symbol %s is in init section, not resolving\n",
> >>>>> +                       elf->name, elf->sym[i].name);
> >>>>
> >>>> ... what I raised concern about (and I had not seen any verbal reply to that,
> >>>> I don't think).
> >>>
> >>> I've extended the commit message to explicitly mention the handling of
> >>> bounds for __init_{begin,end} checks.  Let me know if you are not fine
> >>> with it (or maybe you expected something else?).
> >>
> >> Well, you mention the two symbols you care about, but you don't mention
> >> at all that these two may alias other symbols which might be legal to
> >> reference from a livepatch.
> > 
> > I'm having a hard time understanding why a livepatch would want to
> > reference those, or any symbol in the .init sections for that matter.
> > __init_{begin,end} are exclusively used to unmap the init region after
> > boot.  What's the point in livepatch referencing data that's no
> > longer there?  The only application I would think of is to calculate
> > some kind of offsets, but that would better be done using other
> > symbols instead.
> > 
> > Please bear with me, it would be easier for me to understand if you
> > could provide a concrete example.
> 
> The issue is that you do comparison by address, not by name. Let's assume
> that .rodata ends exactly where .init.* starts. Then &__init_begin ==
> &_erodata == &__2M_rodata_end. Access to the latter two symbols wants to
> be permitted; only __init_begin and whatever ends up being the very first
> symbol in .init.* ought to not be referenced.

Hm, I guess I could add comparison by name additionally, but it looks
fragile to me.

So when st_value == __init_begin check if the name matches
"__init_begin" or "__2M_init_start" or "_sinittext", and fail
resolution, otherwise allow it?

> Worse (but contrived) would be cases of "constructed" symbols derived from
> ones ahead of __init_begin, with an offset large enough to actually point
> into .init.*. Such are _still_ valid to be used in calculations, as long
> as no deref occurs for anything at or past __init_begin.

But one would have to craft such a symbol specifically, at which point
I consider this out of the scope of what this patch is attempting to
protect against.  The aim is not to prevent malicious livepatches, and
there are far easier ways to trigger a page-fault from a livepatch.

Thanks, Roger.
Jan Beulich April 22, 2024, 10:57 a.m. UTC | #9
On 22.04.2024 12:49, Roger Pau Monné wrote:
> On Mon, Apr 22, 2024 at 10:25:40AM +0200, Jan Beulich wrote:
>> On 22.04.2024 09:54, Roger Pau Monné wrote:
>>> On Fri, Apr 19, 2024 at 04:34:41PM +0200, Jan Beulich wrote:
>>>> On 19.04.2024 12:50, Roger Pau Monné wrote:
>>>>> On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
>>>>>> On 19.04.2024 12:02, Roger Pau Monne wrote:
>>>>>>> Livepatch payloads containing symbols that belong to init sections can only
>>>>>>> lead to page faults later on, as by the time the livepatch is loaded init
>>>>>>> sections have already been freed.
>>>>>>>
>>>>>>> Refuse to resolve such symbols and return an error instead.
>>>>>>>
>>>>>>> Note such resolutions are only relevant for symbols that point to undefined
>>>>>>> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
>>>>>>> and hence must either be a Xen or a different livepatch payload symbol.
>>>>>>>
>>>>>>> Do not allow to resolve symbols that point to __init_begin, as that address is
>>>>>>> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
>>>>>>> resolutions against it.
>>>>>>>
>>>>>>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
>>>>>>> ---
>>>>>>> Changes since v1:
>>>>>>>  - Fix off-by-one in range checking.
>>>>>>
>>>>>> Which means you addressed Andrew's comment while at the same time extending
>>>>>> the scope of ...
>>>>>>
>>>>>>> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
>>>>>>>                      break;
>>>>>>>                  }
>>>>>>>              }
>>>>>>> +
>>>>>>> +            /*
>>>>>>> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
>>>>>>> +             * livepatch payloads don't have init sections or equivalent.
>>>>>>> +             */
>>>>>>> +            else if ( st_value >= (uintptr_t)&__init_begin &&
>>>>>>> +                      st_value < (uintptr_t)&__init_end )
>>>>>>> +            {
>>>>>>> +                printk(XENLOG_ERR LIVEPATCH
>>>>>>> +                       "%s: symbol %s is in init section, not resolving\n",
>>>>>>> +                       elf->name, elf->sym[i].name);
>>>>>>
>>>>>> ... what I raised concern about (and I had not seen any verbal reply to that,
>>>>>> I don't think).
>>>>>
>>>>> I've extended the commit message to explicitly mention the handling of
>>>>> bounds for __init_{begin,end} checks.  Let me know if you are not fine
>>>>> with it (or maybe you expected something else?).
>>>>
>>>> Well, you mention the two symbols you care about, but you don't mention
>>>> at all that these two may alias other symbols which might be legal to
>>>> reference from a livepatch.
>>>
>>> I'm having a hard time understanding why a livepatch would want to
>>> reference those, or any symbol in the .init sections for that matter.
>>> __init_{begin,end} are exclusively used to unmap the init region after
>>> boot.  What's the point in livepatch referencing data that's no
>>> longer there?  The only application I would think of is to calculate
>>> some kind of offsets, but that would better be done using other
>>> symbols instead.
>>>
>>> Please bear with me, it would be easier for me to understand if you
>>> could provide a concrete example.
>>
>> The issue is that you do comparison by address, not by name. Let's assume
>> that .rodata ends exactly where .init.* starts. Then &__init_begin ==
>> &_erodata == &__2M_rodata_end. Access to the latter two symbols wants to
>> be permitted; only __init_begin and whatever ends up being the very first
>> symbol in .init.* ought to not be referenced.
> 
> Hm, I guess I could add comparison by name additionally, but it looks
> fragile to me.

It looks fragile, yes. Thing is that you're trying to deal with this when
crucial information was lost already. Or wait - isn't the section number
still available in ->st_shndx?

> So when st_value == __init_begin check if the name matches
> "__init_begin" or "__2M_init_start" or "_sinittext", and fail
> resolution, otherwise allow it?

Kind of, but that's not enough. For one, as said, the first symbol in
the first .init.* section would also have this same address, and would
also want rejecting. And then the same would be needed for __init_end.

>> Worse (but contrived) would be cases of "constructed" symbols derived from
>> ones ahead of __init_begin, with an offset large enough to actually point
>> into .init.*. Such are _still_ valid to be used in calculations, as long
>> as no deref occurs for anything at or past __init_begin.
> 
> But one would have to craft such a symbol specifically, at which point
> I consider this out of the scope of what this patch is attempting to
> protect against.  The aim is not to prevent malicious livepatches, and
> there are far easier ways to trigger a page-fault from a livepatch.

I understand the latter is the case, but I'm afraid I then don't see what
the goal of this change is.

Jan
Roger Pau Monné April 22, 2024, 11:34 a.m. UTC | #10
On Mon, Apr 22, 2024 at 12:57:55PM +0200, Jan Beulich wrote:
> On 22.04.2024 12:49, Roger Pau Monné wrote:
> > On Mon, Apr 22, 2024 at 10:25:40AM +0200, Jan Beulich wrote:
> >> On 22.04.2024 09:54, Roger Pau Monné wrote:
> >>> On Fri, Apr 19, 2024 at 04:34:41PM +0200, Jan Beulich wrote:
> >>>> On 19.04.2024 12:50, Roger Pau Monné wrote:
> >>>>> On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
> >>>>>> On 19.04.2024 12:02, Roger Pau Monne wrote:
> >>>>>>> Livepatch payloads containing symbols that belong to init sections can only
> >>>>>>> lead to page faults later on, as by the time the livepatch is loaded init
> >>>>>>> sections have already been freed.
> >>>>>>>
> >>>>>>> Refuse to resolve such symbols and return an error instead.
> >>>>>>>
> >>>>>>> Note such resolutions are only relevant for symbols that point to undefined
> >>>>>>> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
> >>>>>>> and hence must either be a Xen or a different livepatch payload symbol.
> >>>>>>>
> >>>>>>> Do not allow to resolve symbols that point to __init_begin, as that address is
> >>>>>>> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
> >>>>>>> resolutions against it.
> >>>>>>>
> >>>>>>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> >>>>>>> ---
> >>>>>>> Changes since v1:
> >>>>>>>  - Fix off-by-one in range checking.
> >>>>>>
> >>>>>> Which means you addressed Andrew's comment while at the same time extending
> >>>>>> the scope of ...
> >>>>>>
> >>>>>>> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
> >>>>>>>                      break;
> >>>>>>>                  }
> >>>>>>>              }
> >>>>>>> +
> >>>>>>> +            /*
> >>>>>>> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
> >>>>>>> +             * livepatch payloads don't have init sections or equivalent.
> >>>>>>> +             */
> >>>>>>> +            else if ( st_value >= (uintptr_t)&__init_begin &&
> >>>>>>> +                      st_value < (uintptr_t)&__init_end )
> >>>>>>> +            {
> >>>>>>> +                printk(XENLOG_ERR LIVEPATCH
> >>>>>>> +                       "%s: symbol %s is in init section, not resolving\n",
> >>>>>>> +                       elf->name, elf->sym[i].name);
> >>>>>>
> >>>>>> ... what I raised concern about (and I had not seen any verbal reply to that,
> >>>>>> I don't think).
> >>>>>
> >>>>> I've extended the commit message to explicitly mention the handling of
> >>>>> bounds for __init_{begin,end} checks.  Let me know if you are not fine
> >>>>> with it (or maybe you expected something else?).
> >>>>
> >>>> Well, you mention the two symbols you care about, but you don't mention
> >>>> at all that these two may alias other symbols which might be legal to
> >>>> reference from a livepatch.
> >>>
> >>> I'm having a hard time understanding why a livepatch would want to
> >>> reference those, or any symbol in the .init sections for that matter.
> >>> __init_{begin,end} are exclusively used to unmap the init region after
> >>> boot.  What's the point in livepatch referencing data that's no
> >>> longer there?  The only application I would think of is to calculate
> >>> some kind of offsets, but that would better be done using other
> >>> symbols instead.
> >>>
> >>> Please bear with me, it would be easier for me to understand if you
> >>> could provide a concrete example.
> >>
> >> The issue is that you do comparison by address, not by name. Let's assume
> >> that .rodata ends exactly where .init.* starts. Then &__init_begin ==
> >> &_erodata == &__2M_rodata_end. Access to the latter two symbols wants to
> >> be permitted; only __init_begin and whatever ends up being the very first
> >> symbol in .init.* ought to not be referenced.
> > 
> > Hm, I guess I could add comparison by name additionally, but it looks
> > fragile to me.
> 
> It looks fragile, yes. Thing is that you're trying to deal with this when
> crucial information was lost already. Or wait - isn't the section number
> still available in ->st_shndx?

But that's the section number of the to be resolved symbol?  In the
livepatch payload it would for example appear as:

0000000000000000       F *UND*	0000000000000000 .hidden setup_boot_APIC_clock

With undefined section.

It's possible I'm not following, is there a way to get the section
number of the current Xen symbols, and then correlate it with the
.init section?

Overall, I think it's unlikely for a livepatch to care about the
section start/end markers, albeit it would be good if we could make
this less ambiguous.

> 
> > So when st_value == __init_begin check if the name matches
> > "__init_begin" or "__2M_init_start" or "_sinittext", and fail
> > resolution, otherwise allow it?
> 
> Kind of, but that's not enough. For one, as said, the first symbol in
> the first .init.* section would also have this same address, and would
> also want rejecting. And then the same would be needed for __init_end.
> 
> >> Worse (but contrived) would be cases of "constructed" symbols derived from
> >> ones ahead of __init_begin, with an offset large enough to actually point
> >> into .init.*. Such are _still_ valid to be used in calculations, as long
> >> as no deref occurs for anything at or past __init_begin.
> > 
> > But one would have to craft such a symbol specifically, at which point
> > I consider this out of the scope of what this patch is attempting to
> > protect against.  The aim is not to prevent malicious livepatches, and
> > there are far easier ways to trigger a page-fault from a livepatch.
> 
> I understand the latter is the case, but I'm afraid I then don't see what
> the goal of this change is.

The goal would be for something like what caused:

https://xenbits.xen.org/gitweb/?p=xen.git;a=commit;h=af4cd0a6a61cdb03bc1afca9478b05b0c9703599

To be rejected at load time instead of causing a page-fault during
alternative patching, because xsm_ops was (wrongly) an .init symbol.

Thanks, Roger.
Jan Beulich April 22, 2024, 11:51 a.m. UTC | #11
On 22.04.2024 13:34, Roger Pau Monné wrote:
> On Mon, Apr 22, 2024 at 12:57:55PM +0200, Jan Beulich wrote:
>> On 22.04.2024 12:49, Roger Pau Monné wrote:
>>> On Mon, Apr 22, 2024 at 10:25:40AM +0200, Jan Beulich wrote:
>>>> On 22.04.2024 09:54, Roger Pau Monné wrote:
>>>>> On Fri, Apr 19, 2024 at 04:34:41PM +0200, Jan Beulich wrote:
>>>>>> On 19.04.2024 12:50, Roger Pau Monné wrote:
>>>>>>> On Fri, Apr 19, 2024 at 12:15:19PM +0200, Jan Beulich wrote:
>>>>>>>> On 19.04.2024 12:02, Roger Pau Monne wrote:
>>>>>>>>> Livepatch payloads containing symbols that belong to init sections can only
>>>>>>>>> lead to page faults later on, as by the time the livepatch is loaded init
>>>>>>>>> sections have already been freed.
>>>>>>>>>
>>>>>>>>> Refuse to resolve such symbols and return an error instead.
>>>>>>>>>
>>>>>>>>> Note such resolutions are only relevant for symbols that point to undefined
>>>>>>>>> sections (SHN_UNDEF), as that implies the symbol is not in the current payload
>>>>>>>>> and hence must either be a Xen or a different livepatch payload symbol.
>>>>>>>>>
>>>>>>>>> Do not allow to resolve symbols that point to __init_begin, as that address is
>>>>>>>>> also unmapped.  On the other hand, __init_end is not unmapped, and hence allow
>>>>>>>>> resolutions against it.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
>>>>>>>>> ---
>>>>>>>>> Changes since v1:
>>>>>>>>>  - Fix off-by-one in range checking.
>>>>>>>>
>>>>>>>> Which means you addressed Andrew's comment while at the same time extending
>>>>>>>> the scope of ...
>>>>>>>>
>>>>>>>>> @@ -310,6 +311,21 @@ int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
>>>>>>>>>                      break;
>>>>>>>>>                  }
>>>>>>>>>              }
>>>>>>>>> +
>>>>>>>>> +            /*
>>>>>>>>> +             * Ensure not an init symbol.  Only applicable to Xen symbols, as
>>>>>>>>> +             * livepatch payloads don't have init sections or equivalent.
>>>>>>>>> +             */
>>>>>>>>> +            else if ( st_value >= (uintptr_t)&__init_begin &&
>>>>>>>>> +                      st_value < (uintptr_t)&__init_end )
>>>>>>>>> +            {
>>>>>>>>> +                printk(XENLOG_ERR LIVEPATCH
>>>>>>>>> +                       "%s: symbol %s is in init section, not resolving\n",
>>>>>>>>> +                       elf->name, elf->sym[i].name);
>>>>>>>>
>>>>>>>> ... what I raised concern about (and I had not seen any verbal reply to that,
>>>>>>>> I don't think).
>>>>>>>
>>>>>>> I've extended the commit message to explicitly mention the handling of
>>>>>>> bounds for __init_{begin,end} checks.  Let me know if you are not fine
>>>>>>> with it (or maybe you expected something else?).
>>>>>>
>>>>>> Well, you mention the two symbols you care about, but you don't mention
>>>>>> at all that these two may alias other symbols which might be legal to
>>>>>> reference from a livepatch.
>>>>>
>>>>> I'm having a hard time understanding why a livepatch would want to
>>>>> reference those, or any symbol in the .init sections for that matter.
>>>>> __init_{begin,end} are exclusively used to unmap the init region after
>>>>> boot.  What's the point in livepatch referencing data that's no
>>>>> longer there?  The only application I would think of is to calculate
>>>>> some kind of offsets, but that would better be done using other
>>>>> symbols instead.
>>>>>
>>>>> Please bear with me, it would be easier for me to understand if you
>>>>> could provide a concrete example.
>>>>
>>>> The issue is that you do comparison by address, not by name. Let's assume
>>>> that .rodata ends exactly where .init.* starts. Then &__init_begin ==
>>>> &_erodata == &__2M_rodata_end. Access to the latter two symbols wants to
>>>> be permitted; only __init_begin and whatever ends up being the very first
>>>> symbol in .init.* ought to not be referenced.
>>>
>>> Hm, I guess I could add comparison by name additionally, but it looks
>>> fragile to me.
>>
>> It looks fragile, yes. Thing is that you're trying to deal with this when
>> crucial information was lost already. Or wait - isn't the section number
>> still available in ->st_shndx?
> 
> But that's the section number of the to be resolved symbol?  In the
> livepatch payload it would for example appear as:
> 
> 0000000000000000       F *UND*	0000000000000000 .hidden setup_boot_APIC_clock
> 
> With undefined section.
> 
> It's possible I'm not following, is there a way to get the section
> number of the current Xen symbols, and then correlate it with the
> .init section?

Hmm, yes, looks like I was forgetting that livepatch resolves symbols
using kallsyms data, not Xen's ELF symbol table.

Jan
diff mbox series

Patch

diff --git a/xen/common/livepatch_elf.c b/xen/common/livepatch_elf.c
index 45d73912a3cd..a67101eadc02 100644
--- a/xen/common/livepatch_elf.c
+++ b/xen/common/livepatch_elf.c
@@ -4,6 +4,7 @@ 
 
 #include <xen/errno.h>
 #include <xen/lib.h>
+#include <xen/sections.h>
 #include <xen/symbols.h>
 #include <xen/livepatch_elf.h>
 #include <xen/livepatch.h>
@@ -310,6 +311,21 @@  int livepatch_elf_resolve_symbols(struct livepatch_elf *elf)
                     break;
                 }
             }
+
+            /*
+             * Ensure not an init symbol.  Only applicable to Xen symbols, as
+             * livepatch payloads don't have init sections or equivalent.
+             */
+            else if ( st_value >= (uintptr_t)&__init_begin &&
+                      st_value < (uintptr_t)&__init_end )
+            {
+                printk(XENLOG_ERR LIVEPATCH
+                       "%s: symbol %s is in init section, not resolving\n",
+                       elf->name, elf->sym[i].name);
+                rc = -ENXIO;
+                break;
+            }
+
             dprintk(XENLOG_DEBUG, LIVEPATCH "%s: Undefined symbol resolved: %s => %#"PRIxElfAddr"\n",
                     elf->name, elf->sym[i].name, st_value);
             break;