Call REAL(swapcontext) with indirect_return attribute on x86

Message ID 20180718153752.GB13951@intel.com
State New
Headers show
Series
  • Call REAL(swapcontext) with indirect_return attribute on x86
Related show

Commit Message

H.J. Lu July 18, 2018, 3:37 p.m.
asan/asan_interceptors.cc has

...
  int res = REAL(swapcontext)(oucp, ucp);
...

REAL(swapcontext) is a function pointer to swapcontext in libc.  Since
swapcontext may return via indirect branch on x86 when shadow stack is
enabled, we need to call REAL(swapcontext) with indirect_return attribute
on x86 so that compiler can insert ENDBR after REAL(swapcontext) call.

I opened an LLVM bug:

https://bugs.llvm.org/show_bug.cgi?id=38207

But it won't get fixed before indirect_return attribute is added to
LLVM.  I'd like to get it fixed in GCC first.

Tested on i386 and x86-64.  OK for trunk after

https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01007.html

is approved?

Thanks.


H.J.
---
	PR target/86560
	* asan/asan_interceptors.cc (swapcontext): Call REAL(swapcontext)
	with indirect_return attribute on x86.
---
 libsanitizer/asan/asan_interceptors.cc | 6 ++++++
 1 file changed, 6 insertions(+)

-- 
2.17.1

Comments

Ed Smith-Rowland via gcc-patches July 18, 2018, 6:18 p.m. | #1
What's ENDBR and do we really need to have it in compiler-rt?

As usual, I am opposed to any gcc compiler-rt that bypass upstream.

--kcc

On Wed, Jul 18, 2018 at 8:37 AM H.J. Lu <hongjiu.lu@intel.com> wrote:
>

> asan/asan_interceptors.cc has

>

> ...

>   int res = REAL(swapcontext)(oucp, ucp);

> ...

>

> REAL(swapcontext) is a function pointer to swapcontext in libc.  Since

> swapcontext may return via indirect branch on x86 when shadow stack is

> enabled, we need to call REAL(swapcontext) with indirect_return attribute

> on x86 so that compiler can insert ENDBR after REAL(swapcontext) call.

>

> I opened an LLVM bug:

>

> https://bugs.llvm.org/show_bug.cgi?id=38207

>

> But it won't get fixed before indirect_return attribute is added to

> LLVM.  I'd like to get it fixed in GCC first.

>

> Tested on i386 and x86-64.  OK for trunk after

>

> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01007.html

>

> is approved?

>

> Thanks.

>

>

> H.J.

> ---

>         PR target/86560

>         * asan/asan_interceptors.cc (swapcontext): Call REAL(swapcontext)

>         with indirect_return attribute on x86.

> ---

>  libsanitizer/asan/asan_interceptors.cc | 6 ++++++

>  1 file changed, 6 insertions(+)

>

> diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc

> index a8f4b72723f..b8dde4f19c5 100644

> --- a/libsanitizer/asan/asan_interceptors.cc

> +++ b/libsanitizer/asan/asan_interceptors.cc

> @@ -267,7 +267,13 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,

>    uptr stack, ssize;

>    ReadContextStack(ucp, &stack, &ssize);

>    ClearShadowMemoryForContextStack(stack, ssize);

> +#if defined(__x86_64__) || defined(__i386__)

> +  int (*real_swapcontext) (struct ucontext_t *, struct ucontext_t *)

> +    __attribute__((__indirect_return__)) = REAL(swapcontext);

> +  int res = real_swapcontext(oucp, ucp);

> +#else

>    int res = REAL(swapcontext)(oucp, ucp);

> +#endif

>    // swapcontext technically does not return, but program may swap context to

>    // "oucp" later, that would look as if swapcontext() returned 0.

>    // We need to clear shadow for ucp once again, as it may be in arbitrary

> --

> 2.17.1

>
H.J. Lu July 18, 2018, 6:40 p.m. | #2
On Wed, Jul 18, 2018 at 11:18 AM, Kostya Serebryany <kcc@google.com> wrote:
> What's ENDBR and do we really need to have it in compiler-rt?


When shadow stack from Intel CET is enabled,  the first instruction of all
indirect branch targets must be a special instruction, ENDBR.  In this case,

int res = REAL(swapcontext)(oucp, ucp);
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  This function may be
returned via an indirect branch.

Here compiler must insert ENDBR after call, like

call *bar(%rip)
endbr64

> As usual, I am opposed to any gcc compiler-rt that bypass upstream.


We want it to be fixed in upstream.  That is why I opened an LLVM bug.


> --kcc

>

> On Wed, Jul 18, 2018 at 8:37 AM H.J. Lu <hongjiu.lu@intel.com> wrote:

>>

>> asan/asan_interceptors.cc has

>>

>> ...

>>   int res = REAL(swapcontext)(oucp, ucp);

>> ...

>>

>> REAL(swapcontext) is a function pointer to swapcontext in libc.  Since

>> swapcontext may return via indirect branch on x86 when shadow stack is

>> enabled, we need to call REAL(swapcontext) with indirect_return attribute

>> on x86 so that compiler can insert ENDBR after REAL(swapcontext) call.

>>

>> I opened an LLVM bug:

>>

>> https://bugs.llvm.org/show_bug.cgi?id=38207

>>

>> But it won't get fixed before indirect_return attribute is added to

>> LLVM.  I'd like to get it fixed in GCC first.

>>

>> Tested on i386 and x86-64.  OK for trunk after

>>

>> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01007.html

>>

>> is approved?

>>

>> Thanks.

>>

>>

>> H.J.

>> ---

>>         PR target/86560

>>         * asan/asan_interceptors.cc (swapcontext): Call REAL(swapcontext)

>>         with indirect_return attribute on x86.

>> ---

>>  libsanitizer/asan/asan_interceptors.cc | 6 ++++++

>>  1 file changed, 6 insertions(+)

>>

>> diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc

>> index a8f4b72723f..b8dde4f19c5 100644

>> --- a/libsanitizer/asan/asan_interceptors.cc

>> +++ b/libsanitizer/asan/asan_interceptors.cc

>> @@ -267,7 +267,13 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,

>>    uptr stack, ssize;

>>    ReadContextStack(ucp, &stack, &ssize);

>>    ClearShadowMemoryForContextStack(stack, ssize);

>> +#if defined(__x86_64__) || defined(__i386__)

>> +  int (*real_swapcontext) (struct ucontext_t *, struct ucontext_t *)

>> +    __attribute__((__indirect_return__)) = REAL(swapcontext);

>> +  int res = real_swapcontext(oucp, ucp);

>> +#else

>>    int res = REAL(swapcontext)(oucp, ucp);

>> +#endif

>>    // swapcontext technically does not return, but program may swap context to

>>    // "oucp" later, that would look as if swapcontext() returned 0.

>>    // We need to clear shadow for ucp once again, as it may be in arbitrary

>> --

>> 2.17.1

>>




-- 
H.J.
Ed Smith-Rowland via gcc-patches July 18, 2018, 6:45 p.m. | #3
On Wed, Jul 18, 2018 at 11:40 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> On Wed, Jul 18, 2018 at 11:18 AM, Kostya Serebryany <kcc@google.com> wrote:

> > What's ENDBR and do we really need to have it in compiler-rt?

>

> When shadow stack from Intel CET is enabled,  the first instruction of all

> indirect branch targets must be a special instruction, ENDBR.  In this case,


I am confused.
CET is a security mitigation feature (and ENDBR is a pretty weak form of such),
while ASAN is a testing tool, rarely used in production is almost
never as a mitigation (which it is not!).
Why would anyone need to combine CET and ASAN in one process?

Also, CET doesn't exist in the hardware yet, at least not publicly available.
Which means there should be no rush (am I wrong?) and we can do things
in the correct order:
implement the Clang/LLVM support, make the compiler-rt change in LLVM,
merge back to GCC.

--kcc

>

> int res = REAL(swapcontext)(oucp, ucp);

>               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  This function may be

> returned via an indirect branch.

>

> Here compiler must insert ENDBR after call, like

>

> call *bar(%rip)

> endbr64

>

> > As usual, I am opposed to any gcc compiler-rt that bypass upstream.

>

> We want it to be fixed in upstream.  That is why I opened an LLVM bug.

>

>

> > --kcc

> >

