[00/12] x86/CET: The last 12 patches to enable Intel CET

Message ID 20180721142035.21059-1-hjl.tools@gmail.com
Headers show
Series
  • x86/CET: The last 12 patches to enable Intel CET
Related show

Message

H.J. Lu July 21, 2018, 2:20 p.m.
These are the last 12 patches to enable Intel CET.  Tested by

1. build-many-glibcs.py.
2. With --enable-cet and without --enable-cet for i686, x86-64 and x32
on non-CET x86-64 processors.
3. With --enable-cet for x86-64 and x32 on CET SDV using the CET kernel
from cet branch at:

https://github.com/yyu168/linux_cet/tree/cet

When the shadow stack (SHSTK) is enabled, makecontext needs to allocate
a new shadow stack to go with the new stack allocated by the caller.
setcontext and swapcontext must properly handle the corresponding shadow
stack when the stack is switched.  Add more tests for user context
functions to provide more coverage for the shadow stack support.

H.J. Lu (12):
  x86: Update vfork to pop shadow stack
  x86-64: Add endbr64 to tst-quadmod[12].S
  Add <bits/indirect-return.h>
  x86/CET: Extend arch_prctl syscall for CET control
  x86: Rename __glibc_reserved2 to ssp_base in tcbhead_t
  x86-64/CET: Extend ucontext_t to save shadow stack
  x86/CET: Add tests with legacy non-CET shared objects
  Add a test for swapcontext with a wrapper
  Add a test for multiple makecontext calls
  Add another test for setcontext
  Add a test for multiple setcontext calls
  Add tests for setcontext on the context from makecontext

 bits/indirect-return.h                        |  25 ++
 misc/sys/cdefs.h                              |   6 +
 stdlib/Makefile                               |   7 +-
 stdlib/tst-setcontext4.c                      | 217 ++++++++++++++++++
 stdlib/tst-setcontext5.c                      |  88 +++++++
 stdlib/tst-setcontext6.c                      |  76 ++++++
 stdlib/tst-setcontext7.c                      |  96 ++++++++
 stdlib/tst-setcontext8.c                      |  81 +++++++
 stdlib/tst-setcontext9.c                      | 100 ++++++++
 stdlib/tst-swapcontext1.c                     |  92 ++++++++
 stdlib/tst-swapcontext2.c                     | 108 +++++++++
 stdlib/ucontext.h                             |   6 +-
 string/tst-xbzero-opt.c                       |  10 +-
 sysdeps/i386/nptl/tcb-offsets.sym             |   1 +
 sysdeps/i386/nptl/tls.h                       |   3 +-
 sysdeps/unix/sysv/linux/Makefile              |   3 +-
 sysdeps/unix/sysv/linux/bits/prctl.h          |  21 ++
 sysdeps/unix/sysv/linux/i386/vfork.S          |  54 +++++
 sysdeps/unix/sysv/linux/sys/prctl.h           |   1 +
 sysdeps/unix/sysv/linux/x86/bits/prctl.h      |  48 ++++
 sysdeps/unix/sysv/linux/x86/cpu-features.c    |   7 +
 sysdeps/unix/sysv/linux/x86/dl-cet.h          |  29 ++-
 sysdeps/unix/sysv/linux/x86/sys/ucontext.h    |   2 +
 .../unix/sysv/linux/x86_64/__start_context.S  |  75 ++++++
 sysdeps/unix/sysv/linux/x86_64/getcontext.S   |  17 ++
 sysdeps/unix/sysv/linux/x86_64/makecontext.c  |  56 ++++-
 sysdeps/unix/sysv/linux/x86_64/setcontext.S   | 139 +++++++++++
 sysdeps/unix/sysv/linux/x86_64/swapcontext.S  | 150 ++++++++++++
 sysdeps/unix/sysv/linux/x86_64/sysdep.h       |   5 +
 sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym |   1 +
 sysdeps/unix/sysv/linux/x86_64/vfork.S        |  35 +++
 sysdeps/x86/Makefile                          |  38 +++
 sysdeps/x86/bits/indirect-return.h            |  35 +++
 sysdeps/x86/libc-start.c                      |   3 +
 sysdeps/x86/tst-cet-legacy-1.c                |  44 ++++
 sysdeps/x86/tst-cet-legacy-2.c                |  64 ++++++
 sysdeps/x86/tst-cet-legacy-2a.c               |   1 +
 sysdeps/x86/tst-cet-legacy-3.c                |  88 +++++++
 sysdeps/x86/tst-cet-legacy-4.c                |  56 +++++
 sysdeps/x86/tst-cet-legacy-4a.c               |   1 +
 sysdeps/x86/tst-cet-legacy-4b.c               |   1 +
 sysdeps/x86/tst-cet-legacy-4c.c               |   1 +
 sysdeps/x86/tst-cet-legacy-mod-1.c            |  24 ++
 sysdeps/x86/tst-cet-legacy-mod-2.c            |  24 ++
 sysdeps/x86/tst-cet-legacy-mod-4.c            |   2 +
 sysdeps/x86_64/nptl/tcb-offsets.sym           |   1 +
 sysdeps/x86_64/nptl/tls.h                     |  10 +-
 sysdeps/x86_64/tst-quadmod1.S                 |   6 +
 sysdeps/x86_64/tst-quadmod2.S                 |   6 +
 49 files changed, 1950 insertions(+), 14 deletions(-)
 create mode 100644 bits/indirect-return.h
 create mode 100644 stdlib/tst-setcontext4.c
 create mode 100644 stdlib/tst-setcontext5.c
 create mode 100644 stdlib/tst-setcontext6.c
 create mode 100644 stdlib/tst-setcontext7.c
 create mode 100644 stdlib/tst-setcontext8.c
 create mode 100644 stdlib/tst-setcontext9.c
 create mode 100644 stdlib/tst-swapcontext1.c
 create mode 100644 stdlib/tst-swapcontext2.c
 create mode 100644 sysdeps/unix/sysv/linux/bits/prctl.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/bits/prctl.h
 create mode 100644 sysdeps/x86/bits/indirect-return.h
 create mode 100644 sysdeps/x86/tst-cet-legacy-1.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-2.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-2a.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-3.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-4.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-4a.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-4b.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-4c.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-mod-1.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-mod-2.c
 create mode 100644 sysdeps/x86/tst-cet-legacy-mod-4.c

