Use an elf note to handle pax arguments. This is a temporary solution to

avoid wasting OS flag bits. In the future we'll probably use fileassoc to
achieve this (once there is a way to make fileassoc persistent) or in the
shorter term libelf, so that we can add and remove the note on demand instead
of burning bits on each binary. Of course since this is a tool, this means
that we'll need to think about how to handle libelf...
This commit is contained in:
christos 2007-06-24 20:35:36 +00:00
parent e0e4b56127
commit 2ffe4b875f
7 changed files with 140 additions and 67 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysident.h,v 1.13 2006/06/13 13:55:58 simonb Exp $ */
/* $NetBSD: sysident.h,v 1.14 2007/06/24 20:35:36 christos Exp $ */
/*
* Copyright (c) 1997 Christopher G. Demetriou
@ -75,3 +75,17 @@ __asm(
"\t.previous\n"
"\t.p2align\t2\n"
);
__asm(
".section\t\".note.netbsd.pax\", \"a\"\n"
"\t.p2align\t2\n\n"
"\t.long\t" __S(ELF_NOTE_PAX_NAMESZ) "\n"
"\t.long\t" __S(ELF_NOTE_PAX_DESCSZ) "\n"
"\t.long\t" __S(ELF_NOTE_TYPE_PAX_TAG) "\n"
"\t.ascii\t" __S(ELF_NOTE_PAX_NAME) "\n"
"\t.long\t" __S(0) "\n\n"
"\t.previous\n"
"\t.p2align\t2\n"
);

View File

@ -1,4 +1,4 @@
/* $NetBSD: exec_elf32.c,v 1.123 2007/04/22 08:30:00 dsl Exp $ */
/* $NetBSD: exec_elf32.c,v 1.124 2007/06/24 20:35:37 christos Exp $ */
/*-
* Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc.
@ -64,7 +64,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.123 2007/04/22 08:30:00 dsl Exp $");
__KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.124 2007/06/24 20:35:37 christos Exp $");
/* If not included by exec_elf64.c, ELFSIZE won't be defined. */
#ifndef ELFSIZE
@ -699,11 +699,7 @@ exec_elf_makecmds(struct lwp *l, struct exec_package *epp)
case PT_DYNAMIC:
break;
case PT_NOTE:
#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
pax_adjust(l, ph[i].p_flags);
#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
break;
case PT_PHDR:
/* Note address of program headers (in text segment) */
phdr = pp->p_vaddr;
@ -717,6 +713,11 @@ exec_elf_makecmds(struct lwp *l, struct exec_package *epp)
}
}
#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
if (epp->ep_pax_flags)
pax_adjust(l, epp->ep_pax_flags);
#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
/*
* Check if we found a dynamically linked binary and arrange to load
* its interpreter
@ -771,7 +772,10 @@ netbsd_elf_signature(struct lwp *l, struct exec_package *epp,
Elf_Phdr *ph;
size_t phsize;
int error;
int isnetbsd = 0;
char *ndata;
epp->ep_pax_flags = 0;
if (eh->e_phnum > MAXPHNUM)
return ENOEXEC;
@ -796,23 +800,38 @@ netbsd_elf_signature(struct lwp *l, struct exec_package *epp,
if (error)
goto next;
if (np->n_type != ELF_NOTE_TYPE_NETBSD_TAG ||
np->n_namesz != ELF_NOTE_NETBSD_NAMESZ ||
np->n_descsz != ELF_NOTE_NETBSD_DESCSZ ||
memcmp(np + 1, ELF_NOTE_NETBSD_NAME,
ELF_NOTE_NETBSD_NAMESZ))
goto next;
ndata = (char *)(np + 1);
switch (np->n_type) {
case ELF_NOTE_TYPE_NETBSD_TAG:
if (np->n_namesz != ELF_NOTE_NETBSD_NAMESZ ||
np->n_descsz != ELF_NOTE_NETBSD_DESCSZ ||
memcmp(ndata, ELF_NOTE_NETBSD_NAME,
ELF_NOTE_NETBSD_NAMESZ))
goto next;
isnetbsd = 1;
break;
error = 0;
free(np, M_TEMP);
goto out;
case ELF_NOTE_TYPE_PAX_TAG:
if (np->n_namesz != ELF_NOTE_PAX_NAMESZ ||
np->n_descsz != ELF_NOTE_PAX_DESCSZ ||
memcmp(ndata, ELF_NOTE_PAX_NAME,
ELF_NOTE_PAX_NAMESZ))
goto next;
(void)memcpy(&epp->ep_pax_flags,
ndata + ELF_NOTE_PAX_NAMESZ,
sizeof(epp->ep_pax_flags));
break;
next:
default:
break;
}
next:
free(np, M_TEMP);
continue;
}
error = ENOEXEC;
error = isnetbsd ? 0 : ENOEXEC;
out:
free(ph, M_TEMP);
return error;

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_pax.c,v 1.15 2007/02/22 06:34:43 thorpej Exp $ */
/* $NetBSD: kern_pax.c,v 1.16 2007/06/24 20:35:37 christos Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@ -200,14 +200,14 @@ pax_init(void)
}
void
pax_adjust(struct lwp *l, int f)
pax_adjust(struct lwp *l, uint32_t f)
{
#ifdef PAX_MPROTECT
if (pax_mprotect_enabled) {
if (f & PF_PAXMPROTECT)
if (f & ELF_NOTE_PAX_MPROTECT)
proc_setspecific(l->l_proc, pax_mprotect_key,
PAX_MPROTECT_EXPLICIT_ENABLE);
if (f & PF_PAXNOMPROTECT)
if (f & ELF_NOTE_PAX_NOMPROTECT)
proc_setspecific(l->l_proc, pax_mprotect_key,
PAX_MPROTECT_EXPLICIT_DISABLE);
}
@ -215,11 +215,10 @@ pax_adjust(struct lwp *l, int f)
#ifdef PAX_SEGVGUARD
if (pax_segvguard_enabled) {
if (f & PF_PAXGUARD) {
if (f & ELF_NOTE_PAX_GUARD)
proc_setspecific(l->l_proc, pax_segvguard_key,
PAX_SEGVGUARD_EXPLICIT_ENABLE);
}
if (f & PF_PAXNOGUARD)
if (f & ELF_NOTE_PAX_NOGUARD)
proc_setspecific(l->l_proc, pax_segvguard_key,
PAX_SEGVGUARD_EXPLICIT_DISABLE);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: exec.h,v 1.116 2007/04/22 08:30:02 dsl Exp $ */
/* $NetBSD: exec.h,v 1.117 2007/06/24 20:35:37 christos Exp $ */
/*-
* Copyright (c) 1992, 1993
@ -201,6 +201,7 @@ struct exec_package {
const struct execsw *ep_esch;/* execsw entry */
struct vnode *ep_emul_root; /* base of emulation filesystem */
struct vnode *ep_interp; /* vnode of (elf) interpeter */
uint32_t ep_pax_flags; /* pax flags */
};
#define EXEC_INDIR 0x0001 /* script handling already done */
#define EXEC_HASFD 0x0002 /* holding a shell script */

