All of lore.kernel.org
 help / color / mirror / Atom feed
From: Helge Deller <deller@gmx.de>
To: linux-parisc@vger.kernel.org, vapier@gentoo.org
Subject: Re: ptrace interface does not permit modification of syscall return
Date: Tue, 22 Dec 2015 22:10:56 +0100	[thread overview]
Message-ID: <5679BC60.5090107@gmx.de> (raw)
In-Reply-To: <20151221175558.GA11489@vapier.lan>

[-- Attachment #1: Type: text/plain, Size: 4270 bytes --]

Hi Mike,

On 21.12.2015 18:55, Mike Frysinger wrote:
> i have a ptrace program that watches for specific syscalls and when
> matched, will:
>  - on entry change the syscall nr to -1 (so the kernel will skip it)
>  - on exit change the return to -EPERM so the userspace sees a denial
> 
> i have this working on most arches (x86, x86_64, arm, alpha, ia64, etc...).
> on parisc, the kernel (using 3.18.7 currently) appears to be wrong.  in my
> tests, if i don't mess with the syscall nr, i can change the return value
> fine (to EPERM or whatever).  but the syscall executed which i do not want.
> if i change the syscall to -1, then i can't change the return value (so the
> child sees ENOSYS), but the kernel still executes the original syscall.
> 
> i have a simple test case attached to show the issue.  the code does:
>  - spawn a child with the parent tracing it
>  - child will do:
>   - dupe stderr to another fd
>   - unlink a file named ".test.flag"
>   - write a message through the new fd
>   - close a magic # so the parent knows to start denying
>     - should see EPERM but it sees ENOSYS
>   - close the new fd
>     - should see EPERM but it is closed!
>   - write to the new fd
>     - should work, but the fd is closed
>   - call create on ".test.flag"
>     - should see EPERM, but the file is created!
>  - parent will do:
>   - log the syscalls until child runs close(-12345)
>   - the parent will then try to deny all close/creat calls
>   - uses PTRACE_POKEUSER w/PT_GR20 to set syscall to -1
>   - uses PTRACE_POKEUSER w/PT_GR28 to set return to -EPERM
> 
> you can run the test case by doing:
> $ gcc test.c && ./a.out

I agree, something is fishy :-)

I did some tests with your testcase.
First problem I had was, that compiling failed since it didn't found the asm/offset.h header file.
Which one did you used? I know it usually should come with the kernel headers, but there it is asm-offsets.h.
If you used debian, which package did you installed?

Instead I used asm-offsets.h.
First problem: I had to install the 64bit header file. PT_GR20 in this one was much higher than it should be for 32bit userspace.

So, I used those defines (taken from the strace source package):
#define PT_GR20 (20*4)
#define PT_GR26 (26*4)
#define PT_GR28 (28*4)
#define PT_IAOQ0 (106*4)
#define PT_IAOQ1 (107*4)

With that I got those output:
root@c3000:~# ./a.out
a.out: parent waiting for child (pid=1344) to signal: Success
a.out: child setting up ...
a.out: parent: waiting for exec; status: 0x1a7f
a.out: parent: waiting for exec; status: 0x857f
a.out: parent: hit exec!
a.out: parent: NR: 45 brk
a.out: parent: NR: 59 uname
a.out: parent: NR: 33 access
a.out: parent: NR: 90 mmap
a.out: parent: NR: 33 access
a.out: parent: NR:  5 open
a.out: parent: NR:112 fstat64
a.out: parent: NR: 90 mmap
a.out: parent: NR:  6 close
a.out: parent: NR: 33 access
a.out: parent: NR:  5 open
a.out: parent: NR:  3 read
a.out: parent: NR:112 fstat64
a.out: parent: NR: 90 mmap
a.out: parent: NR: 90 mmap
a.out: parent: NR: 90 mmap
a.out: parent: NR:  6 close
a.out: parent: NR: 90 mmap
a.out: parent: NR:125 mprotect
a.out: parent: NR: 90 mmap
a.out: parent: NR:125 mprotect
a.out: parent: NR: 91 munmap
a.out: parent: NR: 41 dup
a.out: parent: NR: 10 
a.out: parent: NR:  4 write
child: you should see two of these
a.out: parent: NR:  6 close
a.out: parent: setting NR to -1
a.out: parent: forcing EPERM
child: close marker (should be EPERM): Function not implemented
a.out: parent: NR:  4 write
a.out: parent: NR:  6 close
a.out: parent: setting NR to -1
a.out: parent: forcing EPERM
child: real close (should be EPERM): Success
a.out: parent: NR:  4 write
a.out: parent: NR:  4 write
child: write (should be success): Bad file descriptor
a.out: parent: NR:  4 write
a.out: parent: NR:  8 creat
a.out: parent: setting NR to -1
a.out: parent: forcing EPERM
child: creat (should be EPERM): Success
a.out: parent: NR:  4 write
a.out: parent: NR: 33 access
child: access (should be ENOENT): Success
a.out: parent: NR:  4 write
a.out: parent: NR: 10 