-- 
2.17.1

Comments

Carlos O'Donell July 24, 2018, 1:41 a.m. | #1
On 07/21/2018 10:20 AM, H.J. Lu wrote:
> These are the last 12 patches to enable Intel CET.  Tested by

> 

> 1. build-many-glibcs.py.

> 2. With --enable-cet and without --enable-cet for i686, x86-64 and x32

> on non-CET x86-64 processors.

> 3. With --enable-cet for x86-64 and x32 on CET SDV using the CET kernel

> from cet branch at:

> 

> https://github.com/yyu168/linux_cet/tree/cet

> 

> When the shadow stack (SHSTK) is enabled, makecontext needs to allocate

> a new shadow stack to go with the new stack allocated by the caller.

> setcontext and swapcontext must properly handle the corresponding shadow

> stack when the stack is switched.  Add more tests for user context

> functions to provide more coverage for the shadow stack support.


Thanks for putting this together for review.

Again, I think this should be ready for inclusion in 2.28.

We have spent a lot of time discussing CET and how it should be
handled. While I wanted to avoid a flag change, I know we can't
if we want to support *context() and that's OK.

At a high level we could still backport CET into various distributions,
but enabling it would disable *context() (because of the ABI change),
and that might be an OK position to take.

Cheers,
Carlos.
 
> H.J. Lu (12):

>   x86: Update vfork to pop shadow stack

>   x86-64: Add endbr64 to tst-quadmod[12].S

>   Add <bits/indirect-return.h>

>   x86/CET: Extend arch_prctl syscall for CET control

>   x86: Rename __glibc_reserved2 to ssp_base in tcbhead_t

>   x86-64/CET: Extend ucontext_t to save shadow stack

>   x86/CET: Add tests with legacy non-CET shared objects

>   Add a test for swapcontext with a wrapper

>   Add a test for multiple makecontext calls

>   Add another test for setcontext

>   Add a test for multiple setcontext calls

>   Add tests for setcontext on the context from makecontext

> 

>  bits/indirect-return.h                        |  25 ++

>  misc/sys/cdefs.h                              |   6 +

>  stdlib/Makefile                               |   7 +-

>  stdlib/tst-setcontext4.c                      | 217 ++++++++++++++++++

>  stdlib/tst-setcontext5.c                      |  88 +++++++

>  stdlib/tst-setcontext6.c                      |  76 ++++++

>  stdlib/tst-setcontext7.c                      |  96 ++++++++

>  stdlib/tst-setcontext8.c                      |  81 +++++++

>  stdlib/tst-setcontext9.c                      | 100 ++++++++

>  stdlib/tst-swapcontext1.c                     |  92 ++++++++

>  stdlib/tst-swapcontext2.c                     | 108 +++++++++

>  stdlib/ucontext.h                             |   6 +-

>  string/tst-xbzero-opt.c                       |  10 +-

>  sysdeps/i386/nptl/tcb-offsets.sym             |   1 +

>  sysdeps/i386/nptl/tls.h                       |   3 +-

>  sysdeps/unix/sysv/linux/Makefile              |   3 +-

>  sysdeps/unix/sysv/linux/bits/prctl.h          |  21 ++

>  sysdeps/unix/sysv/linux/i386/vfork.S          |  54 +++++

>  sysdeps/unix/sysv/linux/sys/prctl.h           |   1 +

>  sysdeps/unix/sysv/linux/x86/bits/prctl.h      |  48 ++++

>  sysdeps/unix/sysv/linux/x86/cpu-features.c    |   7 +

>  sysdeps/unix/sysv/linux/x86/dl-cet.h          |  29 ++-

>  sysdeps/unix/sysv/linux/x86/sys/ucontext.h    |   2 +

>  .../unix/sysv/linux/x86_64/__start_context.S  |  75 ++++++

>  sysdeps/unix/sysv/linux/x86_64/getcontext.S   |  17 ++

>  sysdeps/unix/sysv/linux/x86_64/makecontext.c  |  56 ++++-

>  sysdeps/unix/sysv/linux/x86_64/setcontext.S   | 139 +++++++++++

>  sysdeps/unix/sysv/linux/x86_64/swapcontext.S  | 150 ++++++++++++

>  sysdeps/unix/sysv/linux/x86_64/sysdep.h       |   5 +

>  sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym |   1 +

>  sysdeps/unix/sysv/linux/x86_64/vfork.S        |  35 +++

>  sysdeps/x86/Makefile                          |  38 +++

>  sysdeps/x86/bits/indirect-return.h            |  35 +++

>  sysdeps/x86/libc-start.c                      |   3 +

>  sysdeps/x86/tst-cet-legacy-1.c                |  44 ++++

>  sysdeps/x86/tst-cet-legacy-2.c                |  64 ++++++

>  sysdeps/x86/tst-cet-legacy-2a.c               |   1 +

>  sysdeps/x86/tst-cet-legacy-3.c                |  88 +++++++

>  sysdeps/x86/tst-cet-legacy-4.c                |  56 +++++

>  sysdeps/x86/tst-cet-legacy-4a.c               |   1 +

>  sysdeps/x86/tst-cet-legacy-4b.c               |   1 +

>  sysdeps/x86/tst-cet-legacy-4c.c               |   1 +

>  sysdeps/x86/tst-cet-legacy-mod-1.c            |  24 ++

>  sysdeps/x86/tst-cet-legacy-mod-2.c            |  24 ++

>  sysdeps/x86/tst-cet-legacy-mod-4.c            |   2 +

>  sysdeps/x86_64/nptl/tcb-offsets.sym           |   1 +

