Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37561583
en ru br
Репозитории ALT
S:0.9-alt1
5.1: 0.5-alt1
www.altlinux.org/Changes

Группа :: Система/Настройка/Прочее
Пакет: paxctl

 Главная   Изменения   Спек   Патчи   Исходники   Загрузить   Gear   Bugs and FR  Repocop 

paxctl-0.5/000075500000000000000000000000001121201167700126455ustar00rootroot00000000000000paxctl-0.5/ChangeLog000064400000000000000000000020231121201167700144140ustar00rootroot000000000000002007.04.16 PaX Team <pageexec@freemail.hu>
fixed section header offset handling in stripped binaries,
thanks to Ned Ludd <solar@gentoo.org>

2006.12.12 PaX Team <pageexec@freemail.hu>
use /usr/bin/install for install target
macro'ize elf_modify_phdr to unify Elf32/Elf64 handling

2006.07.22 PaX Team <pageexec@freemail.hu>
added program header extension (chpax is no longer neeeded),
thanks to Kevin F. Quinn <co@kevquinn.com> & Ned Ludd <solar@gentoo.org>

2006.06.17 PaX Team <pageexec@freemail.hu>
fixed code for gcc 2.95, thanks to Ned Ludd <solar@gentoo.org>

2006.04.29 PaX Team <pageexec@freemail.hu>
fixed compilation on systems where PT_GNU_STACK is not defined,
thanks to Ned Ludd <solar@gentoo.org>

2005.05.29 PaX Team <pageexec@freemail.hu>
cleaned up error code reporting, thanks to Kevin F. Quinn <co@kevquinn.com>

2005.05.03 PaX Team <pageexec@freemail.hu>
added -c option to convert PT_GNU_STACK into PT_PAX_FLAGS
minor typo fixes in the code/manpage

2004.02.10 PaX Team <pageexec@freemail.hu>
initial release
paxctl-0.5/Makefile000064400000000000000000000015461121201167700143130ustar00rootroot00000000000000CC:=gcc
CP:=cp
CFLAGS:=-Os -ggdb -Wall -W -Wcast-qual -Wcast-align -Wbad-function-cast -Wshadow -Wwrite-strings -Wnested-externs -Winline -Wredundant-decls -Waggregate-return -Wformat=2 -Wpointer-arith -Wconversion -Wmissing-declarations -Wmissing-prototypes
# -Wunreachable-code -Wdisabled-optimization
DESTDIR:=
LDFLAGS:=
MANDIR:=/usr/share/man/man1
#MKDIR:=mkdir -p
INSTALL:=install
PROG:=paxctl
RM:=rm

all: $(PROG)

$(PROG): $(PROG).o
$(CC) $(LDFLAGS) -o $@ $<

$(PROG).o: $(PROG).c $(PROG).h
$(CC) -c $(CFLAGS) -o $@ $<

install: $(PROG)
# $(MKDIR) $(DESTDIR)/sbin $(DESTDIR)$(MANDIR)
# $(CP) $(PROG) $(DESTDIR)/sbin
# $(CP) $(PROG).1 $(DESTDIR)$(MANDIR)
$(INSTALL) -D --owner 0 --group 0 --mode a=rx $(PROG) $(DESTDIR)/sbin/$(PROG)
$(INSTALL) -D --owner 0 --group 0 --mode a=r $(PROG).1 $(DESTDIR)/$(MANDIR)/$(PROG).1

clean:
$(RM) -f $(PROG) $(PROG).o core
paxctl-0.5/README000064400000000000000000000020651121201167700135300ustar00rootroot000000000000001. What it is

This is paxctl for controlling PaX flags on a per binary basis. PaX
is an intrusion prevention system that provides the best protection
mechanisms against memory corruption bugs. Some applications are not
compatible with certain features (due to design or bad engineering)
and therefore they have to be exempted from certain enforcements. It
is also possible to use PaX in soft mode where none of the protection
mechanisms are active by default - here paxctl can be used to turn
them on for selected programs (e.g., network daemons, programs that
process network data such as mail clients, web browsers, etc).

PaX and paxctl work on ELF executables, both of the standard ET_EXEC
and the newer ET_DYN kind (older PaX releases referred to the latter
as ET_DYN executables, these days they are called Position Independent
Executables or PIEs for short).


