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