>  sysdeps/x86_64/nptl/tls.h                     |  10 +-

>  sysdeps/x86_64/tst-quadmod1.S                 |   6 +

>  sysdeps/x86_64/tst-quadmod2.S                 |   6 +

>  49 files changed, 1950 insertions(+), 14 deletions(-)

>  create mode 100644 bits/indirect-return.h

>  create mode 100644 stdlib/tst-setcontext4.c

>  create mode 100644 stdlib/tst-setcontext5.c

>  create mode 100644 stdlib/tst-setcontext6.c

>  create mode 100644 stdlib/tst-setcontext7.c

>  create mode 100644 stdlib/tst-setcontext8.c

>  create mode 100644 stdlib/tst-setcontext9.c

>  create mode 100644 stdlib/tst-swapcontext1.c

>  create mode 100644 stdlib/tst-swapcontext2.c

>  create mode 100644 sysdeps/unix/sysv/linux/bits/prctl.h

>  create mode 100644 sysdeps/unix/sysv/linux/x86/bits/prctl.h

>  create mode 100644 sysdeps/x86/bits/indirect-return.h

>  create mode 100644 sysdeps/x86/tst-cet-legacy-1.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-2.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-2a.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-3.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-4.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-4a.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-4b.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-4c.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-mod-1.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-mod-2.c

>  create mode 100644 sysdeps/x86/tst-cet-legacy-mod-4.c

>
Florian Weimer July 26, 2018, 11:16 a.m. | #2
On 07/21/2018 04:20 PM, H.J. Lu wrote:
> These are the last 12 patches to enable Intel CET.  Tested by

> 

> 1. build-many-glibcs.py.

> 2. With --enable-cet and without --enable-cet for i686, x86-64 and x32

> on non-CET x86-64 processors.

> 3. With --enable-cet for x86-64 and x32 on CET SDV using the CET kernel

> from cet branch at:

> 

> https://github.com/yyu168/linux_cet/tree/cet

> 

> When the shadow stack (SHSTK) is enabled, makecontext needs to allocate

> a new shadow stack to go with the new stack allocated by the caller.

> setcontext and swapcontext must properly handle the corresponding shadow

> stack when the stack is switched.  Add more tests for user context

> functions to provide more coverage for the shadow stack support.


Building glibc with --enable-cet currently breaks valgrind (even for 
current CPUs which do not support CET):

   https://bugzilla.redhat.com/show_bug.cgi?id=1608824

Mark is working on a valgrind fix.

Thanks,
Florian
Florian Weimer July 27, 2018, 2:53 p.m. | #3
On 07/26/2018 01:16 PM, Florian Weimer wrote:
> On 07/21/2018 04:20 PM, H.J. Lu wrote:

>> These are the last 12 patches to enable Intel CET.  Tested by

>>

>> 1. build-many-glibcs.py.

>> 2. With --enable-cet and without --enable-cet for i686, x86-64 and x32

>> on non-CET x86-64 processors.

>> 3. With --enable-cet for x86-64 and x32 on CET SDV using the CET kernel

>> from cet branch at:

>>

>> https://github.com/yyu168/linux_cet/tree/cet

>>

>> When the shadow stack (SHSTK) is enabled, makecontext needs to allocate

>> a new shadow stack to go with the new stack allocated by the caller.

>> setcontext and swapcontext must properly handle the corresponding shadow

>> stack when the stack is switched.  Add more tests for user context

>> functions to provide more coverage for the shadow stack support.

> 

> Building glibc with --enable-cet currently breaks valgrind (even for 

> current CPUs which do not support CET):

> 

>    https://bugzilla.redhat.com/show_bug.cgi?id=1608824

> 

> Mark is working on a valgrind fix.


This has now been fixed (in valgrind-3.13.0-22.fc29.x86_64), but I get 
this instead:

==22== Conditional jump or move depends on uninitialised value(s)
==22==    at 0x10DF43: _dl_process_cet_property_note (dl-prop.h:82)
==22==    by 0x10DF43: _dl_process_pt_note (dl-prop.h:137)
==22==    by 0x10E713: _dl_map_object_from_fd (dl-load.c:1170)
==22==    by 0x11120B: _dl_map_object (dl-load.c:2241)
==22==    by 0x10D92B: dl_main (rtld.c:1050)
==22==    by 0x121A6E: _dl_sysdep_start (dl-sysdep.c:253)
==22==    by 0x10A1D7: _dl_start_final (rtld.c:413)
==22==    by 0x10A1D7: _dl_start (rtld.c:520)
==22==    by 0x109117: ??? (in …/build-x86_64-redhat-linux/elf/ld.so)
==22==    by 0x3: ???
==22==    by 0x1FFF000746: ???
==22==    by 0x1FFF000750: ???
==22==    by 0x1FFF00075F: ???
==22==    by 0x1FFF000770: ???
==22==  Uninitialised value was created by a stack allocation
==22==    at 0x10DE80: _dl_process_pt_note (dl-prop.h:111)

One potential cause could be that note traversal loop is buggy.

GDB says:

(gdb) bt
#0  0x000000000010df43 in _dl_process_cet_property_note 
(align=<optimized out>, size=48, note=0x1ffefff930, l=0x134160)
     at ../sysdeps/x86/dl-prop.h:82
#1  _dl_process_pt_note (l=l@entry=0x134160, ph=ph@entry=0x1fff000018, 
fd=fd@entry=3, fbp=fbp@entry=0x1ffefffe10)
     at ../sysdeps/x86/dl-prop.h:137
#2  0x000000000010e714 in _dl_map_object_from_fd 
(name=name@entry=0x1fff000721 "/usr/bin/true", origname=origname@entry=0x0,
     fd=<optimized out>, fbp=fbp@entry=0x1ffefffe10, realname=<optimized 
out>, loader=loader@entry=0x0, l_type=<optimized out>,
     mode=<optimized out>, stack_endp=<optimized out>, nsid=<optimized 
out>) at dl-load.c:1170
#3  0x000000000011120c in _dl_map_object (loader=loader@entry=0x0, 
name=0x1fff000721 "/usr/bin/true", type=type@entry=0,
     trace_mode=trace_mode@entry=0, mode=mode@entry=536870912, 