2. Installation

Simply issue 'make' then 'make install'. If the defaults do not suit
your needs, change them in the Makefile.


3. References

PaX - http://pax.grsecurity.net
paxctl-0.5/paxctl.1000064400000000000000000000056101121201167700142240ustar00rootroot00000000000000.TH paxctl 1 2006-06-18 "paxctl Manual" "PaX"
.SH NAME
\fBpaxctl\fR - user-space utility to control PaX flags
.SH SYNTAX
\fBpaxctl\fR <flags> <files>
.SH DESCRIPTION
\fBpaxctl\fR is a tool that allows PaX flags to be modified
on a per-binary basis. PaX is part of common security-enhancing
kernel patches and secure distributions, such as GrSecurity or
Adamantix and Hardened Gentoo, respectively. Your system needs
to be running a properly patched and configured kernel for
this program to have any effect.
.TP
\fB-P\fR
enforce paging based non-executable pages (PAGEEXEC)
.TP
\fB-p\fR
do not enforce paging based non-executable pages (NOPAGEEXEC)
.TP
\fB-E\fR
emulate trampolines (EMUTRAMP)
.TP
\fB-e\fR
do not emulate trampolines (NOEMUTRAMP)
.TP
\fB-M\fR
enforce secure memory protections (MPROTECT)
.TP
\fB-m\fR
do not enforce secure memory protections (NOMPROTECT)
.TP
\fB-R\fR
randomize memory regions (RANDMMAP)
.TP
\fB-r\fR
do not randomize memory regions (NORANDMMAP)
.TP
\fB-X\fR
randomize base address of normal (ET_EXEC) executables (RANDEXEC)
.TP
\fB-x\fR
do not randomize base address of normal (ET_EXEC) executables (NORANDEXEC)
.TP
\fB-S\fR
enforce segmentation based non-executable pages (SEGMEXEC)
.TP
\fB-s\fR
do not enforce segmentation based non-executable pages (NOSEGMEXEC)
.TP
\fB-v\fR
view flags
.TP
\fB-z\fR
restore default flags (further flags still apply)
.TP
\fB-c\fR
create the PT_PAX_FLAGS program header if it does not exist by
converting the PT_GNU_STACK program header if it exists
.TP
\fB-C\fR
create the PT_PAX_FLAGS program header if it does not exist by
adding a new program header, if it is possible
.TP
\fB-q\fR
suppress error messages
.TP
\fB-Q\fR
report flags in short format
.SH CAVEATS
The old PaX flag location and control method have been obsoleted,
if your kernel and binaries use it you have to use chpax(1) instead
(it is recommended to use PT_PAX_FLAGS along with -c or -C however).

Converting PT_GNU_STACK into PT_PAX_FLAGS means that the information
in the former is destroyed, in particular you must make sure that
the EMUTRAMP PaX option is properly set in the newly created PT_PAX_FLAGS.

The secure way is to disable EMUTRAMP first and if PaX reports stack
execution attempts from nested function trampolines then enable it.

Note that the new PT_PAX_FLAGS is created in the same state that
binutils/ld itself would produce (equivalent to -zex).

Note that paxctl does not make backup copies of the files it modifies.
.SH AUTHOR
Written by The PaX Team <pageexec@freemail.hu>
.PP
This manpage was adapted from the chpax manpage written by Martin F. Krafft <madduck@debian.org>
for the Debian GNU/Linux Distribution, but may be used by others.
.SH "SEE ALSO"
.BR chpax (1),
.BR gradm (8)
.PP
PaX website: http://pax.grsecurity.net
.PP
GrSecurity website: http://www.grsecurity.net
.PP
Adamantix website: http://adamantix.org
.PP
Hardened Gentoo website: http://www.gentoo.org/proj/en/hardened
paxctl-0.5/paxctl.c000064400000000000000000000545561121201167700143230ustar00rootroot00000000000000/*
* PaX control
* Copyright 2004,2005,2006,2007 PaX Team <pageexec@freemail.hu>
* Licensed under the GNU GPL version 2
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <elf.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include "paxctl.h"

static void report_flags(const Elf64_Word flags, const struct pax_state * const state)
{
char buffer[13];

/* the logic is: lower case: explicitly disabled, upper case: explicitly enabled, - : default */
buffer[0] = (flags & PF_PAGEEXEC ? 'P' : '-');
buffer[1] = (flags & PF_NOPAGEEXEC ? 'p' : '-');
buffer[2] = (flags & PF_SEGMEXEC ? 'S' : '-');
buffer[3] = (flags & PF_NOSEGMEXEC ? 's' : '-');
buffer[4] = (flags & PF_MPROTECT ? 'M' : '-');
buffer[5] = (flags & PF_NOMPROTECT ? 'm' : '-');
buffer[6] = (flags & PF_RANDEXEC ? 'X' : '-');
buffer[7] = (flags & PF_NORANDEXEC ? 'x' : '-');
buffer[8] = (flags & PF_EMUTRAMP ? 'E' : '-');
buffer[9] = (flags & PF_NOEMUTRAMP ? 'e' : '-');
buffer[10] = (flags & PF_RANDMMAP ? 'R' : '-');
buffer[11] = (flags & PF_NORANDMMAP ? 'r' : '-');
buffer[12] = 0;