View File

@ -1,4 +1,4 @@
/* $NetBSD: exec_elf.h,v 1.89 2006/11/22 15:08:47 riz Exp $ */
/* $NetBSD: exec_elf.h,v 1.90 2007/06/24 20:35:37 christos Exp $ */
/*-
* Copyright (c) 1994 The NetBSD Foundation, Inc.
@ -346,11 +346,6 @@ typedef struct {
#define PF_W 0x2 /* Segment is writable */
#define PF_X 0x1 /* Segment is executable */
#define PF_PAXMPROTECT 0x08000000 /* Explicitly enable PaX MPROTECT */
#define PF_PAXNOMPROTECT 0x04000000 /* Explicitly disable PaX MPROTECT */
#define PF_PAXGUARD 0x02000000 /* Explicitly enable PaX Segvguard */
#define PF_PAXNOGUARD 0x01000000 /* Explicitly disable PaX Segvguard */
#define PF_MASKOS 0x0ff00000 /* Operating system specific values */
#define PF_MASKPROC 0xf0000000 /* Processor-specific values */
@ -678,6 +673,12 @@ typedef struct {
/* NetBSD-specific note type: Emulation name. desc is emul name string. */
#define ELF_NOTE_TYPE_NETBSD_TAG 1
/* NetBSD-specific note name and description sizes */
#define ELF_NOTE_NETBSD_NAMESZ 7
#define ELF_NOTE_NETBSD_DESCSZ 4
/* NetBSD-specific note name */
#define ELF_NOTE_NETBSD_NAME "NetBSD\0\0"
/* NetBSD-specific note type: Checksum. There should be 1 NOTE per PT_LOAD
section. desc is a tuple of <phnum>(16),<chk-type>(16),<chk-value>. */
#define ELF_NOTE_TYPE_CHECKSUM_TAG 2
@ -686,11 +687,16 @@ typedef struct {
#define ELF_NOTE_CHECKSUM_SHA1 3
#define ELF_NOTE_CHECKSUM_SHA256 4
/* NetBSD-specific note name and description sizes */
#define ELF_NOTE_NETBSD_NAMESZ 7
#define ELF_NOTE_NETBSD_DESCSZ 4
/* NetBSD-specific note name */
#define ELF_NOTE_NETBSD_NAME "NetBSD\0\0"
/* NetBSD-specific note type: PaX. There should be 1 NOTE per executable.
section. desc is a 32 bit bitmask */
#define ELF_NOTE_TYPE_PAX_TAG 3
#define ELF_NOTE_PAX_MPROTECT 0x1 /* Force enable Mprotect */
#define ELF_NOTE_PAX_NOMPROTECT 0x2 /* Force disable Mprotect */
#define ELF_NOTE_PAX_GUARD 0x4 /* Force enable Segvguard */
#define ELF_NOTE_PAX_NOGUARD 0x8 /* Force disable Servguard */
#define ELF_NOTE_PAX_NAMESZ 4
#define ELF_NOTE_PAX_NAME "PaX\0"
#define ELF_NOTE_PAX_DESCSZ 4
/*
* NetBSD-specific core file information.

View File

@ -1,4 +1,4 @@
/* $NetBSD: pax.h,v 1.8 2007/02/21 23:00:10 thorpej Exp $ */
/* $NetBSD: pax.h,v 1.9 2007/06/24 20:35:37 christos Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@ -35,7 +35,7 @@
struct lwp;
void pax_init(void);
void pax_adjust(struct lwp *, int);
void pax_adjust(struct lwp *, uint32_t);
void pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: paxctl.c,v 1.1 2007/01/30 19:40:08 elad Exp $ */
/* $NetBSD: paxctl.c,v 1.2 2007/06/24 20:35:36 christos Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@ -33,7 +33,7 @@
#include <sys/cdefs.h>
#ifndef lint
#ifdef __RCSID
__RCSID("$NetBSD: paxctl.c,v 1.1 2007/01/30 19:40:08 elad Exp $");
__RCSID("$NetBSD: paxctl.c,v 1.2 2007/06/24 20:35:36 christos Exp $");
#endif
#endif /* not lint */
@ -56,13 +56,17 @@ static int pax_flags_sane(u_long);
static int pax_haveflags(u_long);
static void pax_printflags(u_long);
#ifndef PF_PAXMPROTECT
#define PF_PAXMPROTECT 0x08000000
#define PF_PAXNOMPROTECT 0x04000000
#endif
#ifndef PF_PAXGUARD
#define PF_PAXGUARD 0x02000000
#define PF_PAXNOGUARD 0x01000000
#ifndef ELF_NOTE_TYPE_PAX_TAG
/* NetBSD-specific note type: PaX. There should be 1 NOTE per executable.
section. desc is a 32 bit bitmask */
#define ELF_NOTE_TYPE_PAX_TAG 3
#define ELF_NOTE_PAX_MPROTECT 0x1 /* Force enable Mprotect */
#define ELF_NOTE_PAX_NOMPROTECT 0x2 /* Force disable Mprotect */
#define ELF_NOTE_PAX_GUARD 0x4 /* Force enable Segvguard */
#define ELF_NOTE_PAX_NOGUARD 0x8 /* Force disable Servguard */
#define ELF_NOTE_PAX_NAMESZ 4
#define ELF_NOTE_PAX_NAME "PaX\0"
#define ELF_NOTE_PAX_DESCSZ 4
#endif
#ifndef __arraycount
#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
@ -74,10 +78,14 @@ static const struct paxflag {
const char *name;
int bits;
} flags[] = {
{ 'G', "Segvguard, explicit enable", PF_PAXGUARD },
{ 'g', "Segvguard, explicit disable", PF_PAXNOGUARD },
{ 'M', "mprotect(2) restrictions, explicit enable", PF_PAXMPROTECT },
{ 'm', "mprotect(2) restrictions, explicit disable", PF_PAXNOMPROTECT },
{ 'G', "Segvguard, explicit enable",
ELF_NOTE_PAX_GUARD },
{ 'g', "Segvguard, explicit disable",
ELF_NOTE_PAX_NOGUARD },
{ 'M', "mprotect(2) restrictions, explicit enable",
ELF_NOTE_PAX_MPROTECT },
{ 'm', "mprotect(2) restrictions, explicit disable",
ELF_NOTE_PAX_NOMPROTECT },
};
static void
@ -156,8 +164,13 @@ main(int argc, char **argv)
Elf32_Phdr h32;
Elf64_Phdr h64;
} p;
union {
Elf32_Nhdr h32;
Elf64_Nhdr h64;
} n;
#define EH(field) (size == 32 ? e.h32.field : e.h64.field)
#define PH(field) (size == 32 ? p.h32.field : p.h64.field)
#define NH(field) (size == 32 ? n.h32.field : n.h64.field)
#define SPH(field, val) do { \
if (size == 32) \
p.h32.field val; \
@ -165,6 +178,11 @@ main(int argc, char **argv)
p.h64.field val; \
} while (/*CONSTCOND*/0)
#define PHSIZE (size == 32 ? sizeof(p.h32) : sizeof(p.h64))
#define NHSIZE (size == 32 ? sizeof(n.h32) : sizeof(n.h64))
struct {
char name[ELF_NOTE_PAX_NAMESZ];
uint32_t flags;
} pax_tag;
int size;
char *opt = NULL;
@ -227,41 +245,57 @@ main(int argc, char **argv)
for (i = 0; i < EH(e_phnum); i++) {
if (pread(fd, &p, PHSIZE,
(off_t)EH(e_phoff) + i * PHSIZE) != PHSIZE)
err(EXIT_FAILURE, "Can't read data from `%s'", opt);
err(EXIT_FAILURE, "Can't read program header data"
" from `%s'", opt);
if (PH(p_type) != PT_NOTE)
continue;
if (pread(fd, &n, NHSIZE, (off_t)PH(p_offset)) != NHSIZE)
err(EXIT_FAILURE, "Can't read note header from `%s'",
opt);
if (NH(n_type) != ELF_NOTE_TYPE_PAX_TAG ||
NH(n_descsz) != ELF_NOTE_PAX_DESCSZ ||
NH(n_namesz) != ELF_NOTE_PAX_NAMESZ)
continue;
if (pread(fd, &pax_tag, sizeof(pax_tag), PH(p_offset) + NHSIZE)
!= sizeof(pax_tag))
err(EXIT_FAILURE, "Can't read pax_tag from `%s'",
opt);
if (memcmp(pax_tag.name, ELF_NOTE_PAX_NAME,
sizeof(pax_tag.name)) != 0)
err(EXIT_FAILURE, "Unknown pax_tag name `%*.*s' from"
" `%s'", ELF_NOTE_PAX_NAMESZ, ELF_NOTE_PAX_NAMESZ,
pax_tag.name, opt);
ok = 1;
if (list) {
if (!pax_haveflags((u_long)PH(p_flags)))
if (!pax_haveflags(pax_tag.flags))
break;
if (!pax_flags_sane((u_long)PH(p_flags)))
warnx("Current flags %lx don't make sense",
(u_long)PH(p_flags));
if (!pax_flags_sane(pax_tag.flags))
warnx("Current flags %x don't make sense",
pax_tag.flags);
(void)printf("PaX flags:\n");
pax_printflags((u_long)PH(p_flags));
pax_printflags(pax_tag.flags);
flagged = 1;
break;
}
SPH(p_flags, |= add_flags);
SPH(p_flags, &= ~del_flags);
pax_tag.flags |= add_flags;
pax_tag.flags &= ~del_flags;
if (!pax_flags_sane((u_long)PH(p_flags)))
errx(EXIT_FAILURE, "New flags %lx don't make sense",
(u_long)PH(p_flags));
if (!pax_flags_sane(pax_tag.flags))
errx(EXIT_FAILURE, "New flags %x don't make sense",
pax_tag.flags);
if (pwrite(fd, &p, PHSIZE,
(off_t)EH(e_phoff) + i * PHSIZE) != PHSIZE)
if (pwrite(fd, &pax_tag, sizeof(pax_tag),
(off_t)PH(p_offset) + NHSIZE) != sizeof(pax_tag))
err(EXIT_FAILURE, "Can't modify flags on `%s'", opt);
break;
}
@ -269,7 +303,7 @@ main(int argc, char **argv)
if (!ok)
errx(EXIT_FAILURE,
"Could not find an ELF PT_NOTE section in `%s'", opt);
"Could not find an ELF PaX PT_NOTE section in `%s'", opt);
if (list && !flagged)
(void)printf("No PaX flags.\n");