nsid=nsid@entry=0) at dl-load.c:2241
#4  0x000000000010d92c in dl_main (phdr=<optimized out>, phnum=10, 
user_entry=0x1fff0003d8, auxv=<optimized out>) at rtld.c:1050
#5  0x0000000000121a6f in _dl_sysdep_start 
(start_argptr=start_argptr@entry=0x1fff0004b0, 
dl_main=dl_main@entry=0x10a610 <dl_main>)
     at ../elf/dl-sysdep.c:253
#6  0x000000000010a1d8 in _dl_start_final (arg=0x1fff0004b0) at rtld.c:413
#7  _dl_start (arg=0x1fff0004b0) at rtld.c:520
#8  0x0000000000109118 in _start ()

The problem seems to be this:

	      unsigned int type = *(unsigned int *) ptr;
	      unsigned int datasz = *(unsigned int *) (ptr + 4);

	      ptr += 8;
	      if ((ptr + datasz) > ptr_end)
		break;

We load datasz and then check for having encountered the last note.  I'm 
checking a fix.

Thanks,
Florian
Florian Weimer July 27, 2018, 2:58 p.m. | #4
On 07/27/2018 04:53 PM, Florian Weimer wrote:
> On 07/26/2018 01:16 PM, Florian Weimer wrote:

>> On 07/21/2018 04:20 PM, H.J. Lu wrote:

>>> These are the last 12 patches to enable Intel CET.  Tested by

>>>

>>> 1. build-many-glibcs.py.

>>> 2. With --enable-cet and without --enable-cet for i686, x86-64 and x32

>>> on non-CET x86-64 processors.

>>> 3. With --enable-cet for x86-64 and x32 on CET SDV using the CET kernel

>>> from cet branch at:

>>>

>>> https://github.com/yyu168/linux_cet/tree/cet

>>>

>>> When the shadow stack (SHSTK) is enabled, makecontext needs to allocate

>>> a new shadow stack to go with the new stack allocated by the caller.

>>> setcontext and swapcontext must properly handle the corresponding shadow

>>> stack when the stack is switched.  Add more tests for user context

>>> functions to provide more coverage for the shadow stack support.

>>

>> Building glibc with --enable-cet currently breaks valgrind (even for 

>> current CPUs which do not support CET):

>>

>>    https://bugzilla.redhat.com/show_bug.cgi?id=1608824

>>

>> Mark is working on a valgrind fix.

> 

> This has now been fixed (in valgrind-3.13.0-22.fc29.x86_64), but I get 

> this instead:

> 

> ==22== Conditional jump or move depends on uninitialised value(s)

> ==22==    at 0x10DF43: _dl_process_cet_property_note (dl-prop.h:82)

> ==22==    by 0x10DF43: _dl_process_pt_note (dl-prop.h:137)

> ==22==    by 0x10E713: _dl_map_object_from_fd (dl-load.c:1170)

> ==22==    by 0x11120B: _dl_map_object (dl-load.c:2241)

> ==22==    by 0x10D92B: dl_main (rtld.c:1050)

> ==22==    by 0x121A6E: _dl_sysdep_start (dl-sysdep.c:253)

> ==22==    by 0x10A1D7: _dl_start_final (rtld.c:413)

> ==22==    by 0x10A1D7: _dl_start (rtld.c:520)

> ==22==    by 0x109117: ??? (in …/build-x86_64-redhat-linux/elf/ld.so)

> ==22==    by 0x3: ???

> ==22==    by 0x1FFF000746: ???

> ==22==    by 0x1FFF000750: ???

> ==22==    by 0x1FFF00075F: ???

> ==22==    by 0x1FFF000770: ???

> ==22==  Uninitialised value was created by a stack allocation

> ==22==    at 0x10DE80: _dl_process_pt_note (dl-prop.h:111)

> 

> One potential cause could be that note traversal loop is buggy.

> 

> GDB says:

> 

> (gdb) bt

> #0  0x000000000010df43 in _dl_process_cet_property_note 

> (align=<optimized out>, size=48, note=0x1ffefff930, l=0x134160)

>      at ../sysdeps/x86/dl-prop.h:82

> #1  _dl_process_pt_note (l=l@entry=0x134160, ph=ph@entry=0x1fff000018, 

> fd=fd@entry=3, fbp=fbp@entry=0x1ffefffe10)

>      at ../sysdeps/x86/dl-prop.h:137

> #2  0x000000000010e714 in _dl_map_object_from_fd 

> (name=name@entry=0x1fff000721 "/usr/bin/true", origname=origname@entry=0x0,

>      fd=<optimized out>, fbp=fbp@entry=0x1ffefffe10, realname=<optimized 

> out>, loader=loader@entry=0x0, l_type=<optimized out>,

>      mode=<optimized out>, stack_endp=<optimized out>, nsid=<optimized 

> out>) at dl-load.c:1170

> #3  0x000000000011120c in _dl_map_object (loader=loader@entry=0x0, 

> name=0x1fff000721 "/usr/bin/true", type=type@entry=0,

>      trace_mode=trace_mode@entry=0, mode=mode@entry=536870912, 

> nsid=nsid@entry=0) at dl-load.c:2241

> #4  0x000000000010d92c in dl_main (phdr=<optimized out>, phnum=10, 

> user_entry=0x1fff0003d8, auxv=<optimized out>) at rtld.c:1050

> #5  0x0000000000121a6f in _dl_sysdep_start 

> (start_argptr=start_argptr@entry=0x1fff0004b0, 

> dl_main=dl_main@entry=0x10a610 <dl_main>)

>      at ../elf/dl-sysdep.c:253

> #6  0x000000000010a1d8 in _dl_start_final (arg=0x1fff0004b0) at rtld.c:413