fprintf(stdout, "- PaX flags: %s [%s]\n", buffer, state->argv[state->files]);

if (state->shortonly)
return;

if (flags & PF_PAGEEXEC) fprintf(stdout, "\tPAGEEXEC is enabled\n");
if (flags & PF_NOPAGEEXEC) fprintf(stdout, "\tPAGEEXEC is disabled\n");
if (flags & PF_SEGMEXEC) fprintf(stdout, "\tSEGMEXEC is enabled\n");
if (flags & PF_NOSEGMEXEC) fprintf(stdout, "\tSEGMEXEC is disabled\n");
if (flags & PF_MPROTECT) fprintf(stdout, "\tMPROTECT is enabled\n");
if (flags & PF_NOMPROTECT) fprintf(stdout, "\tMPROTECT is disabled\n");
if (flags & PF_RANDEXEC) fprintf(stdout, "\tRANDEXEC is enabled\n");
if (flags & PF_NORANDEXEC) fprintf(stdout, "\tRANDEXEC is disabled\n");
if (flags & PF_EMUTRAMP) fprintf(stdout, "\tEMUTRAMP is enabled\n");
if (flags & PF_NOEMUTRAMP) fprintf(stdout, "\tEMUTRAMP is disabled\n");
if (flags & PF_RANDMMAP) fprintf(stdout, "\tRANDMMAP is enabled\n");
if (flags & PF_NORANDMMAP) fprintf(stdout, "\tRANDMMAP is disabled\n");
}

