From patchwork Mon Feb 12 12:42:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 128032 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3176179ljc; Mon, 12 Feb 2018 04:49:19 -0800 (PST) X-Google-Smtp-Source: AH8x226YgJyUy6dAOWR1CPTXqs+ZfeFpIu2wOi+r4gGfOp7sKCRSbXlpFmMQZok9zJ/osbTiF3+E X-Received: by 2002:a17:902:5854:: with SMTP id f20-v6mr6597392plj.374.1518439759642; Mon, 12 Feb 2018 04:49:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518439759; cv=none; d=google.com; s=arc-20160816; b=UhWtmEXkLwPR9hXTqN7dMsYhADKzAa3X2+uwdgfbt98Odj1+UpagLwE2IqNc4916P8 DmaZWpsRNRShUh5YL+LByeXmJuRWZHIdJ+YVFP8jL2VJLG1mWwraMmtkDwi4q18T3IeC YXNai7TY9hsy3N+8ERsMIJ8POcQdaEo0i4GKFgvAzYqEiyValDbk0QMpi4MMhbPr1zj3 LSaa1S8EKH34gRG4HtuMA9S0qdIkzDYyhgkz/swUqEJZ8ReXN28NMZOnmKnGMwg4oTUX HbPCn8yKK02S0ApnuYVXTBoBWxdCdF48CiPX906kjeHwmeDZ1ZofG9JCApBuClAJdH23 ql9Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:to:from:delivered-to :sender:list-help:list-post:list-archive:list-subscribe :list-unsubscribe:list-id:precedence:mailing-list:dkim-signature :domainkey-signature:arc-authentication-results; bh=70dswwT2acrztGtM4lQWP/nyF82j1PsDXLJyBh27544=; b=bhOiOoeojcWqOy4ibeCoPBqHmcBsy2cf6EB6aPF1pCiDM1Y0AxxKhRhCd1lXkXg/Km jr2h6gCqFR16uVIc32dJsqGBo0frMUvBdo30p1Mc5MSMUAUyPFj89sZ1K03BEOwehX3Z 4PV4YR1OPO4rO5j+99YE2C3fR5+TDrB7HoSPN0eK0DHEkC7crsKBgMXANWau4nE1r+EY pD232USEuFRQJK+fMYM6DIGzYp/rlc1RnpM1ajE7xaTzo1nL6KQ5YMzluV+NIdcXs3qk Gi2wnuc6+aBFF4qOoTG8+Au8e4bxx8GmcmqGn5v5lZl3Jj/YhNhbRwgpCxhDKNpRbGAU Dnag== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=cSeqO2dJ; spf=pass (google.com: domain of libc-alpha-return-90260-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=libc-alpha-return-90260-patch=linaro.org@sourceware.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id j88si6293111pfj.145.2018.02.12.04.49.19 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 12 Feb 2018 04:49:19 -0800 (PST) Received-SPF: pass (google.com: domain of libc-alpha-return-90260-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=cSeqO2dJ; spf=pass (google.com: domain of libc-alpha-return-90260-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=libc-alpha-return-90260-patch=linaro.org@sourceware.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; q=dns; s=default; b=IMwHJqtBQtxYYQCv5/IPf4QvwNo4ov1 9a0DhRnWOKSd4wZDoST7gEH85PWg/pUFusr3ErImI/w6qMqgOFeCYrEbSJvIPHzh 6XLfE9Upu0V02Pq4zw/aETUy9seov6q5cnea2nyUuoVCNOShdzJsqDcK3bzVepHx 6RG0sSkZJ6dY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; s=default; bh=/i52dxwAfxFen/kzhA4h2wdlE9c=; b=cSeqO 2dJerYsIQafGTRYcRLZ0A2sM8GseCvTpCttptIfnuX6yA+VjpQnxfbwofTKSbN3A 8oRxgZEIt0A/LzEgiQsmImz91OIFLQEhyOubEegK+gmhyezn7qjl1At/ED/NmPX4 S5axqHIiQxMEFi4bCyiRT8rPqRjG2CvADTum20= Received: (qmail 82044 invoked by alias); 12 Feb 2018 12:49:00 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 81918 invoked by uid 89); 12 Feb 2018 12:48:58 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=Fire, faults X-HELO: mail-qt0-f194.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=70dswwT2acrztGtM4lQWP/nyF82j1PsDXLJyBh27544=; b=bVPyEqulFamowigi2wWPbhYLvUgEjGHhwjLmYp0OZ5rVtwsY3dw3ElEeTz+YHxgTzt 2jSI9X9wdLZ216bLWLXJgHEuK9Ns6RbZR95B6MNUSYqDuULP08plDA1X5S42rCjlodv2 dYyq16CVslTxges4S1fhLkbwHuDBkb8nsHf+WqI5OlFlf4SZstrLtTBmPBWTZg8ETZZI m8HiR5HuKQWPhXEaWNc/XEId624M8D6HVgIUmB1yf7e1PrLoYkmkJwDL2k5gxGXH4scA cx/frPp251Fd9juP0byuCdp3no9ldRokTu18AEs06ZoJcGQ/jujNeZGVAaKkrR822aLk ireQ== X-Gm-Message-State: APf1xPBsPanCNtuhfxRQSDloJU3u8MOs4F7DMZcofDfcR0DUtnfulLdJ 2Uk9peDq1/mFAuh7MxeycMGFOp1oGgU= X-Received: by 10.200.97.86 with SMTP id d22mr18205977qtm.217.1518439355560; Mon, 12 Feb 2018 04:42:35 -0800 (PST) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v4 4/4] i386: Fix i386 sigaction sa_restorer initialization (BZ#21269) Date: Mon, 12 Feb 2018 10:42:25 -0200 Message-Id: <1518439345-6013-4-git-send-email-adhemerval.zanella@linaro.org> In-Reply-To: <1518439345-6013-1-git-send-email-adhemerval.zanella@linaro.org> References: <1518439345-6013-1-git-send-email-adhemerval.zanella@linaro.org> This patch fixes the i386 sa_restorer field initialization for sigaction syscall for kernel with vDSO. As described in bug report, x86_32 Linux (and compat on x86_64) interprets SA_RESTORER clear with nonzero sa_restorer as a request for stack switching if the SS segment is 'funny' This means that anything that tries to mix glibc's signal handling with segmentation (for instance through modify_ldt syscall) is randomly broken depending on what values lands in sa_restorer. The testcase added is based on Linux test tools/testing/selftests/x86/ldt_gdt.c, more specifically in do_multicpu_tests function. The main changes are: - C11 atomics instead of plain access. - Remove x86_64 support which simplifies the syscall handling and fallbacks. - Replicate only the test required to trigger the issue. (I added some comments of my understanding of how the testcase is triggering the issue, so if someone with more x86 knowledge could check if I get this right I will be grateful) Checked on i686-linux-gnu. [BZ #21269] * sysdeps/unix/sysv/linux/i386/Makefile (tests): Add tst-bz21269. * sysdeps/unix/sysv/linux/i386/sigaction.c (SET_SA_RESTORER): Clear sa_restorer for vDSO case. * sysdeps/unix/sysv/linux/i386/tst-bz21269.c: New file. Signed-off-by: Adhemerval Zanella --- ChangeLog | 6 + sysdeps/unix/sysv/linux/i386/Makefile | 3 + sysdeps/unix/sysv/linux/i386/sigaction.c | 2 + sysdeps/unix/sysv/linux/i386/tst-bz21269.c | 233 +++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 sysdeps/unix/sysv/linux/i386/tst-bz21269.c -- 2.7.4 diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile index 4080b8c..da716e2 100644 --- a/sysdeps/unix/sysv/linux/i386/Makefile +++ b/sysdeps/unix/sysv/linux/i386/Makefile @@ -3,6 +3,9 @@ default-abi := 32 ifeq ($(subdir),misc) sysdep_routines += ioperm iopl vm86 + +tests += tst-bz21269 +$(objpfx)tst-bz21269: $(shared-thread-library) endif ifeq ($(subdir),elf) diff --git a/sysdeps/unix/sysv/linux/i386/sigaction.c b/sysdeps/unix/sysv/linux/i386/sigaction.c index 137c73b..df9fa0c 100644 --- a/sysdeps/unix/sysv/linux/i386/sigaction.c +++ b/sysdeps/unix/sysv/linux/i386/sigaction.c @@ -32,6 +32,8 @@ extern void restore (void) asm ("__restore") attribute_hidden; (kact)->sa_restorer = (((act)->sa_flags & SA_SIGINFO) \ ? &restore_rt : &restore); \ } \ + else \ + (kact)->sa_restorer = NULL; \ }) #define RESET_SA_RESTORER(act, kact) \ diff --git a/sysdeps/unix/sysv/linux/i386/tst-bz21269.c b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c new file mode 100644 index 0000000..353e365 --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c @@ -0,0 +1,233 @@ +/* Test for i386 sigaction sa_restorer handling (BZ#21269) + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This is based on Linux test tools/testing/selftests/x86/ldt_gdt.c, + more specifically in do_multicpu_tests function. The main changes + are: + + - C11 atomics instead of plain access. + - Remove x86_64 support which simplifies the syscall handling + and fallbacks. + - Replicate only the test required to trigger the issue for the + BZ#21269. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +static int +xset_thread_area (struct user_desc *u_info) +{ + long ret = syscall (SYS_set_thread_area, u_info); + TEST_VERIFY_EXIT (ret == 0); + return ret; +} + +static void +xmodify_ldt (int func, const void *ptr, unsigned long bytecount) +{ + TEST_VERIFY_EXIT (syscall (SYS_modify_ldt, 1, ptr, bytecount) == 0); +} + +static int +futex (int *uaddr, int futex_op, int val, void *timeout, int *uaddr2, + int val3) +{ + return syscall (SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3); +} + +static void +xsethandler (int sig, void (*handler)(int, siginfo_t *, void *), int flags) +{ + struct sigaction sa = { 0 }; + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + TEST_VERIFY_EXIT (sigemptyset (&sa.sa_mask) == 0); + TEST_VERIFY_EXIT (sigaction (sig, &sa, 0) == 0); +} + +static jmp_buf jmpbuf; + +static void +sigsegv_handler (int sig, siginfo_t *info, void *ctx_void) +{ + siglongjmp (jmpbuf, 1); +} + +/* Points to an array of 1024 ints, each holding its own index. */ +static const unsigned int *counter_page; +static struct user_desc *low_user_desc; +static struct user_desc *low_user_desc_clear; /* Used to delete GDT entry. */ +static int gdt_entry_num; + +static void +setup_counter_page (void) +{ + long page_size = sysconf (_SC_PAGE_SIZE); + TEST_VERIFY_EXIT (page_size > 0); + unsigned int *page = xmmap (NULL, page_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1); + for (int i = 0; i < (page_size / sizeof (unsigned int)); i++) + page[i] = i; + counter_page = page; +} + +static void +setup_low_user_desc (void) +{ + low_user_desc = xmmap (NULL, 2 * sizeof (struct user_desc), + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1); + + low_user_desc->entry_number = -1; + low_user_desc->base_addr = (unsigned long) &counter_page[1]; + low_user_desc->limit = 0xffff; + low_user_desc->seg_32bit = 1; + low_user_desc->contents = 0; + low_user_desc->read_exec_only = 0; + low_user_desc->limit_in_pages = 1; + low_user_desc->seg_not_present = 0; + low_user_desc->useable = 0; + + xset_thread_area (low_user_desc); + + low_user_desc_clear = low_user_desc + 1; + low_user_desc_clear->entry_number = gdt_entry_num; + low_user_desc_clear->read_exec_only = 1; + low_user_desc_clear->seg_not_present = 1; +} + +/* Possible values of futex: + 0: thread is idle. + 1: thread armed. + 2: thread should clear LDT entry 0. + 3: thread should exit. */ +static atomic_uint ftx; + +static void * +threadproc (void *ctx) +{ + while (1) + { + futex ((int *) &ftx, FUTEX_WAIT, 1, NULL, NULL, 0); + while (atomic_load (&ftx) != 2) + { + if (atomic_load (&ftx) >= 3) + return NULL; + } + + /* clear LDT entry 0. */ + const struct user_desc desc = { 0 }; + xmodify_ldt (1, &desc, sizeof (desc)); + + /* If ftx == 2, set it to zero, If ftx == 100, quit. */ + if (atomic_fetch_add (&ftx, -2) != 2) + return NULL; + } +} + + +/* As described in testcase, for historical reasons x86_32 Linux (and compat + on x86_64) interprets SA_RESTORER clear with nonzero sa_restorer as a + request for stack switching if the SS segment is 'funny' (this is default + scenario for vDSO system). This means that anything that tries to mix + signal handling with segmentation should explicit clear the sa_restorer. + + This testcase check if sigaction in fact does it by changing the local + descriptor table (LDT) through the modify_ldt syscall and triggering + a synchronous segfault on iret fault by trying to install an invalid + segment. With a correct zeroed sa_restorer it should not trigger an + 'real' SEGSEGV and allows the siglongjmp in signal handler. */ + +static int +do_test (void) +{ + setup_counter_page (); + setup_low_user_desc (); + + pthread_t thread; + unsigned short orig_ss; + + xsethandler (SIGSEGV, sigsegv_handler, 0); + /* 32-bit kernels send SIGILL instead of SIGSEGV on IRET faults. */ + xsethandler (SIGILL, sigsegv_handler, 0); + + thread = xpthread_create (0, threadproc, 0); + + asm volatile ("mov %%ss, %0" : "=rm" (orig_ss)); + + for (int i = 0; i < 5; i++) + { + if (sigsetjmp (jmpbuf, 1) != 0) + continue; + + /* Make sure the thread is ready after the last test. */ + while (atomic_load (&ftx) != 0) + ; + + struct user_desc desc = { + .entry_number = 0, + .base_addr = 0, + .limit = 0xffff, + .seg_32bit = 1, + .contents = 0, + .read_exec_only = 0, + .limit_in_pages = 1, + .seg_not_present = 0, + .useable = 0 + }; + + xmodify_ldt (0x11, &desc, sizeof (desc)); + + /* Arm the thread. */ + ftx = 1; + futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); + + asm volatile ("mov %0, %%ss" : : "r" (0x7)); + + /* Fire up thread modify_ldt call. */ + atomic_store (&ftx, 2); + + while (atomic_load (&ftx) != 0) + ; + + /* On success, modify_ldt will segfault us synchronously and we will + escape via siglongjmp. */ + support_record_failure (); + } + + atomic_store (&ftx, 100); + futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); + + xpthread_join (thread); + + return 0; +} + +#include