> #7  _dl_start (arg=0x1fff0004b0) at rtld.c:520

> #8  0x0000000000109118 in _start ()

> 

> The problem seems to be this:

> 

>            unsigned int type = *(unsigned int *) ptr;

>            unsigned int datasz = *(unsigned int *) (ptr + 4);

> 

>            ptr += 8;

>            if ((ptr + datasz) > ptr_end)

>          break;

> 

> We load datasz and then check for having encountered the last note.  I'm 

> checking a fix.


The attached patch should fix this.  Only lightly tested.

Thanks,
Florian
Subject: [PATCH] x86: Fix out of bounds access in CET note parser
To: libc-alpha@sourceware.org

2018-07-27  Florian Weimer  <fweimer@redhat.com>

	* sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Fixed
	out-of-bounds access in note parser.

diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
index d56e20a6dc..9ee70ebc01 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -73,7 +73,7 @@ _dl_process_cet_property_note (struct link_map *l,
 	  unsigned char *ptr = (unsigned char *) (note + 1) + 4;
 	  unsigned char *ptr_end = ptr + note->n_descsz;
 
-	  while (1)
+	  while (ptr_end - ptr >= 8)
 	    {
 	      unsigned int type = *(unsigned int *) ptr;
 	      unsigned int datasz = *(unsigned int *) (ptr + 4);
H.J. Lu July 27, 2018, 4:37 p.m. | #5
On Fri, Jul 27, 2018 at 7:53 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 07/26/2018 01:16 PM, Florian Weimer wrote:

>>

>> On 07/21/2018 04:20 PM, H.J. Lu wrote:

>>>

>>> These are the last 12 patches to enable Intel CET.  Tested by

>>>

>>> 1. build-many-glibcs.py.

>>> 2. With --enable-cet and without --enable-cet for i686, x86-64 and x32

>>> on non-CET x86-64 processors.

>>> 3. With --enable-cet for x86-64 and x32 on CET SDV using the CET kernel

>>> from cet branch at:

>>>

>>> https://github.com/yyu168/linux_cet/tree/cet

>>>

>>> When the shadow stack (SHSTK) is enabled, makecontext needs to allocate

>>> a new shadow stack to go with the new stack allocated by the caller.

>>> setcontext and swapcontext must properly handle the corresponding shadow

>>> stack when the stack is switched.  Add more tests for user context

>>> functions to provide more coverage for the shadow stack support.

>>

>>

>> Building glibc with --enable-cet currently breaks valgrind (even for

>> current CPUs which do not support CET):

>>

>>    https://bugzilla.redhat.com/show_bug.cgi?id=1608824

>>

>> Mark is working on a valgrind fix.

>

>

> This has now been fixed (in valgrind-3.13.0-22.fc29.x86_64), but I get this

> instead:

>

> ==22== Conditional jump or move depends on uninitialised value(s)

> ==22==    at 0x10DF43: _dl_process_cet_property_note (dl-prop.h:82)

> ==22==    by 0x10DF43: _dl_process_pt_note (dl-prop.h:137)

> ==22==    by 0x10E713: _dl_map_object_from_fd (dl-load.c:1170)

> ==22==    by 0x11120B: _dl_map_object (dl-load.c:2241)

> ==22==    by 0x10D92B: dl_main (rtld.c:1050)

> ==22==    by 0x121A6E: _dl_sysdep_start (dl-sysdep.c:253)

> ==22==    by 0x10A1D7: _dl_start_final (rtld.c:413)

> ==22==    by 0x10A1D7: _dl_start (rtld.c:520)

> ==22==    by 0x109117: ??? (in …/build-x86_64-redhat-linux/elf/ld.so)

> ==22==    by 0x3: ???

> ==22==    by 0x1FFF000746: ???

> ==22==    by 0x1FFF000750: ???

> ==22==    by 0x1FFF00075F: ???

> ==22==    by 0x1FFF000770: ???

> ==22==  Uninitialised value was created by a stack allocation

> ==22==    at 0x10DE80: _dl_process_pt_note (dl-prop.h:111)

>

> One potential cause could be that note traversal loop is buggy.

>

> GDB says:

>

> (gdb) bt

> #0  0x000000000010df43 in _dl_process_cet_property_note (align=<optimized

> out>, size=48, note=0x1ffefff930, l=0x134160)

>     at ../sysdeps/x86/dl-prop.h:82

> #1  _dl_process_pt_note (l=l@entry=0x134160, ph=ph@entry=0x1fff000018,

> fd=fd@entry=3, fbp=fbp@entry=0x1ffefffe10)

>     at ../sysdeps/x86/dl-prop.h:137

> #2  0x000000000010e714 in _dl_map_object_from_fd

> (name=name@entry=0x1fff000721 "/usr/bin/true", origname=origname@entry=0x0,

>     fd=<optimized out>, fbp=fbp@entry=0x1ffefffe10, realname=<optimized

> out>, loader=loader@entry=0x0, l_type=<optimized out>,

>     mode=<optimized out>, stack_endp=<optimized out>, nsid=<optimized out>)

> at dl-load.c:1170

> #3  0x000000000011120c in _dl_map_object (loader=loader@entry=0x0,

> name=0x1fff000721 "/usr/bin/true", type=type@entry=0,

>     trace_mode=trace_mode@entry=0, mode=mode@entry=536870912,

> nsid=nsid@entry=0) at dl-load.c:2241

> #4  0x000000000010d92c in dl_main (phdr=<optimized out>, phnum=10,

> user_entry=0x1fff0003d8, auxv=<optimized out>) at rtld.c:1050

> #5  0x0000000000121a6f in _dl_sysdep_start

> (start_argptr=start_argptr@entry=0x1fff0004b0,

> dl_main=dl_main@entry=0x10a610 <dl_main>)

>     at ../elf/dl-sysdep.c:253

> #6  0x000000000010a1d8 in _dl_start_final (arg=0x1fff0004b0) at rtld.c:413