#define elf_modify_phdr(bit) \
static int elf##bit##_modify_phdr(struct pax_state * const state) \
{ \
unsigned int i, pt_phdr, pt_load, gnu_stack, pax_flags; \
Elf##bit##_Phdr * phdr = state->ops->phdr._##bit; \
Elf##bit##_Shdr * shdr = state->ops->shdr._##bit; \
\
/* init phdr info */ \
pt_phdr = state->ops->phnum._##bit; \
pt_load = state->ops->phnum._##bit; \
gnu_stack = state->ops->phnum._##bit; \
pax_flags = state->ops->phnum._##bit; \
\
/* verify shdr info */ \
for (i = 0U; i < state->ops->shnum._##bit; i++) { \
if (SHT_NULL == shdr[i].sh_type) \
continue; \
\
if ((shdr[i].sh_addralign && (~(shdr[i].sh_addralign - 1) + shdr[i].sh_addralign)) || \
(shdr[i].sh_addralign && shdr[i].sh_addr && (shdr[i].sh_addr & (shdr[i].sh_addralign - 1))) || \
(shdr[i].sh_addr && shdr[i].sh_addr + shdr[i].sh_size < shdr[i].sh_addr) || \
shdr[i].sh_offset < sizeof(Elf##bit##_Ehdr) + sizeof(Elf##bit##_Phdr) * state->ops->phnum._##bit || \
shdr[i].sh_offset + shdr[i].sh_size < shdr[i].sh_offset || \
(SHT_NOBITS != shdr[i].sh_type && shdr[i].sh_offset + shdr[i].sh_size > state->size)) \
{ \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (invalid SHT_ entry:%u)\n", state->argv[state->files], i); \
return EXIT_FAILURE; \
} \
} \
\
/* gather/verify phdr info */ \
for (i = 0U; i < state->ops->phnum._##bit; i++) { \
if ((phdr[i].p_align && (~(phdr[i].p_align - 1) + phdr[i].p_align)) || \
(phdr[i].p_align && ((phdr[i].p_offset ^ phdr[i].p_vaddr) & (phdr[i].p_align - 1))) || \
phdr[i].p_vaddr + phdr[i].p_memsz < phdr[i].p_vaddr || \
phdr[i].p_offset + phdr[i].p_filesz < phdr[i].p_offset || \
phdr[i].p_offset + phdr[i].p_filesz > state->size || \
phdr[i].p_filesz > phdr[i].p_memsz) \
{ \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (invalid PT_ entry:%u)\n", state->argv[state->files], i); \
return EXIT_FAILURE; \
} \
\
switch (phdr[i].p_type) { \
case PT_PHDR: \
if (pt_phdr == state->ops->phnum._##bit) { \
if (pt_load != state->ops->phnum._##bit) { \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (PT_LOAD before PT_PHDR)\n", state->argv[state->files]); \
return EXIT_FAILURE; \
} \
pt_phdr = i; \
} else { \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (more than one PT_PHDR)\n", state->argv[state->files]); \
return EXIT_FAILURE; \
} \
break; \
\
case PT_LOAD: \
if (pt_load == state->ops->phnum._##bit) \
pt_load = i; \
break; \
\
case PT_PAX_FLAGS: \
if (pax_flags != state->ops->phnum._##bit) { \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (more than one PT_PAX_FLAGS)\n", state->argv[state->files]); \
return EXIT_FAILURE; \
} \
pax_flags = i; \
break; \
\
case PT_GNU_STACK: \
if (gnu_stack != state->ops->phnum._##bit) { \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (more than one PT_GNU_STACK)\n", state->argv[state->files]); \
return EXIT_FAILURE; \
} \
gnu_stack = i; \
break; \
} \
} \
\
/* verify phdr info */ \
if (pt_load == state->ops->phnum._##bit) { \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (no PT_LOAD found)\n", state->argv[state->files]); \
return EXIT_FAILURE; \
} \
\
if (pt_phdr < state->ops->phnum._##bit) { \
if (phdr[pt_phdr].p_vaddr + phdr[pt_phdr].p_memsz <= phdr[pt_load].p_vaddr || \
phdr[pt_load].p_vaddr + phdr[pt_load].p_memsz <= phdr[pt_phdr].p_vaddr) { \
if (!state->quiet) \
fprintf(stderr, "file %s is not a valid ELF executable (PT_PHDR is outside of first PT_LOAD)\n", state->argv[state->files]); \
return EXIT_FAILURE; \
} \
} \
\
/* convert PT_GNU_STACK if necessary/possible */ \
if (pax_flags == state->ops->phnum._##bit && state->convert) { \
if (gnu_stack < state->ops->phnum._##bit) { \
pax_flags = gnu_stack; \
phdr[pax_flags].p_type = PT_PAX_FLAGS; \
phdr[pax_flags].p_flags = PF_NORANDEXEC | PF_NOEMUTRAMP; \
if (!state->quiet) \
fprintf(stderr, "file %s had a PT_GNU_STACK program header, converted\n", state->argv[state->files]); \
} else { \
if (!state->quiet) \
fprintf(stderr, "file %s does not have a PT_GNU_STACK program header, conversion failed\n", state->argv[state->files]); \
} \
} \
\
/* create PT_PAX_FLAGS if necessary/possible */ \
if (pax_flags == state->ops->phnum._##bit && state->create) { \
Elf##bit##_Word shift = phdr[pt_load].p_align; \
\
if (shift == phdr[pt_load].p_vaddr) { \
shift >>= 1; \
if (!state->quiet) \
fprintf(stderr, "file %s will be realigned, beware\n", state->argv[state->files]); \
} \
\
if ((pt_phdr == state->ops->phnum._##bit || \
(phdr[pt_phdr].p_offset == sizeof(Elf##bit##_Ehdr) && \
phdr[pt_phdr].p_align < shift && \
phdr[pt_phdr].p_memsz + sizeof(Elf##bit##_Phdr) < phdr[pt_load].p_memsz)) && \
phdr[pt_load].p_vaddr > shift && \
state->size + shift > shift) \
{ \
unsigned char * newmap; \
Elf##bit##_Ehdr * ehdr; \
Elf##bit##_Phdr * newphdr; \
\
/* unmap old mapping with old size */ \
if (-1 == munmap(state->map, state->size)) { \
if (!state->quiet) \
perror(state->argv[state->files]); \
return EXIT_FAILURE; \
} \
\
/* set up new size */ \
state->size += shift; \
\
/* adjust underlying file size */ \
if (-1 == ftruncate(state->fd, (off_t)state->size)) { \
if (!state->quiet) \
perror(state->argv[state->files]); \
return EXIT_FAILURE; \
} \
\
/* map underlying file again with the new size */ \
newmap = mmap(NULL, state->size, PROT_READ | PROT_WRITE, MAP_SHARED, state->fd, (off_t)0); \
if (MAP_FAILED == newmap) { \
if (!state->quiet) \
perror(state->argv[state->files]); \
return EXIT_FAILURE; \
} \
\
/* adjust pointers based on the new mapping */ \
phdr = state->ops->phdr._##bit = (Elf##bit##_Phdr *)((unsigned char*)phdr + (newmap - state->map)); \
if (shdr) \
shdr = state->ops->shdr._##bit = (Elf##bit##_Shdr *)((unsigned char*)shdr + (newmap - state->map)); \
state->map = newmap; \
\
/* make room for the new PHDR */ \
memmove(state->map + shift, state->map, state->size - shift); \
memset(state->map + sizeof(Elf##bit##_Ehdr), 0, shift - sizeof(Elf##bit##_Ehdr)); \
\
/* adjust pointers again */ \
phdr = state->ops->phdr._##bit = (Elf##bit##_Phdr *)((unsigned char*)phdr + shift); \
if (shdr) \
shdr = state->ops->shdr._##bit = (Elf##bit##_Shdr *)((unsigned char*)shdr + shift); \
\
/* adjust file offsets: ehdr */ \
ehdr = (Elf##bit##_Ehdr *)state->map; \
if (shdr) \
ehdr->e_shoff += shift; \
\
/* adjust file offsets: phdr */ \
newphdr = (Elf##bit##_Phdr *)(state->map + ehdr->e_phoff); \
for (i = 0; i < state->ops->phnum._##bit; i++) { \
newphdr[i] = phdr[i]; \
if (newphdr[i].p_offset >= sizeof(Elf##bit##_Ehdr) + sizeof(Elf##bit##_Phdr) * state->ops->phnum._##bit) \
newphdr[i].p_offset += shift; \
else if (newphdr[i].p_vaddr >= phdr[pt_load].p_vaddr) { \
newphdr[i].p_vaddr -= shift; \
newphdr[i].p_paddr -= shift; \
} \
if (newphdr[i].p_align > shift) \
newphdr[i].p_align = shift; \
} \
newphdr[pt_load].p_memsz += shift; \
newphdr[pt_load].p_filesz += shift; \
\
/* the moment of truth */ \
pax_flags = i; \
newphdr[pax_flags].p_type = PT_PAX_FLAGS; \
newphdr[pax_flags].p_flags = PF_NORANDEXEC | PF_NOEMUTRAMP; \
newphdr[pax_flags].p_align = 4; \
if (pt_phdr < state->ops->phnum._##bit) { \
newphdr[pt_phdr].p_memsz += sizeof(Elf##bit##_Phdr); \
newphdr[pt_phdr].p_filesz += sizeof(Elf##bit##_Phdr); \
} else \
pt_phdr++; \
ehdr->e_phnum += 1; \
state->ops->phnum._##bit += 1; \
phdr = newphdr; \
\
/* adjust file offsets: shdr */ \
for (i = 0; i < state->ops->shnum._##bit; i++) { \
if (shdr[i].sh_offset) \
shdr[i].sh_offset += shift; \
} \
\
if (!state->quiet) \
fprintf(stderr, "file %s got a new PT_PAX_FLAGS program header\n", state->argv[state->files]); \
} \
if (pax_flags == state->ops->phnum._##bit) { \
if (!state->quiet) \
fprintf(stderr, "file %s cannot have a PT_PAX_FLAGS program header, creation failed\n", state->argv[state->files]); \
} \
} \
\
if (pax_flags == state->ops->phnum._##bit) { \
if (!state->quiet && !state->convert && !state->create) \
fprintf(stderr, "file %s does not have a PT_PAX_FLAGS program header, try conversion\n", state->argv[state->files]); \
return EXIT_FAILURE; \
} \
\
if (state->view) \
report_flags(phdr[pax_flags].p_flags, state); \
if (state->flags_on | state->flags_off) { \
const Elf##bit##_Ehdr * const ehdr = (const Elf##bit##_Ehdr *)state->map; \
\
if (ehdr->e_type == ET_DYN) { \
phdr[pax_flags].p_flags &= ~((state->flags_off | PF_RANDEXEC) & ~PF_NORANDEXEC); \
phdr[pax_flags].p_flags |= (state->flags_on | PF_NORANDEXEC) & ~PF_RANDEXEC; \
} else { \
phdr[pax_flags].p_flags &= ~state->flags_off; \
phdr[pax_flags].p_flags |= state->flags_on; \
} \
} \
return EXIT_SUCCESS; \
}

elf_modify_phdr(32);
elf_modify_phdr(64);

static struct elf_ops elf32 = {
.modify_phdr = elf32_modify_phdr,
};

static struct elf_ops elf64 = {
.modify_phdr = elf64_modify_phdr,
};

static void banner(void)
{
fprintf(stderr,
"PaX control v" PAXCTL_VERSION "\n"
"Copyright 2004,2005,2006,2007 PaX Team <pageexec@freemail.hu>\n\n");
}

static void usage(void)
{
banner();
fprintf(stderr,
"usage: paxctl <options> <files>\n\n"
"options:\n"
"\t-p: disable PAGEEXEC\t\t-P: enable PAGEEXEC\n"
"\t-e: disable EMUTRMAP\t\t-E: enable EMUTRMAP\n"
"\t-m: disable MPROTECT\t\t-M: enable MPROTECT\n"
"\t-r: disable RANDMMAP\t\t-R: enable RANDMMAP\n"
"\t-x: disable RANDEXEC\t\t-X: enable RANDEXEC\n"
"\t-s: disable SEGMEXEC\t\t-S: enable SEGMEXEC\n\n"
"\t-v: view flags\t\t\t-z: restore default flags\n"
"\t-q: suppress error messages\t-Q: report flags in short format\n"
"\t-c: convert PT_GNU_STACK into PT_PAX_FLAGS (see manpage!)\n"
"\t-C: create PT_PAX_FLAGS (see manpage!)\n"
);
exit(EXIT_FAILURE);
}

static int is_elf32(struct pax_state * const state)
{
const Elf32_Ehdr * const ehdr = (const Elf32_Ehdr *)state->map;

if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG))
return 0;
if (ehdr->e_ehsize != sizeof(Elf32_Ehdr))
return 0;
if ((ehdr->e_version != EV_CURRENT) || (ehdr->e_ident[EI_CLASS] != ELFCLASS32))
return 0;
if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN))
return 0;

if (!ehdr->e_phoff || !ehdr->e_phnum || sizeof(Elf32_Phdr) != ehdr->e_phentsize)
return 0;
if (ehdr->e_phnum > 65536U / ehdr->e_phentsize - 1)
return 0;
if (ehdr->e_phoff > ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum)
return 0;
if ((Elf32_Off)state->size < ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum)
return 0;

if (ehdr->e_shoff) {
if (!ehdr->e_shnum || sizeof(Elf32_Shdr) != ehdr->e_shentsize)
return 0;
if (ehdr->e_shnum > 65536U / ehdr->e_shentsize)
return 0;
if (ehdr->e_shoff > ehdr->e_shoff + ehdr->e_shentsize * ehdr->e_shnum)
return 0;
if ((Elf32_Off)state->size < ehdr->e_shoff + ehdr->e_shentsize * ehdr->e_shnum)
return 0;
}

state->ops = &elf32;
state->ops->phdr._32 = (Elf32_Phdr *)(state->map + ehdr->e_phoff);
state->ops->phnum._32 = ehdr->e_phnum;
if (ehdr->e_shoff) {
state->ops->shdr._32 = (Elf32_Shdr *)(state->map + ehdr->e_shoff);
state->ops->shnum._32 = ehdr->e_shnum;
} else {
state->ops->shdr._32 = NULL;
state->ops->shnum._32 = 0;
}

return 1;
}

static int is_elf64(struct pax_state * const state)
{
const Elf64_Ehdr * const ehdr = (const Elf64_Ehdr *)state->map;

if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG))
return 0;
if (ehdr->e_ehsize != sizeof(Elf64_Ehdr))
return 0;
if ((ehdr->e_version != EV_CURRENT) || (ehdr->e_ident[EI_CLASS] != ELFCLASS64))
return 0;
if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN))
return 0;

if (!ehdr->e_phoff || !ehdr->e_phnum || sizeof(Elf64_Phdr) != ehdr->e_phentsize)
return 0;
if (ehdr->e_phnum > 65536U / ehdr->e_phentsize - 1)
return 0;
if (ehdr->e_phoff > ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum)
return 0;
if ((Elf64_Off)state->size < ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum)
return 0;

if (ehdr->e_shoff) {
if (!ehdr->e_shnum || sizeof(Elf64_Shdr) != ehdr->e_shentsize)
return 0;
if (ehdr->e_shnum > 65536U / ehdr->e_shentsize)
return 0;
if (ehdr->e_shoff > ehdr->e_shoff + ehdr->e_shentsize * ehdr->e_shnum)
return 0;
if ((Elf64_Off)state->size < ehdr->e_shoff + ehdr->e_shentsize * ehdr->e_shnum)
return 0;
}

state->ops = &elf64;
state->ops->phdr._64 = (Elf64_Phdr *)(state->map + ehdr->e_phoff);
state->ops->phnum._64 = ehdr->e_phnum;
if (ehdr->e_shoff) {
state->ops->shdr._64 = (Elf64_Shdr *)(state->map + ehdr->e_shoff);
state->ops->shnum._64 = ehdr->e_shnum;
} else {
state->ops->shdr._64 = NULL;
state->ops->shnum._64 = 0;
}

return 1;
}

static int pax_verify_file(struct pax_state * const state)
{
int fd, oflags, mflags;
struct stat st;

if (state->flags_on | state->flags_off | state->convert | state->create) {
oflags = O_RDWR;
mflags = PROT_READ | PROT_WRITE;
} else {
oflags = O_RDONLY;
mflags = PROT_READ;
}

fd = open(state->argv[state->files], oflags);
if (-1 == fd) {
if (!state->quiet)
perror(state->argv[state->files]);
return EXIT_FAILURE;
}

if (-1 == fstat(fd, &st)) {
close(fd);
if (!state->quiet)
perror(state->argv[state->files]);
return EXIT_FAILURE;
}

state->size = st.st_size;
state->map = mmap(NULL, state->size, mflags, MAP_SHARED, fd, (off_t)0);
if (MAP_FAILED == state->map) {
state->map = NULL;
state->size = 0;
close(fd);
if (!state->quiet)
perror(state->argv[state->files]);
return EXIT_FAILURE;
}

if (state->size < sizeof(Elf64_Ehdr) || (!is_elf32(state) && !is_elf64(state))) {
munmap(state->map, (size_t)st.st_size);
state->map = NULL;
state->size = 0;
close(fd);
if (!state->quiet)
fprintf(stderr, "file %s is not a valid ELF executable\n", state->argv[state->files]);
return EXIT_FAILURE;
}

state->fd = fd;

return EXIT_SUCCESS;
}

static int pax_process_file(struct pax_state * const state)
{
int ret = EXIT_FAILURE;

/* get/verify ELF header */
if (EXIT_SUCCESS == pax_verify_file(state)) {
/* report/modify program header */
ret = state->ops->modify_phdr(state);

munmap(state->map, state->size);
close(state->fd);
state->map = NULL;
state->size = 0;
state->fd = -1;
}

return ret;
}

static int pax_process_files(struct pax_state * const state)
{
int status = EXIT_SUCCESS;

while (state->argv[state->files]) {
if (EXIT_SUCCESS != pax_process_file(state))
status = EXIT_FAILURE;
++state->files;
}

return status;
}

static int pax_parse_args(int argc, struct pax_state * const state)
{
while (1) {
switch(getopt(argc, state->argv, "pPsSmMeErRxXvqQzcC")) {
case -1:
state->files = optind;
return optind < argc ? EXIT_SUCCESS : EXIT_FAILURE;

case '?':
return EXIT_FAILURE;

#define parse_flag(option1, option2, flag) \
case option1: \
state->flags_on &= ~PF_##flag; \
state->flags_on |= PF_NO##flag; \
state->flags_off &= ~PF_NO##flag; \
state->flags_off |= PF_##flag; \
break; \
case option2: \
state->flags_on &= ~PF_NO##flag; \
state->flags_on |= PF_##flag; \
state->flags_off &= ~PF_##flag; \
state->flags_off |= PF_NO##flag; \
break;

parse_flag('p', 'P', PAGEEXEC);
parse_flag('s', 'S', SEGMEXEC);
parse_flag('m', 'M', MPROTECT);
parse_flag('e', 'E', EMUTRAMP);
parse_flag('r', 'R', RANDMMAP);
parse_flag('x', 'X', RANDEXEC);

#undef parse_flag

case 'v':
state->view = 1;
break;

case 'q':
state->quiet = 1;
break;

case 'Q':
state->shortonly = 1;
break;

case 'z':
state->flags_on = 0U;
state->flags_off = PF_PAX_MASK;
break;

case 'c':
state->convert = 1;
break;

case 'C':
state->create = 1;
break;
}
}
}

int main(int argc, char * argv[])
{
struct pax_state state = {
.argv = argv,
.flags_on = 0U,
.flags_off = 0U,
.files = 0U,
.quiet = 0,
.shortonly = 0,
.view = 0,
.convert = 0,
.create = 0,
.ops = NULL,
.map = NULL,
.size = 0,
.fd = -1,
};

if (3 > argc)
usage();

/* parse arguments */
if (EXIT_SUCCESS != pax_parse_args(argc, &state))
return EXIT_FAILURE;

if (state.view)
banner();

/* process files */
return pax_process_files(&state);
}
paxctl-0.5/paxctl.h000064400000000000000000000031011121201167700143040ustar00rootroot00000000000000#ifndef __PAXCTL_H
#define __PAXCTL_H

#include <elf.h>

#define PAXCTL_VERSION "0.5"

struct pax_state;

struct elf_ops {
int (* const modify_phdr)(struct pax_state * const);
union {
Elf32_Phdr * _32;
Elf64_Phdr * _64;
} phdr;
union {
Elf32_Half _32;
Elf64_Half _64;
} phnum;
union {
Elf32_Shdr * _32;
Elf64_Shdr * _64;
} shdr;
union {
Elf32_Half _32;
Elf64_Half _64;
} shnum;
};

struct pax_state {
char ** argv;
unsigned int flags_on;
unsigned int flags_off;
unsigned int files;
unsigned int quiet:1;
unsigned int shortonly:1;
unsigned int view:1;
unsigned int convert:1;
unsigned int create:1;
struct elf_ops * ops;
int fd;
unsigned char * map;
size_t size;
};

#ifndef PT_GNU_STACK
#define PT_GNU_STACK 0x6474e551 /* Indicates vanilla stack executability */
#endif

#ifndef PT_PAX_FLAGS

#define PT_PAX_FLAGS 0x65041580

#define PF_PAGEEXEC (1U << 4) /* Enable PAGEEXEC */
#define PF_NOPAGEEXEC (1U << 5) /* Disable PAGEEXEC */
#define PF_SEGMEXEC (1U << 6) /* Enable SEGMEXEC */
#define PF_NOSEGMEXEC (1U << 7) /* Disable SEGMEXEC */
#define PF_MPROTECT (1U << 8) /* Enable MPROTECT */
#define PF_NOMPROTECT (1U << 9) /* Disable MPROTECT */
#define PF_RANDEXEC (1U << 10) /* Enable RANDEXEC */
#define PF_NORANDEXEC (1U << 11) /* Disable RANDEXEC */
#define PF_EMUTRAMP (1U << 12) /* Enable EMUTRAMP */
#define PF_NOEMUTRAMP (1U << 13) /* Disable EMUTRAMP */
#define PF_RANDMMAP (1U << 14) /* Enable RANDMMAP */
#define PF_NORANDMMAP (1U << 15) /* Disable RANDMMAP */

#endif

#define PF_PAX_MASK 0xFFF0U

#endif
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin