1 /* $NetBSD: paxctl.c,v 1.11 2009/05/02 16:19:36 christos Exp $ */
4 * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
5 * Copyright (c) 2008 Christos Zoulas <christos@NetBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #if HAVE_NBTOOL_CONFIG_H
31 #include "nbtool_config.h"
34 #include <sys/cdefs.h>
37 __RCSID("$NetBSD: paxctl.c,v 1.11 2009/05/02 16:19:36 christos Exp $");
41 #include <sys/types.h>
42 #ifdef HAVE_NBTOOL_CONFIG_H
43 #include "../../sys/sys/exec_elf.h"
54 static void usage(void) __dead
;
55 static uint32_t pax_flag(char);
56 static int pax_flags_sane(uint32_t);
57 static int pax_haveflags(uint32_t);
58 static void pax_printflags(const char *, int, uint32_t);
60 #ifndef ELF_NOTE_TYPE_PAX_TAG
61 /* NetBSD-specific note type: PaX. There should be 1 NOTE per executable.
62 section. desc is a 32 bit bitmask */
63 #define ELF_NOTE_TYPE_PAX_TAG 3
64 #define ELF_NOTE_PAX_MPROTECT 0x01 /* Force enable MPROTECT */
65 #define ELF_NOTE_PAX_NOMPROTECT 0x02 /* Force disable MPROTECT */
66 #define ELF_NOTE_PAX_GUARD 0x04 /* Force enable Segvguard */
67 #define ELF_NOTE_PAX_NOGUARD 0x08 /* Force disable Segvguard */
68 #define ELF_NOTE_PAX_ASLR 0x10 /* Force enable ASLR */
69 #define ELF_NOTE_PAX_NOASLR 0x20 /* Force disable ASLR */
70 #define ELF_NOTE_PAX_NAMESZ 4
71 #define ELF_NOTE_PAX_NAME "PaX\0"
72 #define ELF_NOTE_PAX_DESCSZ 4
75 #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
79 static const struct paxflag
{
84 { 'A', "ASLR, explicit enable",
86 { 'a', "ASLR, explicit disable",
87 ELF_NOTE_PAX_NOASLR
},
88 { 'G', "Segvguard, explicit enable",
90 { 'g', "Segvguard, explicit disable",
91 ELF_NOTE_PAX_NOGUARD
},
92 { 'M', "mprotect(2) restrictions, explicit enable",
93 ELF_NOTE_PAX_MPROTECT
},
94 { 'm', "mprotect(2) restrictions, explicit disable",
95 ELF_NOTE_PAX_NOMPROTECT
},
101 (void)fprintf(stderr
, "Usage: %s [ <-|+><A|a|G|g|M|m> ] <file> ...\n",
102 #if HAVE_NBTOOL_CONFIG_H
119 for (i
= 0; i
< __arraycount(flags
); i
++)
120 if (s
== flags
[i
].mark
)
121 return flags
[i
].bits
;
127 pax_flags_sane(uint32_t f
)
131 for (i
= 0; i
< __arraycount(flags
) - 1; i
+= 2) {
132 uint32_t g
= flags
[i
].bits
| flags
[i
+1].bits
;
141 pax_haveflags(uint32_t f
)
145 for (i
= 0; i
< __arraycount(flags
); i
++)
146 if (f
& flags
[i
].bits
)
153 pax_printflags(const char *name
, int many
, uint32_t f
)
157 for (i
= 0; i
< __arraycount(flags
); i
++)
158 if (f
& flags
[i
].bits
) {
160 (void)printf("%s: ", name
);
161 (void)printf(" %c: %s\n",
162 flags
[i
].mark
, flags
[i
].name
);
167 process_one(const char *name
, uint32_t add_flags
, uint32_t del_flags
,
182 #define SWAP(a) (swap == 0 ? (a) : \
183 /*LINTED*/(sizeof(a) == 1 ? (a) : \
184 /*LINTED*/(sizeof(a) == 2 ? bswap16(a) : \
185 /*LINTED*/(sizeof(a) == 4 ? bswap32(a) : \
186 /*LINTED*/(sizeof(a) == 8 ? bswap64(a) : (abort(), (a)))))))
187 #define EH(field) (size == 32 ? SWAP(e.h32.field) : SWAP(e.h64.field))
188 #define SH(field) (size == 32 ? SWAP(s.h32.field) : SWAP(s.h64.field))
189 #define NH(field) (size == 32 ? SWAP(n.h32.field) : SWAP(n.h64.field))
190 #define SHSIZE (size == 32 ? sizeof(s.h32) : sizeof(s.h64))
191 #define NHSIZE (size == 32 ? sizeof(n.h32) : sizeof(n.h64))
193 char name
[ELF_NOTE_PAX_NAMESZ
];
196 int fd
, size
, ok
= 0, flagged
= 0, swap
, error
= 1;
199 fd
= open(name
, list
? O_RDONLY
: O_RDWR
, 0);
201 warn("Can't open `%s'", name
);
205 if (read(fd
, &e
, sizeof(e
)) != sizeof(e
)) {
206 warn("Can't read ELF header from `%s'", name
);
210 if (memcmp(e
.h32
.e_ident
, ELFMAG
, SELFMAG
) != 0) {
211 warnx("Bad ELF magic from `%s' (maybe it's not an ELF?)", name
);
215 if (e
.h32
.e_ehsize
== sizeof(e
.h32
)) {
218 } else if (e
.h64
.e_ehsize
== sizeof(e
.h64
)) {
221 } else if (bswap16(e
.h32
.e_ehsize
) == sizeof(e
.h32
)) {
224 } else if (bswap16(e
.h64
.e_ehsize
) == sizeof(e
.h64
)) {
228 warnx("Bad ELF size %d from `%s' (maybe it's not an ELF?)",
229 (int)e
.h32
.e_ehsize
, name
);
233 for (i
= 0; i
< EH(e_shnum
); i
++) {
234 if ((size_t)pread(fd
, &s
, SHSIZE
,
235 (off_t
)EH(e_shoff
) + i
* SHSIZE
) != SHSIZE
) {
236 warn("Can't read section header data from `%s'", name
);
240 if (SH(sh_type
) != SHT_NOTE
)
243 if (pread(fd
, &n
, NHSIZE
, (off_t
)SH(sh_offset
)) != NHSIZE
) {
244 warn("Can't read note header from `%s'", name
);
247 if (NH(n_type
) != ELF_NOTE_TYPE_PAX_TAG
||
248 NH(n_descsz
) != ELF_NOTE_PAX_DESCSZ
||
249 NH(n_namesz
) != ELF_NOTE_PAX_NAMESZ
)
251 if (pread(fd
, &pax_tag
, sizeof(pax_tag
), SH(sh_offset
) + NHSIZE
)
252 != sizeof(pax_tag
)) {
253 warn("Can't read pax_tag from `%s'", name
);
256 if (memcmp(pax_tag
.name
, ELF_NOTE_PAX_NAME
,
257 sizeof(pax_tag
.name
)) != 0) {
258 warn("Unknown pax_tag name `%*.*s' from `%s'",
259 ELF_NOTE_PAX_NAMESZ
, ELF_NOTE_PAX_NAMESZ
,
266 if (!pax_haveflags(SWAP(pax_tag
.flags
)))
269 if (!pax_flags_sane(SWAP(pax_tag
.flags
)))
270 warnx("Current flags 0x%x don't make sense",
271 (uint32_t)SWAP(pax_tag
.flags
));
274 (void)printf("%s: ", name
);
275 (void)printf("PaX flags:\n");
277 pax_printflags(name
, many
, SWAP(pax_tag
.flags
));
282 pax_tag
.flags
|= SWAP(add_flags
);
283 pax_tag
.flags
&= SWAP(~del_flags
);
285 if (!pax_flags_sane(SWAP(pax_tag
.flags
))) {
286 warnx("New flags 0x%x don't make sense",
287 (uint32_t)SWAP(pax_tag
.flags
));
291 if (pwrite(fd
, &pax_tag
, sizeof(pax_tag
),
292 (off_t
)SH(sh_offset
) + NHSIZE
) != sizeof(pax_tag
))
293 warn("Can't modify flags on `%s'", name
);
298 warnx("Could not find an ELF PaX SHT_NOTE section in `%s'",
304 if (list
&& !flagged
) {
306 (void)printf("%s: ", name
);
307 (void)printf("No PaX flags.\n");
315 main(int argc
, char **argv
)
318 int i
, list
= 0, bad
= 0, many
, minus
;
319 uint32_t add_flags
= 0, del_flags
= 0;
321 setprogname(argv
[0]);
326 for (i
= 1; i
< argc
; i
++) {
329 if (*opt
== '-' || *opt
== '+') {
347 t
= pax_flag(*opt
++);
348 if (t
== (uint32_t)-1)
364 if (add_flags
|| del_flags
) {
370 many
= i
!= argc
- 1;
371 for (; i
< argc
; i
++)
372 bad
|= process_one(argv
[i
], add_flags
, del_flags
, list
, many
);
374 return bad
? EXIT_FAILURE
: 0;