> #7  _dl_start (arg=0x1fff0004b0) at rtld.c:520

> #8  0x0000000000109118 in _start ()

>

> The problem seems to be this:

>

>               unsigned int type = *(unsigned int *) ptr;

>               unsigned int datasz = *(unsigned int *) (ptr + 4);

>

>               ptr += 8;

>               if ((ptr + datasz) > ptr_end)

>                 break;

>

> We load datasz and then check for having encountered the last note.  I'm

> checking a fix.


How can I reproduce it?

[hjl@gnu-cfl-1 build-x86_64-linux]$ strace ./misc/tst-mntent --direct
execve("./misc/tst-mntent", ["./misc/tst-mntent", "--direct"],
0x7ffca647e038 /* 70 vars */) = 0
brk(NULL)                               = 0x205c000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd122d56f0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x7fce93e8a000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
...
[hjl@gnu-cfl-1 build-x86_64-linux]$ valgrind ./misc/tst-mntent --direct
==21245== Memcheck, a memory error detector
==21245== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21245== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==21245== Command: ./misc/tst-mntent --direct
==21245==
Found!
==21245==
==21245== HEAP SUMMARY:
==21245==     in use at exit: 552 bytes in 1 blocks
==21245==   total heap usage: 3 allocs, 2 frees, 8,744 bytes allocated
==21245==
==21245== LEAK SUMMARY:
==21245==    definitely lost: 0 bytes in 0 blocks
==21245==    indirectly lost: 0 bytes in 0 blocks
==21245==      possibly lost: 0 bytes in 0 blocks
==21245==    still reachable: 552 bytes in 1 blocks
==21245==         suppressed: 0 bytes in 0 blocks
==21245== Rerun with --leak-check=full to see details of leaked memory
==21245==
==21245== For counts of detected and suppressed errors, rerun with: -v
==21245== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[hjl@gnu-cfl-1 build-x86_64-linux]$


-- 
H.J.
Florian Weimer July 27, 2018, 4:44 p.m. | #6
On 07/27/2018 06:37 PM, H.J. Lu wrote:

>> We load datasz and then check for having encountered the last note.  I'm

>> checking a fix.

> 

> How can I reproduce it?


Perhaps it is only visible with an explicit invocation of the dynamic 
linker?

I saw it while building GCC on Fedora rawhide.  I've pushed my latest 
changes (commit a4a5659439698554d18b9f1ef56cbd86591e217b) to the 
distribution Git, even though they do not build.  The valgrind check at 
the end of the build fails.

Thanks,
Florian
H.J. Lu July 27, 2018, 4:47 p.m. | #7
On Fri, Jul 27, 2018 at 9:44 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 07/27/2018 06:37 PM, H.J. Lu wrote:

>

>>> We load datasz and then check for having encountered the last note.  I'm

>>> checking a fix.

>>

>>

>> How can I reproduce it?

>

>

> Perhaps it is only visible with an explicit invocation of the dynamic

> linker?

>

> I saw it while building GCC on Fedora rawhide.  I've pushed my latest

> changes (commit a4a5659439698554d18b9f1ef56cbd86591e217b) to the

> distribution Git, even though they do not build.  The valgrind check at the

> end of the build fails.


What is the command line to reproduce it with glibc build configured
with --enable-cet?


-- 
H.J.
Florian Weimer July 27, 2018, 4:49 p.m. | #8
On 07/27/2018 06:47 PM, H.J. Lu wrote:
> On Fri, Jul 27, 2018 at 9:44 AM, Florian Weimer <fweimer@redhat.com> wrote:

>> On 07/27/2018 06:37 PM, H.J. Lu wrote:

>>

>>>> We load datasz and then check for having encountered the last note.  I'm

>>>> checking a fix.

>>>

>>>

>>> How can I reproduce it?

>>

>>

>> Perhaps it is only visible with an explicit invocation of the dynamic

>> linker?

>>

>> I saw it while building GCC on Fedora rawhide.  I've pushed my latest

>> changes (commit a4a5659439698554d18b9f1ef56cbd86591e217b) to the

>> distribution Git, even though they do not build.  The valgrind check at the

>> end of the build fails.

> 

> What is the command line to reproduce it with glibc build configured

> with --enable-cet?


This command is run inside the build directory:

elf/ld.so --library-path .:elf:nptl:dlfcn /usr/bin/valgrind 
--vgdb-error=1 --track-origins=yes --error-exitcode=1 elf/ld.so 
--library-path .:elf:nptl:dlfcn /usr/bin/true

Thanks,
Florian
H.J. Lu July 27, 2018, 5:13 p.m. | #9
On Fri, Jul 27, 2018 at 9:49 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 07/27/2018 06:47 PM, H.J. Lu wrote:

>>

>> On Fri, Jul 27, 2018 at 9:44 AM, Florian Weimer <fweimer@redhat.com>

>> wrote:

>>>

>>> On 07/27/2018 06:37 PM, H.J. Lu wrote:

>>>

>>>>> We load datasz and then check for having encountered the last note.

>>>>> I'm

>>>>> checking a fix.

>>>>

>>>>

>>>>

>>>> How can I reproduce it?

>>>

>>>

>>>

>>> Perhaps it is only visible with an explicit invocation of the dynamic

>>> linker?

>>>

>>> I saw it while building GCC on Fedora rawhide.  I've pushed my latest

>>> changes (commit a4a5659439698554d18b9f1ef56cbd86591e217b) to the

>>> distribution Git, even though they do not build.  The valgrind check at

>>> the

>>> end of the build fails.

>>

>>

>> What is the command line to reproduce it with glibc build configured

>> with --enable-cet?

>

>

> This command is run inside the build directory:

>

> elf/ld.so --library-path .:elf:nptl:dlfcn /usr/bin/valgrind --vgdb-error=1

> --track-origins=yes --error-exitcode=1 elf/ld.so --library-path

> .:elf:nptl:dlfcn /usr/bin/true

>


