Subject: using an elf note for paxctl instead of os bits...
To: None <tech-kern@netbsd.org>
From: Christos Zoulas <christos@zoulas.com>
List: tech-kern
Date: 06/13/2007 12:48:44
Hi,
I've been asked by core to provide a diff to use an elf note instead of
the os bits in the elf flags, so that we don't waste the bits. Ultimately
this could use fileassoc, but it is a lot more work. Here's the diff I
am planning to apply. Comments?
christos
Index: sys/kern/exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/kern/exec_elf32.c,v
retrieving revision 1.123
diff -u -u -r1.123 exec_elf32.c
--- sys/kern/exec_elf32.c 22 Apr 2007 08:30:00 -0000 1.123
+++ sys/kern/exec_elf32.c 13 Jun 2007 16:44:35 -0000
@@ -699,11 +699,7 @@
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 @@
}
}
+#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 @@
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 @@
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;
+
+ default:
+ break;
+ }
- next:
+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: /cvsroot/src/sys/kern/kern_pax.c,v
retrieving revision 1.15
diff -u -u -r1.15 kern_pax.c
--- sys/kern/kern_pax.c 22 Feb 2007 06:34:43 -0000 1.15
+++ sys/kern/kern_pax.c 13 Jun 2007 16:44:35 -0000
@@ -200,14 +200,14 @@
}
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 @@
#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: /cvsroot/src/sys/sys/exec.h,v
retrieving revision 1.116
diff -u -u -r1.116 exec.h
--- sys/sys/exec.h 22 Apr 2007 08:30:02 -0000 1.116
+++ sys/sys/exec.h 13 Jun 2007 16:44:39 -0000
@@ -201,6 +201,7 @@
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 */
Index: sys/sys/exec_elf.h
===================================================================
RCS file: /cvsroot/src/sys/sys/exec_elf.h,v
retrieving revision 1.89
diff -u -u -r1.89 exec_elf.h
--- sys/sys/exec_elf.h 22 Nov 2006 15:08:47 -0000 1.89
+++ sys/sys/exec_elf.h 13 Jun 2007 16:44:40 -0000
@@ -346,11 +346,6 @@
#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 @@
/* 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 @@
#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.
Index: sys/sys/pax.h
===================================================================
RCS file: /cvsroot/src/sys/sys/pax.h,v
retrieving revision 1.8
diff -u -u -r1.8 pax.h
--- sys/sys/pax.h 21 Feb 2007 23:00:10 -0000 1.8
+++ sys/sys/pax.h 13 Jun 2007 16:44:40 -0000
@@ -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 *);
Index: usr.sbin/paxctl/paxctl.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/paxctl/paxctl.c,v
retrieving revision 1.1
diff -u -u -r1.1 paxctl.c
--- usr.sbin/paxctl/paxctl.c 30 Jan 2007 19:40:08 -0000 1.1
+++ usr.sbin/paxctl/paxctl.c 13 Jun 2007 16:44:49 -0000
@@ -56,13 +56,17 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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");
Index: libexec/ld.elf_so/sysident.h
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/sysident.h,v
retrieving revision 1.13
diff -u -u -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 13 Jun 2007 16:45:01 -0000
@@ -75,3 +75,17 @@
"\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"
+);