> > On Wed, Jul 18, 2018 at 8:37 AM H.J. Lu <hongjiu.lu@intel.com> wrote:

> >>

> >> asan/asan_interceptors.cc has

> >>

> >> ...

> >>   int res = REAL(swapcontext)(oucp, ucp);

> >> ...

> >>

> >> REAL(swapcontext) is a function pointer to swapcontext in libc.  Since

> >> swapcontext may return via indirect branch on x86 when shadow stack is

> >> enabled, we need to call REAL(swapcontext) with indirect_return attribute

> >> on x86 so that compiler can insert ENDBR after REAL(swapcontext) call.

> >>

> >> I opened an LLVM bug:

> >>

> >> https://bugs.llvm.org/show_bug.cgi?id=38207

> >>

> >> But it won't get fixed before indirect_return attribute is added to

> >> LLVM.  I'd like to get it fixed in GCC first.

> >>

> >> Tested on i386 and x86-64.  OK for trunk after

> >>

> >> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01007.html

> >>

> >> is approved?

> >>

> >> Thanks.

> >>

> >>

> >> H.J.

> >> ---

> >>         PR target/86560

> >>         * asan/asan_interceptors.cc (swapcontext): Call REAL(swapcontext)

> >>         with indirect_return attribute on x86.

> >> ---

> >>  libsanitizer/asan/asan_interceptors.cc | 6 ++++++

> >>  1 file changed, 6 insertions(+)

> >>

> >> diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc

> >> index a8f4b72723f..b8dde4f19c5 100644

> >> --- a/libsanitizer/asan/asan_interceptors.cc

> >> +++ b/libsanitizer/asan/asan_interceptors.cc

> >> @@ -267,7 +267,13 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,

> >>    uptr stack, ssize;

> >>    ReadContextStack(ucp, &stack, &ssize);

> >>    ClearShadowMemoryForContextStack(stack, ssize);

> >> +#if defined(__x86_64__) || defined(__i386__)

> >> +  int (*real_swapcontext) (struct ucontext_t *, struct ucontext_t *)

> >> +    __attribute__((__indirect_return__)) = REAL(swapcontext);

> >> +  int res = real_swapcontext(oucp, ucp);

> >> +#else

> >>    int res = REAL(swapcontext)(oucp, ucp);

> >> +#endif

> >>    // swapcontext technically does not return, but program may swap context to

> >>    // "oucp" later, that would look as if swapcontext() returned 0.

> >>    // We need to clear shadow for ucp once again, as it may be in arbitrary

> >> --

> >> 2.17.1

> >>

>

>

>

> --

> H.J.
H.J. Lu July 18, 2018, 7:29 p.m. | #4
On Wed, Jul 18, 2018 at 11:45 AM, Kostya Serebryany <kcc@google.com> wrote:
> On Wed, Jul 18, 2018 at 11:40 AM H.J. Lu <hjl.tools@gmail.com> wrote:

>>

>> On Wed, Jul 18, 2018 at 11:18 AM, Kostya Serebryany <kcc@google.com> wrote:

>> > What's ENDBR and do we really need to have it in compiler-rt?

>>

>> When shadow stack from Intel CET is enabled,  the first instruction of all

>> indirect branch targets must be a special instruction, ENDBR.  In this case,

>

> I am confused.

> CET is a security mitigation feature (and ENDBR is a pretty weak form of such),

> while ASAN is a testing tool, rarely used in production is almost

> never as a mitigation (which it is not!).

> Why would anyone need to combine CET and ASAN in one process?

>


CET is transparent to ASAN.  It is perfectly OK to use -fcf-protection to
enable CET together with ASAN.

> Also, CET doesn't exist in the hardware yet, at least not publicly available.

> Which means there should be no rush (am I wrong?) and we can do things

> in the correct order:

> implement the Clang/LLVM support, make the compiler-rt change in LLVM,

> merge back to GCC.


I am working with our LLVM people to address this.

H.J.
> --kcc

>

>>

>> int res = REAL(swapcontext)(oucp, ucp);

>>               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  This function may be

>> returned via an indirect branch.

>>

>> Here compiler must insert ENDBR after call, like

>>

>> call *bar(%rip)

>> endbr64

>>

