PaX: Heritage bug

2015-02-25 Thread Maxime Villard
Hi,
I've found a bug in the way the kernel handles the PaX flags when
loading an ELF binary.

-- kern/exec_elf.c --
#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
l-l_proc-p_pax = epp-ep_pax_flags;
#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */

if (is_dyn)
elf_placedynexec(l, epp, eh, ph);
-

'epp-ep_pax_flags' is set depending on information found in a section
of the binary being loaded. Here, the current proc PaX flag is
overwritten with the new one, and is then used in elf_placedynexec().

The problem here is that this flag is overwritten in the first part of
the loader, and not in the last one. If exec_elf_makecmds() fails, the
kernel returns an error to userland, and the calling process is still
alive. Therefore, it overwrote for free the PaX flag of the current
process.

It means that if the current process is not PaX'ed, and tries to execve
a PaX'ed binary and fails to, it gets tagged as PaX'ed while it is not.

This can lead to several inconsistencies. For example, the mmap syscall
calls pax_aslr(l), which reads the PaX flag on the fly and offsets the
memory.

To trigger the bug, launch a malformed PaX'ed binary with a normal
binary; and then, in this normal binary, call mmap(). With
PAX_ASLR_DEBUG enabled:

m00nbsd$ gcc -Wl,-dynamic-linker,/DEAD_INTERP_PATH -o paxed paxed.c
m00nbsd$ paxctl +A paxed
m00nbsd$ gcc -o launcher launcher.c
m00nbsd$ ./launcher
EXECVE FAILED!
CALLING MMAP
applying to 0x7f7ff7fff000 orig_addr=0x0 f=1002
result 0x7f7ff7fff000
applying to 0x7f7ff7fff000 orig_addr=0x0 f=1002
result 0x7f7ff7fff000
applying to 0x7f7ff7f0 orig_addr=0x0 f=14001002
result 0x7f7ff7f0
execve: -1
applying to 0x7f7ff7fff000 orig_addr=0x0 f=2
result 0x7f7ff7fff000

execve() fails, and the launcher becomes PaX'ed, as testifies the kernel
ASLR output.

Attached is a patch. However I have a doubt: if the kernel loads a
binary, and then its interpreter, the p_pax flag is not used when load-
ing this interpreter, right?

Thanks!
Maxime

Index: kern/exec_elf.c
===
RCS file: /cvsroot/src/sys/kern/exec_elf.c,v
retrieving revision 1.70
diff -u -r1.70 exec_elf.c
--- kern/exec_elf.c 17 Aug 2014 23:03:58 -  1.70
+++ kern/exec_elf.c 24 Feb 2015 15:04:29 -
@@ -116,8 +116,7 @@
 #defineELF_TRUNC(a, b) ((a)  ~((b) - 1))

 static void
-elf_placedynexec(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh,
-Elf_Phdr *ph)
+elf_placedynexec(struct exec_package *epp, Elf_Ehdr *eh, Elf_Phdr *ph)
 {
Elf_Addr align, offset;
int i;
@@ -127,7 +126,7 @@
align = ph[i].p_align;

 #ifdef PAX_ASLR
-   if (pax_aslr_active(l)) {
+   if (pax_aslr_exec_active(epp)) {
size_t pax_align, l2, delta;
uint32_t r;

@@ -722,12 +721,8 @@
pos = (Elf_Addr)startp;
}

-#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
-   l-l_proc-p_pax = epp-ep_pax_flags;
-#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */
-
if (is_dyn)
-   elf_placedynexec(l, epp, eh, ph);
+   elf_placedynexec(epp, eh, ph);

/*
 * Load all the necessary sections
Index: kern/kern_exec.c
===
RCS file: /cvsroot/src/sys/kern/kern_exec.c,v
retrieving revision 1.412
diff -u -r1.412 kern_exec.c
--- kern/kern_exec.c14 Dec 2014 23:49:28 -  1.412
+++ kern/kern_exec.c24 Feb 2015 15:04:29 -
@@ -705,7 +705,7 @@
 */

 #ifdef PAX_ASLR
-#defineASLR_GAP(l) (pax_aslr_active(l) ? (cprng_fast32() % 
PAGE_SIZE) : 0)
+#defineASLR_GAP(l) (pax_aslr_exec_active(epp) ? (cprng_fast32() %
PAGE_SIZE) : 0)
 #else
 #defineASLR_GAP(l) 0
 #endif
@@ -1097,6 +1097,9 @@
/* Remove POSIX timers */
timers_free(p, TIMERS_POSIX);

+   /* Set the PaX flag. No lock needed. */
+   p-p_pax = epp-ep_pax_flags;
+
/*
 * Do whatever is necessary to prepare the address space
 * for remapping.  Note that this might replace the current
Index: kern/kern_pax.c
===
RCS file: /cvsroot/src/sys/kern/kern_pax.c,v
retrieving revision 1.27
diff -u -r1.27 kern_pax.c
--- kern/kern_pax.c 25 Feb 2014 18:30:11 -  1.27
+++ kern/kern_pax.c 24 Feb 2015 15:04:29 -
@@ -284,21 +284,29 @@
 #endif /* PAX_MPROTECT */

 #ifdef PAX_ASLR
-bool
-pax_aslr_active(struct lwp *l)
+static bool
+pax_aslr_is_active(uint32_t f)
 {
-   uint32_t f;
-
if (!pax_aslr_enabled)
return false;
-
-   f = l-l_proc-p_pax;
if ((pax_aslr_global  (f  ELF_NOTE_PAX_NOASLR) != 0) ||
(!pax_aslr_global  (f  

Re: PaX: Heritage bug

2015-02-25 Thread Christos Zoulas
In article 54edb259.7020...@m00nbsd.net,
Maxime Villard  m...@m00nbsd.net wrote:

Attached is a patch. However I have a doubt: if the kernel loads a
binary, and then its interpreter, the p_pax flag is not used when load-
ing this interpreter, right?

I don't see why it can't... Try turning it on.

christos



Re: PaX: Heritage bug

2015-02-25 Thread Maxime Villard
Le 25/02/2015 15:48, Christos Zoulas a écrit :
 In article 54edb259.7020...@m00nbsd.net,
 Maxime Villard  m...@m00nbsd.net wrote:
 
 Attached is a patch. However I have a doubt: if the kernel loads a
 binary, and then its interpreter, the p_pax flag is not used when load-
 ing this interpreter, right?
 
 I don't see why it can't... Try turning it on.

What do you mean?

 
 christos
 


Re: PaX: Heritage bug

2015-02-25 Thread Christos Zoulas
On Feb 25,  4:50pm, m...@m00nbsd.net (Maxime Villard) wrote:
-- Subject: Re: PaX: Heritage bug

|  Attached is a patch. However I have a doubt: if the kernel loads a
|  binary, and then its interpreter, the p_pax flag is not used when load-
|  ing this interpreter, right?
|  
|  I don't see why it can't... Try turning it on.
| 
| What do you mean?

That the location where the interpreter is loaded should be randomized if it
is not. Last time I checked it was.

christos


Re: PaX: Heritage bug

2015-02-25 Thread Maxime Villard
Le 25/02/2015 18:16, Christos Zoulas a écrit :
 On Feb 25,  4:50pm, m...@m00nbsd.net (Maxime Villard) wrote:
 -- Subject: Re: PaX: Heritage bug
 
 |  Attached is a patch. However I have a doubt: if the kernel loads a
 |  binary, and then its interpreter, the p_pax flag is not used when load-
 |  ing this interpreter, right?
 |  
 |  I don't see why it can't... Try turning it on.
 | 
 | What do you mean?
 
 That the location where the interpreter is loaded should be randomized if it
 is not. Last time I checked it was.

elf_load_interp() loads the interpreter. AFAICT, it only adds VMCMDs to
the exec package. So this function does not look like there's actually
something randomized in it.

In my patch, I first set the PaX flag in the exec package - and update
ASLR_GAP() accordingly -, and then I set the proc's p_pax flag just
before processing these VMCMDs.

My question was: is this p_pax flag used in the meantime? From what I've
seen, my answer is no, but in case I miss something...

(and I'm figuring out my ASLR_GAP() change is wrong; it should be:
 #ifdef PAX_ASLR
 #defineASLR_GAP(epp)   (pax_aslr_exec_active(epp) ? (cprng_fast32() %
PAGE_SIZE) : 0)
 #else
 #defineASLR_GAP(epp)   0
 #endif
)



Re: Revisiting DTrace syscall provider

2015-02-25 Thread Ryota Ozaki
Anyway I updated my patches; they're based on latest -current.

Changes since the previous are:
- Remove an unexpected contribution comment from kern_dtrace.c
  (thanks riastradh!)
- Don't unload systrace.kmod when there are users using dtrace
- Add created from line to *_systrace_args.c

http://www.netbsd.org/~ozaki-r/systrace.diff
http://www.netbsd.org/~ozaki-r/systrace-full.diff
https://github.com/ozaki-r/netbsd-src/commits/dtrace-syscall-provider2

Regards,
  ozaki-r