summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorelad <elad@NetBSD.org>2006-11-22 02:02:51 +0000
committerelad <elad@NetBSD.org>2006-11-22 02:02:51 +0000
commita84fee7faffe0455d7a4d4f03c03d697bde6849c (patch)
treea598a3231359a9c3ccc229b5b9c2aa9f340660fa /sys
parent25e0bf9073a7cb7cb3443ad5b3b97717c19b18ac (diff)
Initial implementation of PaX Segvguard (this is still work-in-progress,
it's just to get it out of my local tree).
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files5
-rw-r--r--sys/kern/exec_elf32.c13
-rw-r--r--sys/kern/init_main.c13
-rw-r--r--sys/kern/kern_exec.c15
-rw-r--r--sys/kern/kern_pax.c263
-rw-r--r--sys/kern/kern_sig.c12
-rw-r--r--sys/sys/pax.h5
7 files changed, 301 insertions, 25 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 82f1d23e0c5..fad506448ab 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.816 2006/10/27 21:20:48 christos Exp $
+# $NetBSD: files,v 1.817 2006/11/22 02:02:51 elad Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -90,6 +90,7 @@ defflag opt_syscall_stats.h SYSCALL_TIMES_HASCOUNTER: SYSCALL_TIMES
file kern/subr_syscall_stats.c syscall_stats
defparam opt_pax.h PAX_MPROTECT
+ PAX_SEGVGUARD
defflag opt_fileassoc.h FILEASSOC
defparam opt_fileassoc.h FILEASSOC_NHOOKS
@@ -1289,7 +1290,7 @@ file kern/kern_malloc.c
file kern/kern_malloc_debug.c malloc_debug
file kern/kern_fileassoc.c fileassoc
file kern/kern_ntptime.c
-file kern/kern_pax.c pax_mprotect
+file kern/kern_pax.c pax_mprotect | pax_segvguard
file kern/kern_physio.c
file kern/kern_proc.c
file kern/kern_prot.c
diff --git a/sys/kern/exec_elf32.c b/sys/kern/exec_elf32.c
index b7aa4f2a9c0..00aac776a56 100644
--- a/sys/kern/exec_elf32.c
+++ b/sys/kern/exec_elf32.c
@@ -1,4 +1,4 @@
-/* $NetBSD: exec_elf32.c,v 1.118 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: exec_elf32.c,v 1.119 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc.
@@ -64,7 +64,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.118 2006/11/22 00:41:38 elad Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.119 2006/11/22 02:02:51 elad Exp $");
/* If not included by exec_elf64.c, ELFSIZE won't be defined. */
#ifndef ELFSIZE
@@ -91,9 +91,9 @@ __KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.118 2006/11/22 00:41:38 elad Exp $"
#include <machine/cpu.h>
#include <machine/reg.h>
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
#include <sys/pax.h>
-#endif /* PAX_MPROTECT */
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
extern const struct emul emul_netbsd;
@@ -690,11 +690,10 @@ exec_elf_makecmds(struct lwp *l, struct exec_package *epp)
case PT_INTERP:
/* Already did this one. */
case PT_DYNAMIC:
- break;
case PT_NOTE:
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
pax_adjust(l, ph[i].p_flags);
-#endif /* PAX_MPROTECT */
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
break;
case PT_PHDR:
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 626176b9bd7..18520e09382 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: init_main.c,v 1.281 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: init_main.c,v 1.282 2006/11/22 02:02:51 elad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
@@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.281 2006/11/22 00:41:38 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.282 2006/11/22 02:02:51 elad Exp $");
#include "opt_ipsec.h"
#include "opt_kcont.h"
@@ -156,10 +156,9 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.281 2006/11/22 00:41:38 elad Exp $")
#include <sys/fileassoc.h>
#endif /* FILEASSOC */
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
#include <sys/pax.h>
-#endif /* PAX_MPROTECT */
-
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
#include <ufs/ufs/quota.h>
#include <miscfs/genfs/genfs.h>
@@ -390,9 +389,9 @@ main(void)
veriexec_init_fp_ops();
#endif /* NVERIEXEC > 0 */
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
pax_init();
-#endif /* PAX_MPROTECT */
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
/* Attach pseudo-devices. */
for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index b951f00b08e..7135d535727 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_exec.c,v 1.231 2006/11/01 10:17:58 yamt Exp $ */
+/* $NetBSD: kern_exec.c,v 1.232 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou
@@ -33,12 +33,13 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.231 2006/11/01 10:17:58 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.232 2006/11/22 02:02:51 elad Exp $");
#include "opt_ktrace.h"
#include "opt_syscall_debug.h"
#include "opt_compat_netbsd.h"
#include "veriexec.h"
+#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -73,6 +74,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.231 2006/11/01 10:17:58 yamt Exp $")
#include <sys/systrace.h>
#endif /* SYSTRACE */
+#ifdef PAX_SEGVGUARD
+#include <sys/pax.h>
+#endif /* PAX_SEGVGUARD */
+
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
@@ -282,13 +287,17 @@ check_exec(struct lwp *l, struct exec_package *epp, int flag)
/* unlock vp, since we need it unlocked from here on out. */
VOP_UNLOCK(vp, 0);
-
#if NVERIEXEC > 0
if ((error = veriexec_verify(l, vp, epp->ep_ndp->ni_dirp, flag,
NULL)) != 0)
goto bad2;
#endif /* NVERIEXEC > 0 */
+#ifdef PAX_SEGVGUARD
+ if (pax_segvguard(l, vp, epp->ep_ndp->ni_dirp, FALSE))
+ return (EPERM);
+#endif /* PAX_SEGVGUARD */
+
/* now we have the file, get the exec header */
uvn_attach(vp, VM_PROT_READ);
error = vn_rdwr(UIO_READ, vp, epp->ep_hdr, epp->ep_hdrlen, 0,
diff --git a/sys/kern/kern_pax.c b/sys/kern/kern_pax.c
index 5087fc5c27f..8d55004e100 100644
--- a/sys/kern/kern_pax.c
+++ b/sys/kern/kern_pax.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_pax.c,v 1.7 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: kern_pax.c,v 1.8 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@@ -37,21 +37,64 @@
#include <sys/exec_elf.h>
#include <sys/pax.h>
#include <sys/sysctl.h>
+#include <sys/malloc.h>
+#include <sys/fileassoc.h>
+#include <sys/syslog.h>
+#include <sys/vnode.h>
+#include <sys/queue.h>
+#include <sys/kauth.h>
#ifdef PAX_MPROTECT
static int pax_mprotect_enabled = 1;
static int pax_mprotect_global = PAX_MPROTECT;
specificdata_key_t pax_mprotect_key;
-#endif /* PAX_MPROTECT */
+#endif
+
+#ifdef PAX_SEGVGUARD
+#ifndef PAX_SEGVGUARD_EXPIRY
+#define PAX_SEGVGUARD_EXPIRY (2 * 60)
+#endif
+
+#ifndef PAX_SEGVGUARD_SUSPENSION
+#define PAX_SEGVGUARD_SUSPENSION (10 * 60)
+#endif
+
+#ifndef PAX_SEGVGUARD_MAXCRASHES
+#define PAX_SEGVGUARD_MAXCRASHES 5
+#endif
+
+static int pax_segvguard_enabled = 1;
+static int pax_segvguard_global = PAX_SEGVGUARD;
+static int pax_segvguard_expiry = PAX_SEGVGUARD_EXPIRY;
+static int pax_segvguard_suspension = PAX_SEGVGUARD_SUSPENSION;
+static int pax_segvguard_maxcrashes = PAX_SEGVGUARD_MAXCRASHES;
+
+static fileassoc_t segvguard_id;
+specificdata_key_t pax_segvguard_key;
+
+struct pax_segvguard_uid_entry {
+ uid_t sue_uid;
+ size_t sue_ncrashes;
+ time_t sue_expiry;
+ time_t sue_suspended;
+ LIST_ENTRY(pax_segvguard_uid_entry) sue_list;
+};
+
+struct pax_segvguard_entry {
+ LIST_HEAD(, pax_segvguard_uid_entry) segv_uids;
+};
+#endif /* PAX_SEGVGUARD */
/* PaX internal setspecific flags */
#define PAX_MPROTECT_EXPLICIT_ENABLE (void *)0x01
#define PAX_MPROTECT_EXPLICIT_DISABLE (void *)0x02
+#define PAX_SEGVGUARD_EXPLICIT_ENABLE (void *)0x03
+#define PAX_SEGVGUARD_EXPLICIT_DISABLE (void *)0x04
SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
{
- const struct sysctlnode *rnode = NULL;
+ const struct sysctlnode *rnode = NULL, *cnode;
sysctl_createv(clog, 0, NULL, &rnode,
CTLFLAG_PERMANENT,
@@ -66,6 +109,8 @@ SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
NULL, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
+ cnode = rnode;
+
#ifdef PAX_MPROTECT
sysctl_createv(clog, 0, &rnode, &rnode,
CTLFLAG_PERMANENT,
@@ -88,6 +133,47 @@ SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
NULL, 0, &pax_mprotect_global, 0,
CTL_CREATE, CTL_EOL);
#endif /* PAX_MPROTECT */
+
+ rnode = cnode;
+
+#ifdef PAX_SEGVGUARD
+ sysctl_createv(clog, 0, &rnode, &rnode,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "segvguard",
+ SYSCTL_DESCR("PaX segvguard."),
+ NULL, 0, NULL, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &rnode, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "enabled",
+ SYSCTL_DESCR("segvguard enabled."),
+ NULL, 0, &pax_segvguard_enabled, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &rnode, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "global",
+ SYSCTL_DESCR("segvguard all programs."),
+ NULL, 0, &pax_segvguard_global, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &rnode, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "expiry_timeout",
+ SYSCTL_DESCR("Entry expiry timeout (in seconds)."),
+ NULL, 0, &pax_segvguard_expiry, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &rnode, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "suspend_timeout",
+ SYSCTL_DESCR("Entry suspension timeout (in seconds)."),
+ NULL, 0, &pax_segvguard_suspension, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &rnode, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "max_crashes",
+ SYSCTL_DESCR("Max number of crashes before expiry."),
+ NULL, 0, &pax_segvguard_maxcrashes, 0,
+ CTL_CREATE, CTL_EOL);
+#endif /* PAX_SEGVGUARD */
}
/*
@@ -99,6 +185,11 @@ pax_init(void)
#ifdef PAX_MPROTECT
proc_specific_key_create(&pax_mprotect_key, NULL);
#endif /* PAX_MPROTECT */
+
+#ifdef PAX_SEGVGUARD
+ segvguard_id = fileassoc_register("segvguard", pax_segvguard_cb);
+ proc_specific_key_create(&pax_segvguard_key, NULL);
+#endif /* PAX_SEGVGUARD */
}
void
@@ -114,6 +205,18 @@ pax_adjust(struct lwp *l, int f)
PAX_MPROTECT_EXPLICIT_DISABLE);
}
#endif /* PAX_MPROTECT */
+
+#ifdef PAX_SEGVGUARD
+ if (pax_segvguard_enabled) {
+ if (f & PF_PAXGUARD) {
+ proc_setspecific(l->l_proc, pax_segvguard_key,
+ PAX_SEGVGUARD_EXPLICIT_ENABLE);
+ }
+ if (f & PF_PAXNOGUARD)
+ proc_setspecific(l->l_proc, pax_segvguard_key,
+ PAX_SEGVGUARD_EXPLICIT_DISABLE);
+ }
+#endif /* PAX_SEGVGUARD */
}
#ifdef PAX_MPROTECT
@@ -139,3 +242,157 @@ pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot)
}
}
#endif /* PAX_MPROTECT */
+
+#ifdef PAX_SEGVGUARD
+void
+pax_segvguard_cb(void *v, int what)
+{
+ struct pax_segvguard_entry *p;
+ struct pax_segvguard_uid_entry *up;
+
+ if (v == NULL)
+ return;
+
+ if (what == FILEASSOC_CLEANUP_FILE) {
+ p = v;
+ while ((up = LIST_FIRST(&p->segv_uids)) != NULL) {
+ LIST_REMOVE(up, sue_list);
+ free(up, M_TEMP);
+ }
+ }
+
+ free(v, M_TEMP);
+}
+
+/*
+ * Called when a process of image vp generated a segfault.
+ */
+int
+pax_segvguard(struct lwp *l, struct vnode *vp, const char *name,
+ boolean_t crashed)
+{
+ struct pax_segvguard_entry *p;
+ struct pax_segvguard_uid_entry *up;
+ struct timeval tv;
+ uid_t uid;
+ void *t;
+ boolean_t have_uid;
+
+ if (!pax_segvguard_enabled)
+ return (0);
+
+ t = proc_getspecific(l->l_proc, pax_segvguard_key);
+ if ((pax_segvguard_global && t == PAX_SEGVGUARD_EXPLICIT_DISABLE) ||
+ (!pax_segvguard_global && t != PAX_SEGVGUARD_EXPLICIT_ENABLE))
+ return (0);
+
+ if (segvguard_id == FILEASSOC_INVAL || vp == NULL)
+ return (EFAULT);
+
+ /* Check if we already monitor the file. */
+ p = fileassoc_lookup(vp, segvguard_id);
+
+ /* Fast-path if starting a program we don't know. */
+ if (p == NULL && !crashed)
+ return (0);
+
+ microtime(&tv);
+
+ /*
+ * If a program we don't know crashed, we need to create a new entry
+ * for it.
+ */
+ if (p == NULL) {
+ p = malloc(sizeof(*p), M_TEMP, M_WAITOK);
+ if (fileassoc_add(vp, segvguard_id, p) != 0) {
+ fileassoc_table_add(vp->v_mount, 16);
+ fileassoc_add(vp, segvguard_id, p);
+ }
+ LIST_INIT(&p->segv_uids);
+
+ /*
+ * Initialize a new entry with "crashes so far" of 1.
+ * The expiry time is when we purge the entry if it didn't
+ * reach the limit.
+ */
+ up = malloc(sizeof(*up), M_TEMP, M_WAITOK);
+ up->sue_uid = kauth_cred_getuid(l->l_cred);
+ up->sue_ncrashes = 1;
+ up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
+ up->sue_suspended = 0;
+
+ LIST_INSERT_HEAD(&p->segv_uids, up, sue_list);
+
+ return (0);
+ }
+
+ /*
+ * A program we "know" either executed or crashed again.
+ * See if it's a culprit we're familiar with.
+ */
+ uid = kauth_cred_getuid(l->l_cred);
+ have_uid = FALSE;
+ LIST_FOREACH(up, &p->segv_uids, sue_list) {
+ if (up->sue_uid == uid) {
+ have_uid = TRUE;
+ break;
+ }
+ }
+
+ /*
+ * It's someone else. Add an entry for him if we crashed.
+ */
+ if (!have_uid) {
+ if (crashed) {
+ up = malloc(sizeof(*up), M_TEMP, M_WAITOK);
+ up->sue_uid = uid;
+ up->sue_ncrashes = 1;
+ up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
+ up->sue_suspended = 0;
+
+ LIST_INSERT_HEAD(&p->segv_uids, up, sue_list);
+ }
+
+ return (0);
+ }
+
+ if (crashed) {
+ /* Check if timer on previous crashes expired first. */
+ if (up->sue_expiry < tv.tv_sec) {
+ log(LOG_INFO, "PaX Segvguard: [%s] Suspension"
+ " expired.\n", name ? name : "unknown");
+
+ up->sue_ncrashes = 1;
+ up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
+ up->sue_suspended = 0;
+
+ return (0);
+ }
+
+ up->sue_ncrashes++;
+
+ if (up->sue_ncrashes >= pax_segvguard_maxcrashes) {
+ log(LOG_ALERT, "PaX Segvguard: [%s] Suspending "
+ "execution for %d seconds after %zu crashes.\n",
+ name ? name : "unknown", pax_segvguard_suspension,
+ up->sue_ncrashes);
+
+ /* Suspend this program for a while. */
+ up->sue_suspended = tv.tv_sec + pax_segvguard_suspension;
+ up->sue_ncrashes = 0;
+ up->sue_expiry = 0;
+ }
+ } else {
+ /* Are we supposed to be suspended? */
+ if (up->sue_suspended > tv.tv_sec) {
+ log(LOG_ALERT, "PaX Segvguard: [%s] Preventing "
+ "execution due to repeated segfaults.\n", name ?
+ name : "unknown");
+
+ return (EPERM);
+ }
+ }
+
+ return (0);
+}
+#endif /* PAX_SEGVGUARD */
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index dd5e0e75dd2..7648e8dd03e 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp $ */
+/* $NetBSD: kern_sig.c,v 1.240 2006/11/22 02:02:51 elad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.240 2006/11/22 02:02:51 elad Exp $");
#include "opt_coredump.h"
#include "opt_ktrace.h"
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp
#include "opt_compat_sunos.h"
#include "opt_compat_netbsd.h"
#include "opt_compat_netbsd32.h"
+#include "opt_pax.h"
#define SIGPROP /* include signal properties table */
#include <sys/param.h>
@@ -83,6 +84,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp
#include <sys/user.h> /* for coredump */
+#ifdef PAX_SEGVGUARD
+#include <sys/pax.h>
+#endif /* PAX_SEGVGUARD */
+
#include <uvm/uvm.h>
#include <uvm/uvm_extern.h>
@@ -2085,6 +2090,9 @@ sigexit(struct lwp *l, int signum)
p->p_comm, uid, signum);
}
+#ifdef PAX_SEGVGUARD
+ pax_segvguard(l, p->p_textvp, p->p_comm, TRUE);
+#endif /* PAX_SEGVGUARD */
}
exit1(l, W_EXITCODE(0, exitsig));
diff --git a/sys/sys/pax.h b/sys/sys/pax.h
index c8bd5952b70..1b27c1f89d1 100644
--- a/sys/sys/pax.h
+++ b/sys/sys/pax.h
@@ -1,4 +1,4 @@
-/* $NetBSD: pax.h,v 1.4 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: pax.h,v 1.5 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@@ -42,5 +42,8 @@ void pax_adjust(struct lwp *, int);
void pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);
+int pax_segvguard(struct lwp *, struct vnode *, const char *, boolean_t);
+void pax_segvguard_cb(void *, int);
+
#endif /* !__SYS_PAX_H__ */