[hjl@gnu-cet-2 build-x86_64-linux]$ elf/ld.so --library-path
.:elf:nptl:dlfcn /usr/bin/valgrind --vgdb-error=1 --track-origins=yes
--error-exitcode=1 elf/ld.so --library-path .:elf:nptl:dlfcn
/usr/bin/true
==1086== Memcheck, a memory error detector
==1086== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1086== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==1086== Command: elf/ld.so --library-path .:elf:nptl:dlfcn /usr/bin/true
==1086==
==1086==
==1086== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==1086==   /path/to/gdb elf/ld.so
==1086== and then give GDB the following command
==1086==   target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=1086
==1086== --pid is optional if only one valgrind process is running
==1086==
==1086==
==1086== HEAP SUMMARY:
==1086==     in use at exit: 0 bytes in 0 blocks
==1086==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==1086==
==1086== All heap blocks were freed -- no leaks are possible
==1086==
==1086== For counts of detected and suppressed errors, rerun with: -v
==1086== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[hjl@gnu-cet-2 build-x86_64-linux]$ strace  elf/ld.so
execve("elf/ld.so", ["elf/ld.so"], 0x7fff35c62fc0 /* 51 vars */) = 0
brk(NULL)                               = 0x7f0fb46ec000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffecf6aedf0) = 0
writev(2, [{iov_base="Usage: ld.so [OPTION]... EXECUTA"...,
iov_len=1373}], 1Usage: ld.so [OPTION]... EXECUTABLE-FILE
[ARGS-FOR-PROGRAM...]
You have invoked `ld.so', the helper program for shared library executables.
This program usually lives in the file `/lib/ld.so', and special directives
in executable files using ELF shared libraries tell the system's program
loader to load the helper program from this file.  This helper program loads
the shared libraries needed by the program executable, prepares the program
to run, and runs it.  You may invoke this helper program directly from the
command line to load and run an ELF executable file; this is like executing
that file itself, but always uses this helper program from the file you
specified, instead of the helper program file specified in the executable
file you run.  This is mostly of use for maintainers to test new versions
of this helper program; chances are you did not intend to run this program.

  --list                list all dependencies and how they are resolved
  --verify              verify that given object really is a dynamically linked
object we can handle
  --inhibit-cache       Do not use /etc/ld.so.cache
  --library-path PATH   use given PATH instead of content of the environment
variable LD_LIBRARY_PATH
  --inhibit-rpath LIST  ignore RUNPATH and RPATH information in object names
in LIST
  --audit LIST          use objects named in LIST as auditors
) = 1373
exit_group(127)                         = ?
+++ exited with 127 +++
[hjl@gnu-cet-2 build-x86_64-linux]$



-- 
H.J.
H.J. Lu July 27, 2018, 5:50 p.m. | #10
On Fri, Jul 27, 2018 at 10:13 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Jul 27, 2018 at 9:49 AM, Florian Weimer <fweimer@redhat.com> wrote:

>> On 07/27/2018 06:47 PM, H.J. Lu wrote:

>>>

>>> On Fri, Jul 27, 2018 at 9:44 AM, Florian Weimer <fweimer@redhat.com>

>>> wrote:

>>>>

>>>> On 07/27/2018 06:37 PM, H.J. Lu wrote:

>>>>

>>>>>> We load datasz and then check for having encountered the last note.

>>>>>> I'm

>>>>>> checking a fix.

>>>>>

>>>>>

>>>>>

>>>>> How can I reproduce it?

>>>>

>>>>

>>>>

>>>> Perhaps it is only visible with an explicit invocation of the dynamic

>>>> linker?

>>>>

>>>> I saw it while building GCC on Fedora rawhide.  I've pushed my latest

>>>> changes (commit a4a5659439698554d18b9f1ef56cbd86591e217b) to the

>>>> distribution Git, even though they do not build.  The valgrind check at

>>>> the

>>>> end of the build fails.

>>>

>>>

>>> What is the command line to reproduce it with glibc build configured

>>> with --enable-cet?

>>

>>

>> This command is run inside the build directory:

>>

>> elf/ld.so --library-path .:elf:nptl:dlfcn /usr/bin/valgrind --vgdb-error=1

>> --track-origins=yes --error-exitcode=1 elf/ld.so --library-path

>> .:elf:nptl:dlfcn /usr/bin/true

>>

>

> [hjl@gnu-cet-2 build-x86_64-linux]$ elf/ld.so --library-path

> .:elf:nptl:dlfcn /usr/bin/valgrind --vgdb-error=1 --track-origins=yes

> --error-exitcode=1 elf/ld.so --library-path .:elf:nptl:dlfcn

> /usr/bin/true

>


Your note may be different.  Mine has

[hjl@gnu-cet-1 build-x86_64-linux]$ readelf -n elf/ld.so

Displaying notes found in: .note.gnu.build-id
  Owner                 Data size Description
  GNU                  0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: 47063ae06339e7226b68aa983cd3225f2dfa1ee2

Displaying notes found in: .note.gnu.property
  Owner                 Data size Description
  GNU                  0x00000010 NT_GNU_PROPERTY_TYPE_0
      Properties: x86 feature: IBT, SHSTK
[hjl@gnu-cet-1 build-x86_64-linux]$

Can you send me your elf/ld.so?

-- 
H.J.
Florian Weimer July 27, 2018, 5:52 p.m. | #11
On 07/27/2018 07:50 PM, H.J. Lu wrote:
> On Fri, Jul 27, 2018 at 10:13 AM, H.J. Lu <hjl.tools@gmail.com> wrote:

>> On Fri, Jul 27, 2018 at 9:49 AM, Florian Weimer <fweimer@redhat.com> wrote:

>>> On 07/27/2018 06:47 PM, H.J. Lu wrote:

>>>>

>>>> On Fri, Jul 27, 2018 at 9:44 AM, Florian Weimer <fweimer@redhat.com>

>>>> wrote:

>>>>>

>>>>> On 07/27/2018 06:37 PM, H.J. Lu wrote:

>>>>>

