This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 1/2] Linux/x86: Update cancel_jmp_buf to match __jmp_buf_tag [BZ #22563]


On 12/08/2017 03:25 AM, H.J. Lu wrote:
Here is call stack during stack unwind:

(gdb) bt

(snip)

To unwind shadow stack, we need to save shadow stack pointer in
__cancel_buf.   This updated patch adds bits/types/__cancel_jmp_buf_tag.h
to define struct __cancel_jmp_buf_tag so that Linux/x86 can add saved_mask
to __cancel_jmp_buf.   We will check if shadow stack is enabled before saving
and restoring shadow stack pointer so that it works with the old smaller
cancel_jmp_buf which doesn't have space for shadow stack pointer.

I still don't understand why you think you have to reset the shadow stack.

I used this test program:

#include <err.h>
#include <errno.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

__attribute__ ((noinline, noclone, weak))
void
handler1 (void *closure)
{
  printf ("handler1 called\n");
}

__attribute__ ((noinline, noclone, weak))
void
handler2 (void *closure)
{
  printf ("handler2 called\n");
}

__attribute__ ((noinline, noclone, weak))
void
pausefunc (void)
{
  while (true)
    pause ();
}

__attribute__ ((noinline, noclone, weak))
void
handlerfunc (void)
{
  pthread_cleanup_push (handler2, NULL);
  pausefunc ();
  pthread_cleanup_pop (1);
}


__attribute__ ((noinline, noclone, weak))
void *
threadfunc (void *closure)
{
  pthread_cleanup_push (handler1, NULL);
  handlerfunc ();
  pthread_cleanup_pop (0);
  return NULL;
}

int
main (void)
{
  pthread_t thr;
  int ret = pthread_create (&thr, NULL, threadfunc, NULL);
  if (ret != 0)
    {
      errno = ret;
      err (1, "pthread_create");
    }

  ret = pthread_cancel (thr);
  if (ret != 0)
    {
      errno = ret;
      err (1, "pthread_cancel");
    }

  void *result;
  ret = pthread_join (thr, &result);
  if (ret != 0)
    {
      errno = ret;
      err (1, "pthread_join");
    }
  if (result != PTHREAD_CANCELED)
    errx (1, "pthread_join did not return PTHREAD_CANCEL, but %p", result);

  return 0;
}

See the attached GDB log. As you can see, I set breakpoints on all pre-existing RET instructions on the call stack (which would be protected by the shadow stack with CET). None of the RET instructions actually execute, ergo we do not have to restore the shadow stack.

Thanks,
Florian

Attachment: gdblog.txt
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]