Subject: Re: segvguard [was: Re: CVS commit: src/sys/sys]
To: Jason Thorpe <thorpej@shagadelic.org>
From: Elad Efrat <elad@NetBSD.org>
List: tech-kern
Date: 12/03/2006 01:15:53
This is a multi-part message in MIME format.
--Boundary_(ID_D5bFvlqZhiJiqikoG37KJA)
Content-type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: 7BIT
Jason Thorpe wrote:
> No, let's not invent a new ELF phdr type -- we don't control the ELF
> specification, but we do control the contents of our own PT_NOTE fields.
from christos, see attached patch. it moves the PaX flags to the netbsd
PT_NOTE. comments?
-e.
--
Elad Efrat
--Boundary_(ID_D5bFvlqZhiJiqikoG37KJA)
Content-type: text/plain; name=pax-note.diff
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=pax-note.diff
Index: libexec/ld.elf_so/sysident.h
===================================================================
RCS file: /usr/cvs/src/libexec/ld.elf_so/sysident.h,v
retrieving revision 1.13
diff -u -p -r1.13 sysident.h
--- libexec/ld.elf_so/sysident.h 13 Jun 2006 13:55:58 -0000 1.13
+++ libexec/ld.elf_so/sysident.h 1 Dec 2006 21:49:16 -0000
@@ -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"
+);
Index: sys/kern/exec_elf32.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/exec_elf32.c,v
retrieving revision 1.120
diff -u -p -r1.120 exec_elf32.c
--- sys/kern/exec_elf32.c 24 Nov 2006 01:13:11 -0000 1.120
+++ sys/kern/exec_elf32.c 1 Dec 2006 21:48:42 -0000
@@ -692,11 +692,7 @@ exec_elf_makecmds(struct lwp *l, struct
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;
@@ -710,6 +706,10 @@ exec_elf_makecmds(struct lwp *l, struct
}
}
+#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
@@ -764,7 +764,10 @@ netbsd_elf_signature(struct lwp *l, stru
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;
@@ -789,23 +792,37 @@ netbsd_elf_signature(struct lwp *l, stru
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((caddr_t)(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;
Index: sys/kern/kern_pax.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/kern_pax.c,v
retrieving revision 1.8
diff -u -p -r1.8 kern_pax.c
--- sys/kern/kern_pax.c 22 Nov 2006 02:02:51 -0000 1.8
+++ sys/kern/kern_pax.c 1 Dec 2006 21:48:42 -0000
@@ -193,14 +193,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);
}
@@ -208,11 +208,11 @@ 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);
}
Index: sys/sys/exec.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/exec.h,v
retrieving revision 1.114
diff -u -p -r1.114 exec.h
--- sys/sys/exec.h 30 Aug 2006 11:35:21 -0000 1.114
+++ sys/sys/exec.h 1 Dec 2006 21:48:42 -0000
@@ -200,6 +200,7 @@ struct exec_package {
void *ep_emul_arg; /* emulation argument */
const struct execsw *ep_es; /* appropriate execsw entry */
const struct execsw *ep_esch;/* checked execsw entry */
+ uint32_t ep_pax_flags; /* pax flags */
};
#define EXEC_INDIR 0x0001 /* script handling already done */
#define EXEC_HASFD 0x0002 /* holding a shell script */
Index: sys/sys/exec_elf.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/exec_elf.h,v
retrieving revision 1.89
diff -u -p -r1.89 exec_elf.h
--- sys/sys/exec_elf.h 22 Nov 2006 15:08:47 -0000 1.89
+++ sys/sys/exec_elf.h 1 Dec 2006 21:48:42 -0000
@@ -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 */
@@ -686,6 +681,17 @@ typedef struct {
#define ELF_NOTE_CHECKSUM_SHA1 3
#define ELF_NOTE_CHECKSUM_SHA256 4
+/* 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 note name and description sizes */
#define ELF_NOTE_NETBSD_NAMESZ 7
#define ELF_NOTE_NETBSD_DESCSZ 4
Index: sys/sys/pax.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/pax.h,v
retrieving revision 1.5
diff -u -p -r1.5 pax.h
--- sys/sys/pax.h 22 Nov 2006 02:02:51 -0000 1.5
+++ sys/sys/pax.h 1 Dec 2006 21:48:42 -0000
@@ -38,7 +38,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 *);
Index: usr.bin/paxctl/paxctl.c
===================================================================
RCS file: /usr/cvs/src/usr.bin/paxctl/paxctl.c,v
retrieving revision 1.10
diff -u -p -r1.10 paxctl.c
--- usr.bin/paxctl/paxctl.c 22 Nov 2006 15:08:47 -0000 1.10
+++ usr.bin/paxctl/paxctl.c 1 Dec 2006 21:49:16 -0000
@@ -59,13 +59,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]))
@@ -77,10 +81,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
@@ -159,8 +167,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; \
@@ -168,6 +181,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;
@@ -230,41 +248,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;
}
@@ -272,7 +306,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");
--Boundary_(ID_D5bFvlqZhiJiqikoG37KJA)--