From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15122 invoked by alias); 3 Jul 2012 14:27:38 -0000 Received: (qmail 15105 invoked by uid 22791); 3 Jul 2012 14:27:35 -0000 X-SWARE-Spam-Status: No, hits=-6.3 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,SPF_HELO_PASS,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 03 Jul 2012 14:27:16 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q63ERGFq029614 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 3 Jul 2012 10:27:16 -0400 Received: from host2.jankratochvil.net (ovpn-116-32.ams2.redhat.com [10.36.116.32]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q63ERB2L014440 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for ; Tue, 3 Jul 2012 10:27:14 -0400 Date: Tue, 03 Jul 2012 14:27:00 -0000 From: Jan Kratochvil To: gdb-patches@sourceware.org Subject: [patch] ON_STACK: Warn on buggy Linux i386 kernels Message-ID: <20120703142709.GA21059@host2.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-07/txt/msg00037.txt.bz2 Hi, as discussed in: Possible future NX ON_STACk regression Re: [patch 3/3] Use ON_STACK for i386/amd64 (gdb2495.exp regression) http://sourceware.org/ml/gdb-patches/2012-06/msg00568.html I have found the problem with ON_STACK inferior calls affects only i386 Linux kernels (not x86_64, nor Fedora i386 PAE). It was fixed/removed in Fedora by commit 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd Author: Dave Jones Date: Mon Jun 4 11:56:08 2012 -0400 disable 32bit nx, it seems to be broken http://pkgs.fedoraproject.org/gitweb/?p=kernel.git;a=commitdiff;h=88fa1f0332d188795ed73d7ac2b1564e11a0b4cd http://pkgs.fedoraproject.org/gitweb/?p=kernel.git;a=blob_plain;f=linux-2.6-32bit-mmap-exec-randomization.patch;hb=88fa1f0332d188795ed73d7ac2b1564e11a0b4cd http://pkgs.fedoraproject.org/gitweb/?p=kernel.git;a=blob_plain;f=linux-2.6-i386-nx-emulation.patch;hb=88fa1f0332d188795ed73d7ac2b1564e11a0b4cd http://pkgs.fedoraproject.org/gitweb/?p=kernel.git;a=blob_plain;f=nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch;hb=88fa1f0332d188795ed73d7ac2b1564e11a0b4cd http://pkgs.fedoraproject.org/gitweb/?p=kernel.git;a=blob_plain;f=shlib_base_randomize.patch;hb=88fa1f0332d188795ed73d7ac2b1564e11a0b4cd So the last Fedora kernel where it was reproducible is: kernel-3.4.0-1.fc17.i686 It does not seem to be ever present in upstream ("vanilla") Linux kernels. But I have found ubuntu-12.04-dvd-i386.iso (both GA and latest updates) which is LTS (=still maintained) is also affected by this problem so I expect there maybe vocal feedback. It puts there only a warning. As it is both off-trunk patch and also the patch is present in neither old or new (at least Fedora) kernels and as it does not affect the most basic debugging I did not find it worth a workaround. Rather Ubuntu should provide a fix IMO. Thanks, Jan gdb/ 2012-07-03 Jan Kratochvil * common/linux-ptrace.c: Include gdb_assert.h. <__i386__> (linux_ptrace_test_ret_to_nx_instr): New declaration. <__i386__>: Include sys/reg.h, sys/mman.h, signal.h, sys/wait.h and stdint.h. (linux_ptrace_test_ret_to_nx, linux_ptrace_init_warnings): New functions. * common/linux-ptrace.h (linux_ptrace_init_warnings): New declarations. * linux-nat.c (linux_child_post_attach) (linux_child_post_startup_inferior): Call linux_ptrace_init_warnings. gdb/gdbserver/ 2012-07-03 Jan Kratochvil * gdbserver/linux-low.c (initialize_low): Call linux_ptrace_init_warnings. diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c index 600dcb9..10f77c9 100644 --- a/gdb/common/linux-ptrace.c +++ b/gdb/common/linux-ptrace.c @@ -26,6 +26,7 @@ #include "linux-ptrace.h" #include "linux-procfs.h" #include "buffer.h" +#include "gdb_assert.h" /* Find all possible reasons we could fail to attach PID and append these newline terminated reason strings to initialized BUFFER. '\0' termination @@ -47,3 +48,114 @@ linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer) "- the process has already terminated\n"), (int) pid); } + +#ifdef __i386__ + +/* Address of the 'ret' instruction in asm code block below. */ +extern void (linux_ptrace_test_ret_to_nx_instr) (void); + +#include +#include +#include +#include +#include + +#endif /* __i386__ */ + +/* Test broken off-trunk Linux kernel patchset for NX support on i386. It was + removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd. */ + +static void +linux_ptrace_test_ret_to_nx (void) +{ +#ifdef __i386__ + pid_t child, got_pid; + gdb_byte *return_address, *pc; + long l; + int status; + + return_address = mmap (NULL, 2, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (return_address == MAP_FAILED) + { + warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"), + strerror (errno)); + return; + } + + /* Put there 'int3'. */ + *return_address = 0xcc; + + child = fork (); + switch (child) + { + case -1: + warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"), + strerror (errno)); + return; + + case 0: + l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + if (l != 0) + warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"), + strerror (errno)); + else + { + asm volatile ("pushl %0;" + ".globl linux_ptrace_test_ret_to_nx_instr;" + "linux_ptrace_test_ret_to_nx_instr:" + "ret" + : : "r" (return_address) : "%esp", "memory"); + gdb_assert_not_reached ("asm block did not terminate"); + } + + _exit (1); + } + + got_pid = waitpid (child, &status, 0); + gdb_assert (got_pid == child); + gdb_assert (WIFSTOPPED (status)); + + /* We may get SIGSEGV due to missing PROT_EXEC of the return_address. */ + gdb_assert (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == SIGSEGV); + + errno = 0; + l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (EIP * 4), NULL); + gdb_assert (errno == 0); + pc = (void *) (uintptr_t) l; + + /* + 1 is there as x86* stops after the 'int3' instruction. */ + if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1) + { + /* PASS */ + return; + } + + /* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page. */ + if (WSTOPSIG (status) == SIGSEGV && pc == return_address) + { + /* PASS */ + return; + } + + gdb_assert ((void (*) (void)) pc == &linux_ptrace_test_ret_to_nx_instr); + + warning (_("Cannot call inferior functions, you have broken " + "Linux kernel i386 NX (non-executable pages) support!")); +#endif /* __i386__ */ +} + +/* Display possible problems on this system. Display them only once per GDB + execution. */ + +void +linux_ptrace_init_warnings (void) +{ + static int warned = 0; + + if (warned) + return; + warned = 1; + + linux_ptrace_test_ret_to_nx (); +} diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h index 6315b13..96ad33d 100644 --- a/gdb/common/linux-ptrace.h +++ b/gdb/common/linux-ptrace.h @@ -68,5 +68,6 @@ struct buffer; #endif extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer); +extern void linux_ptrace_init_warnings (void); #endif /* COMMON_LINUX_PTRACE_H */ diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 48134c3..a476031 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -5878,6 +5878,7 @@ initialize_low (void) the_low_target.breakpoint_len); linux_init_signals (); linux_test_for_tracefork (); + linux_ptrace_init_warnings (); #ifdef HAVE_LINUX_REGSETS for (num_regsets = 0; target_regsets[num_regsets].size >= 0; num_regsets++) ; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index b82c248..d3a870f 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -583,6 +583,7 @@ linux_child_post_attach (int pid) { linux_enable_event_reporting (pid_to_ptid (pid)); linux_enable_tracesysgood (pid_to_ptid (pid)); + linux_ptrace_init_warnings (); } static void @@ -590,6 +591,7 @@ linux_child_post_startup_inferior (ptid_t ptid) { linux_enable_event_reporting (ptid); linux_enable_tracesysgood (ptid); + linux_ptrace_init_warnings (); } /* Return the number of known LWPs in the tgid given by PID. */