>>>>>>> We load datasz and then check for having encountered the last note.

>>>>>>> I'm

>>>>>>> checking a fix.

>>>>>>

>>>>>>

>>>>>>

>>>>>> How can I reproduce it?

>>>>>

>>>>>

>>>>>

>>>>> Perhaps it is only visible with an explicit invocation of the dynamic

>>>>> linker?

>>>>>

>>>>> I saw it while building GCC on Fedora rawhide.  I've pushed my latest

>>>>> changes (commit a4a5659439698554d18b9f1ef56cbd86591e217b) to the

>>>>> distribution Git, even though they do not build.  The valgrind check at

>>>>> the

>>>>> end of the build fails.

>>>>

>>>>

>>>> What is the command line to reproduce it with glibc build configured

>>>> with --enable-cet?

>>>

>>>

>>> This command is run inside the build directory:

>>>

>>> elf/ld.so --library-path .:elf:nptl:dlfcn /usr/bin/valgrind --vgdb-error=1

>>> --track-origins=yes --error-exitcode=1 elf/ld.so --library-path

>>> .:elf:nptl:dlfcn /usr/bin/true

>>>

>>

>> [hjl@gnu-cet-2 build-x86_64-linux]$ elf/ld.so --library-path

>> .:elf:nptl:dlfcn /usr/bin/valgrind --vgdb-error=1 --track-origins=yes

>> --error-exitcode=1 elf/ld.so --library-path .:elf:nptl:dlfcn

>> /usr/bin/true

>>

> 

> Your note may be different.  Mine has

> 

> [hjl@gnu-cet-1 build-x86_64-linux]$ readelf -n elf/ld.so

> 

> Displaying notes found in: .note.gnu.build-id

>    Owner                 Data size Description

>    GNU                  0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)

>      Build ID: 47063ae06339e7226b68aa983cd3225f2dfa1ee2

> 

> Displaying notes found in: .note.gnu.property

>    Owner                 Data size Description

>    GNU                  0x00000010 NT_GNU_PROPERTY_TYPE_0

>        Properties: x86 feature: IBT, SHSTK

> [hjl@gnu-cet-1 build-x86_64-linux]$

> 

> Can you send me your elf/ld.so?


The note for /bin/true causes the problem.  I'm attaching it.

Thanks,
Florian
H.J. Lu July 27, 2018, 5:56 p.m. | #12
On Fri, Jul 27, 2018 at 10:52 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 07/27/2018 07:50 PM, H.J. Lu wrote:

>>

>> On Fri, Jul 27, 2018 at 10:13 AM, H.J. Lu <hjl.tools@gmail.com> wrote:

>>>

>>> On Fri, Jul 27, 2018 at 9:49 AM, Florian Weimer <fweimer@redhat.com>

>>> wrote:

>>>>

>>>> On 07/27/2018 06:47 PM, H.J. Lu wrote:

>>>>>

>>>>>

>>>>> On Fri, Jul 27, 2018 at 9:44 AM, Florian Weimer <fweimer@redhat.com>

>>>>> wrote:

>>>>>>

>>>>>>

>>>>>> On 07/27/2018 06:37 PM, H.J. Lu wrote:

>>>>>>

>>>>>>>> We load datasz and then check for having encountered the last note.

>>>>>>>> I'm

>>>>>>>> checking a fix.

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>>

>>>>>>> How can I reproduce it?

>>>>>>

>>>>>>

>>>>>>

>>>>>>

>>>>>> Perhaps it is only visible with an explicit invocation of the dynamic

>>>>>> linker?

>>>>>>

>>>>>> I saw it while building GCC on Fedora rawhide.  I've pushed my latest

>>>>>> changes (commit a4a5659439698554d18b9f1ef56cbd86591e217b) to the

>>>>>> distribution Git, even though they do not build.  The valgrind check

>>>>>> at

>>>>>> the

>>>>>> end of the build fails.

>>>>>

>>>>>

>>>>>

>>>>> What is the command line to reproduce it with glibc build configured

>>>>> with --enable-cet?

>>>>

>>>>

>>>>

>>>> This command is run inside the build directory:

>>>>

>>>> elf/ld.so --library-path .:elf:nptl:dlfcn /usr/bin/valgrind

>>>> --vgdb-error=1

>>>> --track-origins=yes --error-exitcode=1 elf/ld.so --library-path

>>>> .:elf:nptl:dlfcn /usr/bin/true

>>>>

>>>

>>> [hjl@gnu-cet-2 build-x86_64-linux]$ elf/ld.so --library-path

>>> .:elf:nptl:dlfcn /usr/bin/valgrind --vgdb-error=1 --track-origins=yes

>>> --error-exitcode=1 elf/ld.so --library-path .:elf:nptl:dlfcn

>>> /usr/bin/true

>>>

>>

>> Your note may be different.  Mine has

>>

>> [hjl@gnu-cet-1 build-x86_64-linux]$ readelf -n elf/ld.so

>>

>> Displaying notes found in: .note.gnu.build-id

>>    Owner                 Data size Description

>>    GNU                  0x00000014 NT_GNU_BUILD_ID (unique build ID

>> bitstring)

>>      Build ID: 47063ae06339e7226b68aa983cd3225f2dfa1ee2

>>

>> Displaying notes found in: .note.gnu.property

>>    Owner                 Data size Description

>>    GNU                  0x00000010 NT_GNU_PROPERTY_TYPE_0

>>        Properties: x86 feature: IBT, SHSTK

>> [hjl@gnu-cet-1 build-x86_64-linux]$

>>

>> Can you send me your elf/ld.so?

>

>

> The note for /bin/true causes the problem.  I'm attaching it.

>


Yes, I can reproduce it.  Let me take a look.

-- 
H.J.
Florian Weimer July 27, 2018, 6:20 p.m. | #13
On 07/27/2018 07:56 PM, H.J. Lu wrote:
> Yes, I can reproduce it.  Let me take a look.


Great.  Did you see the patch I posted?

Thanks,
Florian