Seems not like what it should be.
I need to look closer at it during the next few days.

Regarding on how to get correct 32bit PT_REG #defines/values even on 64bit kernel,
maybe the attached patch is a way to go.

Helge

[-- Attachment #2: pt_reg_32bit.patch --]
[-- Type: text/x-diff, Size: 6943 bytes --]

diff --git a/arch/parisc/include/uapi/asm/ptrace.h b/arch/parisc/include/uapi/asm/ptrace.h
index c4fa6c8..1f2f892 100644
--- a/arch/parisc/include/uapi/asm/ptrace.h
+++ b/arch/parisc/include/uapi/asm/ptrace.h
@@ -33,6 +33,26 @@ struct pt_regs {
 	unsigned long ipsw;	/* CR22 */
 };
 
+#if defined(__LP64__)
+struct compat_pt_regs {
+	unsigned int gr[32];	/* PSW is in gr[0] */
+	__u64 fr[32];
+	unsigned int sr[ 8];
+	unsigned int iasq[2];
+	unsigned int iaoq[2];
+	unsigned int cr27;
+	unsigned int pad0;     /* available for other uses */
+	unsigned int orig_r28;
+	unsigned int ksp;
+	unsigned int kpc;
+	unsigned int sar;	/* CR11 */
+	unsigned int iir;	/* CR19 */
+	unsigned int isr;	/* CR20 */
+	unsigned int ior;	/* CR21 */
+	unsigned int ipsw;	/* CR22 */
+};
+#endif
+
 /*
  * The numbers chosen here are somewhat arbitrary but absolutely MUST
  * not overlap with any of the number assigned in <linux/ptrace.h>.
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index d2f6257..e2a8030 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -240,6 +240,96 @@ int main(void)
 	DEFINE(PT_SIZE, sizeof(struct pt_regs));
 	/* PT_SZ_ALGN includes space for a stack frame. */
 	DEFINE(PT_SZ_ALGN, align_frame(sizeof(struct pt_regs), FRAME_ALIGN));
+#ifdef CONFIG_64BIT
+	COMMENT("for 32bit userspace:");
+	DEFINE(PT_32_PSW, offsetof(struct compat_pt_regs, gr[ 0]));
+	DEFINE(PT_32_GR1, offsetof(struct compat_pt_regs, gr[ 1]));
+	DEFINE(PT_32_GR2, offsetof(struct compat_pt_regs, gr[ 2]));
+	DEFINE(PT_32_GR3, offsetof(struct compat_pt_regs, gr[ 3]));
+	DEFINE(PT_32_GR4, offsetof(struct compat_pt_regs, gr[ 4]));
+	DEFINE(PT_32_GR5, offsetof(struct compat_pt_regs, gr[ 5]));
+	DEFINE(PT_32_GR6, offsetof(struct compat_pt_regs, gr[ 6]));
+	DEFINE(PT_32_GR7, offsetof(struct compat_pt_regs, gr[ 7]));
+	DEFINE(PT_32_GR8, offsetof(struct compat_pt_regs, gr[ 8]));
+	DEFINE(PT_32_GR9, offsetof(struct compat_pt_regs, gr[ 9]));
+	DEFINE(PT_32_GR10, offsetof(struct compat_pt_regs, gr[10]));
+	DEFINE(PT_32_GR11, offsetof(struct compat_pt_regs, gr[11]));
+	DEFINE(PT_32_GR12, offsetof(struct compat_pt_regs, gr[12]));
+	DEFINE(PT_32_GR13, offsetof(struct compat_pt_regs, gr[13]));
+	DEFINE(PT_32_GR14, offsetof(struct compat_pt_regs, gr[14]));
+	DEFINE(PT_32_GR15, offsetof(struct compat_pt_regs, gr[15]));
+	DEFINE(PT_32_GR16, offsetof(struct compat_pt_regs, gr[16]));
+	DEFINE(PT_32_GR17, offsetof(struct compat_pt_regs, gr[17]));
+	DEFINE(PT_32_GR18, offsetof(struct compat_pt_regs, gr[18]));
+	DEFINE(PT_32_GR19, offsetof(struct compat_pt_regs, gr[19]));
+	DEFINE(PT_32_GR20, offsetof(struct compat_pt_regs, gr[20]));
+	DEFINE(PT_32_GR21, offsetof(struct compat_pt_regs, gr[21]));
+	DEFINE(PT_32_GR22, offsetof(struct compat_pt_regs, gr[22]));
+	DEFINE(PT_32_GR23, offsetof(struct compat_pt_regs, gr[23]));
+	DEFINE(PT_32_GR24, offsetof(struct compat_pt_regs, gr[24]));
+	DEFINE(PT_32_GR25, offsetof(struct compat_pt_regs, gr[25]));
+	DEFINE(PT_32_GR26, offsetof(struct compat_pt_regs, gr[26]));
+	DEFINE(PT_32_GR27, offsetof(struct compat_pt_regs, gr[27]));
+	DEFINE(PT_32_GR28, offsetof(struct compat_pt_regs, gr[28]));
+	DEFINE(PT_32_GR29, offsetof(struct compat_pt_regs, gr[29]));
+	DEFINE(PT_32_GR30, offsetof(struct compat_pt_regs, gr[30]));
+	DEFINE(PT_32_GR31, offsetof(struct compat_pt_regs, gr[31]));
+	DEFINE(PT_32_FR0, offsetof(struct compat_pt_regs, fr[ 0]));
+	DEFINE(PT_32_FR1, offsetof(struct compat_pt_regs, fr[ 1]));
+	DEFINE(PT_32_FR2, offsetof(struct compat_pt_regs, fr[ 2]));
+	DEFINE(PT_32_FR3, offsetof(struct compat_pt_regs, fr[ 3]));
+	DEFINE(PT_32_FR4, offsetof(struct compat_pt_regs, fr[ 4]));
+	DEFINE(PT_32_FR5, offsetof(struct compat_pt_regs, fr[ 5]));
+	DEFINE(PT_32_FR6, offsetof(struct compat_pt_regs, fr[ 6]));
+	DEFINE(PT_32_FR7, offsetof(struct compat_pt_regs, fr[ 7]));
+	DEFINE(PT_32_FR8, offsetof(struct compat_pt_regs, fr[ 8]));
+	DEFINE(PT_32_FR9, offsetof(struct compat_pt_regs, fr[ 9]));
+	DEFINE(PT_32_FR10, offsetof(struct compat_pt_regs, fr[10]));
+	DEFINE(PT_32_FR11, offsetof(struct compat_pt_regs, fr[11]));
+	DEFINE(PT_32_FR12, offsetof(struct compat_pt_regs, fr[12]));
+	DEFINE(PT_32_FR13, offsetof(struct compat_pt_regs, fr[13]));
+	DEFINE(PT_32_FR14, offsetof(struct compat_pt_regs, fr[14]));
+	DEFINE(PT_32_FR15, offsetof(struct compat_pt_regs, fr[15]));
+	DEFINE(PT_32_FR16, offsetof(struct compat_pt_regs, fr[16]));
+	DEFINE(PT_32_FR17, offsetof(struct compat_pt_regs, fr[17]));
+	DEFINE(PT_32_FR18, offsetof(struct compat_pt_regs, fr[18]));
+	DEFINE(PT_32_FR19, offsetof(struct compat_pt_regs, fr[19]));
+	DEFINE(PT_32_FR20, offsetof(struct compat_pt_regs, fr[20]));
+	DEFINE(PT_32_FR21, offsetof(struct compat_pt_regs, fr[21]));
+	DEFINE(PT_32_FR22, offsetof(struct compat_pt_regs, fr[22]));
+	DEFINE(PT_32_FR23, offsetof(struct compat_pt_regs, fr[23]));
+	DEFINE(PT_32_FR24, offsetof(struct compat_pt_regs, fr[24]));
+	DEFINE(PT_32_FR25, offsetof(struct compat_pt_regs, fr[25]));
+	DEFINE(PT_32_FR26, offsetof(struct compat_pt_regs, fr[26]));
+	DEFINE(PT_32_FR27, offsetof(struct compat_pt_regs, fr[27]));
+	DEFINE(PT_32_FR28, offsetof(struct compat_pt_regs, fr[28]));
+	DEFINE(PT_32_FR29, offsetof(struct compat_pt_regs, fr[29]));
+	DEFINE(PT_32_FR30, offsetof(struct compat_pt_regs, fr[30]));
+	DEFINE(PT_32_FR31, offsetof(struct compat_pt_regs, fr[31]));
+	DEFINE(PT_32_SR0, offsetof(struct compat_pt_regs, sr[ 0]));
+	DEFINE(PT_32_SR1, offsetof(struct compat_pt_regs, sr[ 1]));
+	DEFINE(PT_32_SR2, offsetof(struct compat_pt_regs, sr[ 2]));
+	DEFINE(PT_32_SR3, offsetof(struct compat_pt_regs, sr[ 3]));
+	DEFINE(PT_32_SR4, offsetof(struct compat_pt_regs, sr[ 4]));
+	DEFINE(PT_32_SR5, offsetof(struct compat_pt_regs, sr[ 5]));
+	DEFINE(PT_32_SR6, offsetof(struct compat_pt_regs, sr[ 6]));
+	DEFINE(PT_32_SR7, offsetof(struct compat_pt_regs, sr[ 7]));
+	DEFINE(PT_32_IASQ0, offsetof(struct compat_pt_regs, iasq[0]));
+	DEFINE(PT_32_IASQ1, offsetof(struct compat_pt_regs, iasq[1]));
+	DEFINE(PT_32_IAOQ0, offsetof(struct compat_pt_regs, iaoq[0]));
+	DEFINE(PT_32_IAOQ1, offsetof(struct compat_pt_regs, iaoq[1]));
+	DEFINE(PT_32_CR27, offsetof(struct compat_pt_regs, cr27));
+	DEFINE(PT_32_ORIG_R28, offsetof(struct compat_pt_regs, orig_r28));
+	DEFINE(PT_32_KSP, offsetof(struct compat_pt_regs, ksp));
+	DEFINE(PT_32_KPC, offsetof(struct compat_pt_regs, kpc));
+	DEFINE(PT_32_SAR, offsetof(struct compat_pt_regs, sar));
+	DEFINE(PT_32_IIR, offsetof(struct compat_pt_regs, iir));
+	DEFINE(PT_32_ISR, offsetof(struct compat_pt_regs, isr));
+	DEFINE(PT_32_IOR, offsetof(struct compat_pt_regs, ior));
+	DEFINE(PT_32_SIZE, sizeof(struct compat_pt_regs));
+	/* PT_32_SZ_ALGN includes space for a stack frame. */
+	DEFINE(PT_32_SZ_ALGN, align_frame(sizeof(struct compat_pt_regs), FRAME_ALIGN));
+#endif
 	BLANK();
 	DEFINE(TI_TASK, offsetof(struct thread_info, task));
 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));

  reply	other threads:[~2015-12-22 21:10 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-21 17:55 ptrace interface does not permit modification of syscall return Mike Frysinger
2015-12-22 21:10 ` Helge Deller [this message]
2015-12-28 18:03   ` Mike Frysinger
2016-01-19 15:11     ` Helge Deller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5679BC60.5090107@gmx.de \
    --to=deller@gmx.de \
    --cc=linux-parisc@vger.kernel.org \
    --cc=vapier@gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.