Subject: Re: using an elf note for paxctl instead of os bits...
To: Christos Zoulas <christos@zoulas.com>
From: Jason Thorpe <thorpej@shagadelic.org>
List: tech-kern
Date: 06/13/2007 10:07:30
On Jun 13, 2007, at 9:48 AM, Christos Zoulas wrote:
>
> 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?
Good. Wasting OS bits is bad.
Is this going to get into netbsd-4? If we're going to make this (ABI)
change, we need to push it back to the first pax-aware release branch.
>
>
> 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"
> +);
-- thorpej