>> > As usual, I am opposed to any gcc compiler-rt that bypass upstream.

>>

>> We want it to be fixed in upstream.  That is why I opened an LLVM bug.

>>

>>

>> > --kcc

>> >

>> > On Wed, Jul 18, 2018 at 8:37 AM H.J. Lu <hongjiu.lu@intel.com> wrote:

>> >>

>> >> asan/asan_interceptors.cc has

>> >>

>> >> ...

>> >>   int res = REAL(swapcontext)(oucp, ucp);

>> >> ...

>> >>

>> >> REAL(swapcontext) is a function pointer to swapcontext in libc.  Since

>> >> swapcontext may return via indirect branch on x86 when shadow stack is

>> >> enabled, we need to call REAL(swapcontext) with indirect_return attribute

>> >> on x86 so that compiler can insert ENDBR after REAL(swapcontext) call.

>> >>

>> >> I opened an LLVM bug:

>> >>

>> >> https://bugs.llvm.org/show_bug.cgi?id=38207

>> >>

>> >> But it won't get fixed before indirect_return attribute is added to

>> >> LLVM.  I'd like to get it fixed in GCC first.

>> >>

>> >> Tested on i386 and x86-64.  OK for trunk after

>> >>

>> >> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01007.html

>> >>

>> >> is approved?

>> >>

>> >> Thanks.

>> >>

>> >>

>> >> H.J.

>> >> ---

>> >>         PR target/86560

>> >>         * asan/asan_interceptors.cc (swapcontext): Call REAL(swapcontext)

>> >>         with indirect_return attribute on x86.

>> >> ---

>> >>  libsanitizer/asan/asan_interceptors.cc | 6 ++++++

>> >>  1 file changed, 6 insertions(+)

>> >>

>> >> diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc

>> >> index a8f4b72723f..b8dde4f19c5 100644

>> >> --- a/libsanitizer/asan/asan_interceptors.cc

>> >> +++ b/libsanitizer/asan/asan_interceptors.cc

>> >> @@ -267,7 +267,13 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,

>> >>    uptr stack, ssize;

>> >>    ReadContextStack(ucp, &stack, &ssize);

>> >>    ClearShadowMemoryForContextStack(stack, ssize);

>> >> +#if defined(__x86_64__) || defined(__i386__)

>> >> +  int (*real_swapcontext) (struct ucontext_t *, struct ucontext_t *)

>> >> +    __attribute__((__indirect_return__)) = REAL(swapcontext);

>> >> +  int res = real_swapcontext(oucp, ucp);

>> >> +#else

>> >>    int res = REAL(swapcontext)(oucp, ucp);

>> >> +#endif

>> >>    // swapcontext technically does not return, but program may swap context to

>> >>    // "oucp" later, that would look as if swapcontext() returned 0.

>> >>    // We need to clear shadow for ucp once again, as it may be in arbitrary

>> >> --

>> >> 2.17.1

>> >>

>>

>>

>>

>> --

>> H.J.




-- 
H.J.
Ed Smith-Rowland via gcc-patches July 18, 2018, 7:34 p.m. | #5
On Wed, Jul 18, 2018 at 12:29 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> On Wed, Jul 18, 2018 at 11:45 AM, Kostya Serebryany <kcc@google.com> wrote:

> > On Wed, Jul 18, 2018 at 11:40 AM H.J. Lu <hjl.tools@gmail.com> wrote:

> >>

> >> On Wed, Jul 18, 2018 at 11:18 AM, Kostya Serebryany <kcc@google.com> wrote:

> >> > What's ENDBR and do we really need to have it in compiler-rt?

> >>

> >> When shadow stack from Intel CET is enabled,  the first instruction of all

> >> indirect branch targets must be a special instruction, ENDBR.  In this case,

> >

> > I am confused.

> > CET is a security mitigation feature (and ENDBR is a pretty weak form of such),

> > while ASAN is a testing tool, rarely used in production is almost

> > never as a mitigation (which it is not!).

> > Why would anyone need to combine CET and ASAN in one process?

> >

>

> CET is transparent to ASAN.  It is perfectly OK to use -fcf-protection to

> enable CET together with ASAN.


It is ok, but does it make any sense?
If anything, the current ASAN's intereceptors are a large blob of
security vulnerabilities.
If we ever want to use ASAN (or, more likely, HWASAN) as a security
mitigation feature,
we will need to get rid of these interceptors entirely.


>

> > Also, CET doesn't exist in the hardware yet, at least not publicly available.

> > Which means there should be no rush (am I wrong?) and we can do things

> > in the correct order:

> > implement the Clang/LLVM support, make the compiler-rt change in LLVM,

> > merge back to GCC.

>

> I am working with our LLVM people to address this.


Cool!


>

> H.J.

> > --kcc

> >

> >>

> >> int res = REAL(swapcontext)(oucp, ucp);

> >>               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  This function may be

> >> returned via an indirect branch.

> >>

> >> Here compiler must insert ENDBR after call, like

> >>

> >> call *bar(%rip)

> >> endbr64

> >>

> >> > As usual, I am opposed to any gcc compiler-rt that bypass upstream.

> >>

> >> We want it to be fixed in upstream.  That is why I opened an LLVM bug.

> >>

> >>

> >> > --kcc

> >> >

> >> > On Wed, Jul 18, 2018 at 8:37 AM H.J. Lu <hongjiu.lu@intel.com> wrote:

> >> >>

> >> >> asan/asan_interceptors.cc has

> >> >>

> >> >> ...

> >> >>   int res = REAL(swapcontext)(oucp, ucp);

> >> >> ...

> >> >>

> >> >> REAL(swapcontext) is a function pointer to swapcontext in libc.  Since

> >> >> swapcontext may return via indirect branch on x86 when shadow stack is

> >> >> enabled, we need to call REAL(swapcontext) with indirect_return attribute

> >> >> on x86 so that compiler can insert ENDBR after REAL(swapcontext) call.

> >> >>

> >> >> I opened an LLVM bug:

> >> >>

> >> >> https://bugs.llvm.org/show_bug.cgi?id=38207

> >> >>

> >> >> But it won't get fixed before indirect_return attribute is added to

> >> >> LLVM.  I'd like to get it fixed in GCC first.

> >> >>

> >> >> Tested on i386 and x86-64.  OK for trunk after

> >> >>

> >> >> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01007.html

> >> >>

> >> >> is approved?

> >> >>

> >> >> Thanks.

> >> >>

> >> >>

> >> >> H.J.

> >> >> ---

> >> >>         PR target/86560

> >> >>         * asan/asan_interceptors.cc (swapcontext): Call REAL(swapcontext)

> >> >>         with indirect_return attribute on x86.

> >> >> ---

> >> >>  libsanitizer/asan/asan_interceptors.cc | 6 ++++++

> >> >>  1 file changed, 6 insertions(+)

> >> >>

> >> >> diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc

> >> >> index a8f4b72723f..b8dde4f19c5 100644

> >> >> --- a/libsanitizer/asan/asan_interceptors.cc

> >> >> +++ b/libsanitizer/asan/asan_interceptors.cc

> >> >> @@ -267,7 +267,13 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,

> >> >>    uptr stack, ssize;

> >> >>    ReadContextStack(ucp, &stack, &ssize);

> >> >>    ClearShadowMemoryForContextStack(stack, ssize);

> >> >> +#if defined(__x86_64__) || defined(__i386__)

> >> >> +  int (*real_swapcontext) (struct ucontext_t *, struct ucontext_t *)

> >> >> +    __attribute__((__indirect_return__)) = REAL(swapcontext);

> >> >> +  int res = real_swapcontext(oucp, ucp);

> >> >> +#else

> >> >>    int res = REAL(swapcontext)(oucp, ucp);

> >> >> +#endif

> >> >>    // swapcontext technically does not return, but program may swap context to

> >> >>    // "oucp" later, that would look as if swapcontext() returned 0.

> >> >>    // We need to clear shadow for ucp once again, as it may be in arbitrary

> >> >> --

> >> >> 2.17.1

> >> >>

> >>

> >>

> >>

> >> --

> >> H.J.

>

>

>

> --

> H.J.
H.J. Lu July 19, 2018, 12:42 p.m. | #6
On Wed, Jul 18, 2018 at 12:34:28PM -0700, Kostya Serebryany wrote:
> On Wed, Jul 18, 2018 at 12:29 PM H.J. Lu <hjl.tools@gmail.com> wrote:

> >

> > On Wed, Jul 18, 2018 at 11:45 AM, Kostya Serebryany <kcc@google.com> wrote:

> > > On Wed, Jul 18, 2018 at 11:40 AM H.J. Lu <hjl.tools@gmail.com> wrote:

> > >>

> > >> On Wed, Jul 18, 2018 at 11:18 AM, Kostya Serebryany <kcc@google.com> wrote:

> > >> > What's ENDBR and do we really need to have it in compiler-rt?

> > >>

> > >> When shadow stack from Intel CET is enabled,  the first instruction of all

> > >> indirect branch targets must be a special instruction, ENDBR.  In this case,

> > >

> > > I am confused.

> > > CET is a security mitigation feature (and ENDBR is a pretty weak form of such),

> > > while ASAN is a testing tool, rarely used in production is almost

> > > never as a mitigation (which it is not!).

> > > Why would anyone need to combine CET and ASAN in one process?

> > >

> >

> > CET is transparent to ASAN.  It is perfectly OK to use -fcf-protection to

> > enable CET together with ASAN.

> 

> It is ok, but does it make any sense?

> If anything, the current ASAN's intereceptors are a large blob of

> security vulnerabilities.

> If we ever want to use ASAN (or, more likely, HWASAN) as a security

> mitigation feature,

> we will need to get rid of these interceptors entirely.

> 

> 

> >

> > > Also, CET doesn't exist in the hardware yet, at least not publicly available.

> > > Which means there should be no rush (am I wrong?) and we can do things

> > > in the correct order:

> > > implement the Clang/LLVM support, make the compiler-rt change in LLVM,

> > > merge back to GCC.

> >

> > I am working with our LLVM people to address this.

> 

> Cool!

> 


I am testing this patch and will submit it upstream.

H.J.
---
asan/asan_interceptors.cc has

...
  int res = REAL(swapcontext)(oucp, ucp);
...

REAL(swapcontext) is a function pointer to swapcontext in libc.  Since
swapcontext may return via indirect branch on x86 when shadow stack is
enabled, we need to call REAL(swapcontext) with indirect_return attribute
on x86 so that compiler can insert ENDBR after REAL(swapcontext) call.

	PR target/86560
	* asan/asan_interceptors.cc (swapcontext): Call REAL(swapcontext)
	with indirect_return attribute on x86 if indirect_return attribute
	is available.
---
 libsanitizer/asan/asan_interceptors.cc | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index a8f4b72723f..3ae473f210a 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -267,7 +267,16 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
   uptr stack, ssize;
   ReadContextStack(ucp, &stack, &ssize);
   ClearShadowMemoryForContextStack(stack, ssize);
+#if defined(__has_attribute) && (defined(__x86_64__) || defined(__i386__))
+  int (*real_swapcontext) (struct ucontext_t *, struct ucontext_t *)
+# if __has_attribute (__indirect_return__)
+    __attribute__((__indirect_return__))
+# endif
+    = REAL(swapcontext);
+  int res = real_swapcontext(oucp, ucp);
+#else
   int res = REAL(swapcontext)(oucp, ucp);
+#endif
   // swapcontext technically does not return, but program may swap context to
   // "oucp" later, that would look as if swapcontext() returned 0.
   // We need to clear shadow for ucp once again, as it may be in arbitrary
-- 
2.17.1

Patch

diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index a8f4b72723f..b8dde4f19c5 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -267,7 +267,13 @@  INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
   uptr stack, ssize;
   ReadContextStack(ucp, &stack, &ssize);
   ClearShadowMemoryForContextStack(stack, ssize);
+#if defined(__x86_64__) || defined(__i386__)
+  int (*real_swapcontext) (struct ucontext_t *, struct ucontext_t *)
+    __attribute__((__indirect_return__)) = REAL(swapcontext);
+  int res = real_swapcontext(oucp, ucp);
+#else
   int res = REAL(swapcontext)(oucp, ucp);
+#endif
   // swapcontext technically does not return, but program may swap context to
   // "oucp" later, that would look as if swapcontext() returned 0.
   // We need to clear shadow for ucp once again, as it may be in arbitrary