Dear tech,
currently the MAP_CONCEAL flag for mmap(2) can be bypassed with a
stack overflow. FreeBSD introduced a similar flag called MAP_NOCORE.
They also save the auxinfo pointer in some struct that is attached
to the proc struct, similar to the diff below.
Here is an example CTF challenge:
/*
* Setup:
* make mmap
* echo 'this is a well kept secret' > flag.txt
* printf 'flag.txt\0' | ./mmap
* strings mmap.core | grep secret
*/
#include <sys/mman.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
char *
load_file(char *path)
{
char *addr;
int fd;
fd = open(path, O_RDONLY);
if ((addr = mmap((char *)0x40000, 0x100, PROT_READ, MAP_FIXED
| MAP_CONCEAL, fd, 0)) == MAP_FAILED)
err(1, NULL);
close(fd);
return (addr);
}
int
main(void)
{
char file[0x100];
char *buf;
puts("Content-type: text/html\n");
puts("<h1>simple mmap</h1><p>POST filename to /cgi-bin/mmap</p>");
read(0, file, 0x1000);
buf = load_file(file);
printf("load: %p\n", buf);
fflush(stdout);
return (0);
}
With the following python program (on amd64) I can generate an input
string that writes the MAP_CONCEALED content of flag.txt to the
core file:
import struct
p64 = lambda x: struct.pack("<Q", x)
leak=0x40000
pwn = (b"flag.txt" + b"\x00"*8 + (p64(leak) + p64(0) )* 100)
import sys
sys.stdout.buffer.write(pwn)
Below is a diff that addresses this.
OK?
mbuhl
Index: kern/exec_elf.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.174
diff -u -p -r1.174 exec_elf.c
--- kern/exec_elf.c 5 Nov 2022 10:31:16 -0000 1.174
+++ kern/exec_elf.c 6 Nov 2022 13:33:53 -0000
@@ -1221,9 +1221,6 @@ coredump_walk_elf(vaddr_t start, vaddr_t
int
coredump_notes_elf(struct proc *p, void *iocookie, size_t *sizep)
{
- struct ps_strings pss;
- struct iovec iov;
- struct uio uio;
struct elfcore_procinfo cpi;
Elf_Note nhdr;
struct process *pr = p->p_p;
@@ -1282,23 +1279,7 @@ coredump_notes_elf(struct proc *p, void
/* Second, write an NT_OPENBSD_AUXV note. */
notesize = sizeof(nhdr) + elfround(sizeof("OpenBSD")) +
elfround(ELF_AUX_WORDS * sizeof(char *));
- if (iocookie) {
- iov.iov_base = &pss;
- iov.iov_len = sizeof(pss);
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_offset = (off_t)pr->ps_strings;
- uio.uio_resid = sizeof(pss);
- uio.uio_segflg = UIO_SYSSPACE;
- uio.uio_rw = UIO_READ;
- uio.uio_procp = NULL;
-
- error = uvm_io(&p->p_vmspace->vm_map, &uio, 0);
- if (error)
- return (error);
-
- if (pss.ps_envstr == NULL)
- return (EIO);
+ if (iocookie && pr->ps_auxinfo) {
nhdr.namesz = sizeof("OpenBSD");
nhdr.descsz = ELF_AUX_WORDS * sizeof(char *);
@@ -1315,7 +1296,7 @@ coredump_notes_elf(struct proc *p, void
return (error);
error = coredump_write(iocookie, UIO_USERSPACE,
- pss.ps_envstr + pss.ps_nenvstr + 1, nhdr.descsz);
+ (caddr_t)pr->ps_auxinfo, nhdr.descsz);
if (error)
return (error);
}
Index: kern/kern_exec.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.238
diff -u -p -r1.238 kern_exec.c
--- kern/kern_exec.c 30 Oct 2022 17:43:40 -0000 1.238
+++ kern/kern_exec.c 6 Nov 2022 10:37:19 -0000
@@ -492,6 +492,8 @@ sys_execve(struct proc *p, void *v, regi
if (!copyargs(&pack, &arginfo, stack, argp))
goto exec_abort;
+ pr->ps_auxinfo = (vaddr_t)pack.ep_auxinfo;
+
/* copy out the process's ps_strings structure */
if (copyout(&arginfo, (char *)pr->ps_strings, sizeof(arginfo)))
goto exec_abort;
Index: sys/proc.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/sys/proc.h,v
retrieving revision 1.334
diff -u -p -r1.334 proc.h
--- sys/proc.h 23 Jul 2022 22:10:59 -0000 1.334
+++ sys/proc.h 6 Nov 2022 10:37:19 -0000
@@ -215,6 +215,7 @@ struct process {
char ps_comm[_MAXCOMLEN]; /* command name, incl NUL */
vaddr_t ps_strings; /* User pointers to argv/env */
+ vaddr_t ps_auxinfo; /* User pointer to auxinfo */
vaddr_t ps_timekeep; /* User pointer to timekeep */
vaddr_t ps_sigcode; /* [I] User pointer to signal code */
vaddr_t ps_sigcoderet; /* [I] User ptr to sigreturn retPC */