Page MenuHomeFreeBSD

D4324.diff
No OneTemporary

D4324.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3318,7 +3318,8 @@
net/vnet.c optional vimage
net/zlib.c optional crypto | geom_uzip | ipsec | \
mxge | netgraph_deflate | \
- ddb_ctf | gzio | geom_uncompress
+ ddb_ctf | gzio | \
+ geom_uncompress | kldgzelf
net80211/ieee80211.c optional wlan
net80211/ieee80211_acl.c optional wlan wlan_acl
net80211/ieee80211_action.c optional wlan
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -131,6 +131,7 @@
GEOM_VOL opt_geom.h
GEOM_ZERO opt_geom.h
KDTRACE_HOOKS opt_kdtrace.h
+KLDGZELF opt_kldgzelf.h
KSTACK_MAX_PAGES
KSTACK_PAGES
KSTACK_USAGE_PROF
Index: sys/kern/link_elf.c
===================================================================
--- sys/kern/link_elf.c
+++ sys/kern/link_elf.c
@@ -29,7 +29,9 @@
#include "opt_ddb.h"
#include "opt_gdb.h"
+#include "opt_kldgzelf.h"
+#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#ifdef GPROF
@@ -64,8 +66,9 @@
#include <vm/vm_map.h>
#include <sys/link_elf.h>
+#include <sys/stat.h>
-#ifdef DDB_CTF
+#if defined(DDB_CTF) || defined(KLDGZELF)
#include <net/zlib.h>
#endif
@@ -73,6 +76,7 @@
#define MAXSEGS 4
+
typedef struct elf_file {
struct linker_file lf; /* Common fields */
int preloaded; /* Was file pre-loaded */
@@ -174,7 +178,7 @@
KOBJMETHOD(linker_ctf_get, link_elf_ctf_get),
KOBJMETHOD(linker_symtab_get, link_elf_symtab_get),
KOBJMETHOD(linker_strtab_get, link_elf_strtab_get),
- { 0, 0 }
+ KOBJMETHOD_END
};
static struct linker_class link_elf_class = {
@@ -186,6 +190,65 @@
link_elf_methods, sizeof(struct elf_file)
};
+#ifdef KLDGZELF
+#define GZ_ID1 31
+#define GZ_ID2 139
+/* Default ocmpression */
+#define GZ_CM 8
+/* Header flags */
+#define GZ_FLG_FTEXT 1
+#define GZ_FLG_FHCRC 2
+#define GZ_FLG_FEXTRA 4
+#define GZ_FLG_FNAME 8
+#define GZ_FLG_FCOMMENT 16
+
+#define GZ_EXTRA_F_SIZE_SIZE 2
+#define GZ_INFLATED_SIZE_SIZE 4
+
+static int link_gzelf_link_preload(linker_class_t,
+ const char *, linker_file_t *);
+static int link_gzelf_link_preload_finish(linker_file_t);
+static int link_gzelf_load_file(linker_class_t, const char *,
+ linker_file_t *);
+
+static kobj_method_t link_gzelf_methods[] = {
+ KOBJMETHOD(linker_load_file, link_elf_load_file),
+ KOBJMETHOD(linker_link_preload, link_gzelf_link_preload),
+ KOBJMETHOD(linker_link_preload_finish, link_gzelf_link_preload_finish),
+ KOBJMETHOD_END
+};
+
+static kobj_class_t link_gzelf_baseclasses[] = {
+ (kobj_class_t)&link_elf_class, NULL
+};
+
+static struct linker_class link_gzelf_class = {
+#if ELF_TARG_CLASS == ELFCLASS32
+ "gzelf32",
+#else
+ "gzelf64",
+#endif
+ link_gzelf_methods, sizeof(struct elf_file), link_gzelf_baseclasses
+};
+
+static int
+link_gzelf_link_preload(linker_class_t cls,
+ const char* filename, linker_file_t *result)
+{
+
+ return ENOENT;
+}
+
+static int
+link_gzelf_link_preload_finish(linker_file_t lf)
+{
+
+ return ENOENT;
+}
+
+#endif
+
+
static int parse_dynamic(elf_file_t);
static int relocate_file(elf_file_t);
static int link_elf_preload_parse_symbols(elf_file_t);
@@ -376,6 +439,9 @@
char *modname;
linker_add_class(&link_elf_class);
+#ifdef KLDGZELF
+ linker_add_class(&link_gzelf_class);
+#endif
dp = (Elf_Dyn *)&_DYNAMIC;
modname = NULL;
@@ -575,7 +641,7 @@
static int
parse_dpcpu(elf_file_t ef)
-{
+{
int count;
int error;
@@ -606,7 +672,7 @@
#ifdef VIMAGE
static int
parse_vnet(elf_file_t ef)
-{
+{
int count;
int error;
@@ -710,14 +776,59 @@
return (link_elf_link_common_finish(lf));
}
+#ifdef KLDGZELF
+typedef struct gzcontext {
+ u_char *out_p;
+ u_int inflated_size;
+ struct vnode *vd;
+ struct thread *td;
+ int error;
+ off_t skip;
+} *gzcontext_t;
+
+typedef struct gz_hdr {
+ u_char id1;
+ u_char id2;
+ u_char cm;
+ u_char flags;
+ u_int mtime;
+ u_char xflags;
+ u_char os;
+}__attribute__((__packed__)) *gz_hdr_t;
+
+static long gzhdr(u_char *, int);
+static int gzelf_inflate(struct gzcontext *);
+static void *zalloc(void *, u_int, u_int);
+static void zfree(void *, void *);
+#endif
+
+/*
+ * Safer memcpy; it checks if attempted copy will not cross source
+ * buffer size.
+ *
+ * Returns: 0 in case of success and EFAULT if chunk would cross
+ * the range of source buffer.
+ */
+static inline int
+smemcpy(void *dst, void *base, off_t off, size_t len, size_t src_size)
+{
+
+ if (off + len > src_size) {
+ return EFAULT;
+ }
+
+ memcpy(dst, (caddr_t)base + off, len);
+ return 0;
+}
+
static int
link_elf_load_file(linker_class_t cls, const char* filename,
linker_file_t* result)
{
- struct nameidata nd;
+ struct nameidata nd = { 0 };
struct thread* td = curthread; /* XXX */
- Elf_Ehdr *hdr;
- caddr_t firstpage;
+ Elf_Ehdr *hdr = NULL;
+ caddr_t firstpage = NULL;
int nbytes, i;
Elf_Phdr *phdr;
Elf_Phdr *phlimit;
@@ -740,6 +851,9 @@
int symstrindex;
int symcnt;
int strcnt;
+#ifdef KLDGZELF
+ struct gzcontext gzc = { 0 };
+#endif
shdr = NULL;
lf = NULL;
@@ -774,6 +888,23 @@
nbytes = PAGE_SIZE - resid;
if (error != 0)
goto out;
+#ifdef KLDGZELF
+ if (cls == &link_gzelf_class) {
+ gzc.td = td;
+ gzc.vd = nd.ni_vp;
+ if (gzelf_inflate(&gzc) != Z_OK) {
+ if (gzc.error != 0)
+ error = gzc.error;
+ else
+ error = EIO;
+
+ goto out;
+ }
+ nbytes = gzc.inflated_size;
+
+ hdr = (Elf_Ehdr *)gzc.out_p;
+ }
+#endif
if (!IS_ELF(*hdr)) {
error = ENOEXEC;
@@ -819,7 +950,7 @@
* We rely on there being exactly two load segments, text and data,
* in that order.
*/
- phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff);
+ phdr = (Elf_Phdr *) ((caddr_t)hdr + hdr->e_phoff);
phlimit = phdr + hdr->e_phnum;
nsegs = 0;
phdyn = NULL;
@@ -872,11 +1003,11 @@
*/
base_offset = trunc_page(segs[0]->p_offset);
base_vaddr = trunc_page(segs[0]->p_vaddr);
- base_vlimit = round_page(segs[nsegs - 1]->p_vaddr +
+ base_vlimit = round_page(segs[nsegs - 1]->p_vaddr +
segs[nsegs - 1]->p_memsz);
mapsize = base_vlimit - base_vaddr;
- lf = linker_make_file(filename, &link_elf_class);
+ lf = linker_make_file(filename, cls);
if (lf == NULL) {
error = ENOMEM;
goto out;
@@ -908,13 +1039,20 @@
*/
for (i = 0; i < nsegs; i++) {
caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
- error = vn_rdwr(UIO_READ, nd.ni_vp,
- segbase, segs[i]->p_filesz, segs[i]->p_offset,
- UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
- &resid, td);
+#ifdef KLDGZELF
+ if (cls == &link_gzelf_class)
+ error = smemcpy(segbase, gzc.out_p, segs[i]->p_offset,
+ segs[i]->p_filesz, gzc.inflated_size);
+ else
+#endif
+ error = vn_rdwr(UIO_READ, nd.ni_vp,
+ segbase, segs[i]->p_filesz, segs[i]->p_offset,
+ UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
+ &resid, td);
+
if (error != 0)
goto out;
- bzero(segbase + segs[i]->p_filesz,
+ memset(segbase + segs[i]->p_filesz, 0,
segs[i]->p_memsz - segs[i]->p_filesz);
#ifdef SPARSE_MAPPING
@@ -975,10 +1113,17 @@
if (nbytes == 0 || hdr->e_shoff == 0)
goto nosyms;
shdr = malloc(nbytes, M_LINKER, M_WAITOK | M_ZERO);
- error = vn_rdwr(UIO_READ, nd.ni_vp,
- (caddr_t)shdr, nbytes, hdr->e_shoff,
- UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
- &resid, td);
+#ifdef KLDGZELF
+ if (cls == &link_gzelf_class)
+ error = smemcpy((caddr_t)shdr, gzc.out_p, hdr->e_shoff,
+ nbytes, gzc.inflated_size);
+ else
+#endif
+ error = vn_rdwr(UIO_READ, nd.ni_vp,
+ (caddr_t)shdr, nbytes, hdr->e_shoff,
+ UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
+ &resid, td);
+
if (error != 0)
goto out;
symtabindex = -1;
@@ -997,16 +1142,31 @@
strcnt = shdr[symstrindex].sh_size;
ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK);
- error = vn_rdwr(UIO_READ, nd.ni_vp,
- ef->symbase, symcnt, shdr[symtabindex].sh_offset,
- UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
- &resid, td);
+#ifdef KLDGZELF
+ if (cls == &link_gzelf_class)
+ error = smemcpy(ef->symbase, gzc.out_p, shdr[symtabindex].sh_offset,
+ symcnt, gzc.inflated_size);
+ else
+#endif
+ error = vn_rdwr(UIO_READ, nd.ni_vp,
+ ef->symbase, symcnt, shdr[symtabindex].sh_offset,
+ UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
+ &resid, td);
+
if (error != 0)
goto out;
- error = vn_rdwr(UIO_READ, nd.ni_vp,
- ef->strbase, strcnt, shdr[symstrindex].sh_offset,
- UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
- &resid, td);
+
+#ifdef KLDGZELF
+ if (cls == &link_gzelf_class)
+ error = smemcpy(ef->strbase, gzc.out_p, shdr[symstrindex].sh_offset,
+ strcnt, gzc.inflated_size);
+ else
+#endif
+ error = vn_rdwr(UIO_READ, nd.ni_vp,
+ ef->strbase, strcnt, shdr[symstrindex].sh_offset,
+ UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
+ &resid, td);
+
if (error != 0)
goto out;
@@ -1025,16 +1185,258 @@
out:
VOP_UNLOCK(nd.ni_vp, 0);
vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
+
if (error != 0 && lf != NULL)
linker_file_unload(lf, LINKER_UNLOAD_FORCE);
if (shdr != NULL)
free(shdr, M_LINKER);
+#ifdef KLDGZELF
+ if (cls == &link_gzelf_class)
+ free(gzc.out_p, M_LINKER);
+
+#endif
if (firstpage != NULL)
free(firstpage, M_LINKER);
return (error);
}
+#ifdef KLDGZELF
+
+/*
+ * Checks buffer for GZIP header.
+ *
+ * Returns: number of bytes skipped while processing header (> 0)
+ * or Z_DATA_ERROR (< 0) in case of failure
+ */
+static long
+gzhdr(u_char *p, int len)
+{
+ struct gz_hdr *hdr = (struct gz_hdr *)p;
+ u_short size = 0;
+ u_long total = sizeof(*hdr);
+
+ if (len < total)
+ return (Z_DATA_ERROR);
+
+ if (hdr->id1 != GZ_ID1 || hdr->id2 != GZ_ID2) {
+ return (Z_DATA_ERROR);
+ }
+
+ if (hdr->cm != GZ_CM) {
+ printf("Unsupported compression\n");
+ return (Z_DATA_ERROR);
+ }
+
+ p += sizeof(*hdr);
+
+ /* Process optional fields */
+ /* Extra field */
+ if (hdr->flags & GZ_FLG_FEXTRA) {
+ if (total + GZ_EXTRA_F_SIZE_SIZE > len)
+ return (Z_DATA_ERROR);
+
+ /*
+ * Extra field length, 2 bytes, does not include size
+ * itself.
+ */
+ if (len < (sizeof(*hdr) + GZ_EXTRA_F_SIZE_SIZE))
+ return (Z_DATA_ERROR);
+
+ size = *(u_short *)p;
+
+ total += GZ_EXTRA_F_SIZE_SIZE;
+ p += GZ_EXTRA_F_SIZE_SIZE;
+
+ if (total + size > len)
+ return (Z_DATA_ERROR);
+
+ total += size;
+ p += size;
+ }
+
+ /* Skip over the file name */
+ if (hdr->flags & GZ_FLG_FNAME) {
+ do {
+ if (total >= len)
+ return (Z_DATA_ERROR);
+ total++;
+ } while (*p++ != 0);
+ }
+
+ /* Skip comment */
+ if (hdr->flags & GZ_FLG_FCOMMENT) {
+ do {
+ if (total >= len)
+ return (Z_DATA_ERROR);
+ total++;
+ } while (*p++ != 0);
+ }
+
+ /* Header crc */
+ if (hdr->flags & GZ_FLG_FHCRC) {
+ total += 2;
+ if (total > len)
+ return (Z_DATA_ERROR);
+ }
+
+ /*
+ * Successfully went through gzip header, return number of
+ * octets processed
+ */
+ return (total);
+}
+
+
+/* zalloc/zfree are malloc/free wrappers for internal use by zlib */
+static void *
+zalloc(void *_up __unused, u_int items, u_int size)
+{
+
+ return (malloc(size*items, M_LINKER, M_WAITOK));
+}
+
+static void
+zfree(void *_up __unused, void *p)
+{
+
+ free(p, M_LINKER);
+}
+
+/*
+ * Inflates file into buffer returned via gzc.out_p pointer.
+ * In case of failure this pointer will be NULL and non 0
+ * (non-Z_OK) error zlib type code will be returned. In case when
+ * Z_ERRNO is returned, gzc.error contains errno.h defined
+ * code.
+ */
+static int
+gzelf_inflate(struct gzcontext *gzc)
+{
+ z_stream strm;
+ u_char *in_p = NULL;
+ int ret = Z_OK;
+ struct stat sb;
+ off_t off = 0;
+ ssize_t resid;
+ ssize_t loaded_bytes;
+
+ gzc->error = 0;
+ gzc->out_p = NULL;
+
+ memset(&strm, 0, sizeof(strm));
+ strm.zalloc = zalloc;
+ strm.zfree = zfree;
+
+ ret = inflateInit2(&strm, -15);
+ if (ret != Z_OK)
+ goto out;
+
+ ret = Z_ERRNO;
+
+ /* Alloc one page for purpose of checking if given file is
+ gzip file indeed and getting inflated file size */
+ in_p = malloc(PAGE_SIZE, M_LINKER, M_WAITOK);
+
+ gzc->error = vn_rdwr(UIO_READ, gzc->vd, in_p, PAGE_SIZE, 0,
+ UIO_SYSSPACE, IO_NODELOCKED, gzc->td->td_ucred, NOCRED,
+ &resid, gzc->td);
+
+ if (gzc->error != 0)
+ goto out;
+
+ ret = gzhdr(in_p, PAGE_SIZE - resid);
+
+ if (ret < 0) {
+ ret = Z_DATA_ERROR;
+ goto out;
+ }
+
+ gzc->skip = ret;
+
+ gzc->error = vn_stat(gzc->vd, &sb, gzc->td->td_ucred, NOCRED, gzc->td);
+ if (gzc->error != 0)
+ goto out;
+
+ gzc->error = vn_rdwr(UIO_READ, gzc->vd, in_p, PAGE_SIZE,
+ MAX(0, sb.st_size - PAGE_SIZE), UIO_SYSSPACE, IO_NODELOCKED,
+ gzc->td->td_ucred, NOCRED, &resid, gzc->td);
+ if (gzc->error != 0)
+ goto out;
+
+ /* Last four bytes of GZIPed file store size of inlated data */
+ loaded_bytes = PAGE_SIZE - resid;
+ gzc->inflated_size = *(u_int *)(in_p + loaded_bytes - GZ_INFLATED_SIZE_SIZE);
+
+ /* Be reasonable, 100MB of module is enough */
+ if (gzc->inflated_size > (100 * 1024 * 1024)) {
+ gzc->error = E2BIG;
+ goto out;
+ }
+
+ gzc->out_p = malloc(gzc->inflated_size, M_LINKER, M_WAITOK);
+
+ strm.avail_out = gzc->inflated_size;
+ strm.next_out = gzc->out_p;
+
+ do {
+ gzc->error = vn_rdwr(UIO_READ, gzc->vd, in_p, PAGE_SIZE,
+ off + gzc->skip, UIO_SYSSPACE, IO_NODELOCKED,
+ gzc->td->td_ucred, NOCRED, &resid, gzc->td);
+ if (gzc->error) {
+ ret = Z_ERRNO;
+ goto out;
+ }
+
+ strm.avail_in = PAGE_SIZE - resid;
+ strm.next_in = in_p;
+ off += strm.avail_in;
+
+ ret = inflate(&strm, Z_NO_FLUSH);
+ if (ret == Z_NEED_DICT)
+ ret = Z_DATA_ERROR;
+
+ /* All negative return codes mean error */
+ if (ret < 0)
+ goto out;
+
+ } while (strm.avail_out > 0 && ret != Z_STREAM_END);
+
+ /*
+ * We run out of buffer space for data and still have not inflated
+ * all of data.
+ */
+ if (strm.avail_out == 0 && ret == Z_OK)
+ ret = Z_DATA_ERROR;
+
+ /*
+ * Expected inflated size differs from obtained, something
+ * went wrong.
+ */
+ if (strm.avail_out != 0 && ret == Z_STREAM_END)
+ ret = Z_DATA_ERROR;
+
+ /* Return Z_OK if stream fully decompressed to avoid confusion */
+ if (ret == Z_STREAM_END)
+ ret = Z_OK;
+out:
+ /* Close file and release buffers */
+ inflateEnd(&strm);
+ free(in_p, M_LINKER);
+
+ if (ret != Z_OK) {
+ free(gzc->out_p, M_LINKER);
+ gzc->out_p = NULL;
+ }
+
+ if (gzc->error != 0)
+ return (Z_ERRNO);
+
+ return (ret);
+}
+
+#endif
+
Elf_Addr
elf_relocaddr(linker_file_t lf, Elf_Addr x)
{
@@ -1416,7 +1818,7 @@
elf_file_t ef = (elf_file_t)file;
const Elf_Sym *symp;
int i, error;
-
+
/* Exhaustive search */
for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
if (symp->st_value != 0 &&
@@ -1602,7 +2004,7 @@
return (ef->ddbsymcnt);
}
-
+
static long
link_elf_strtab_get(linker_file_t lf, caddr_t *strtab)
{

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 21, 6:29 AM (7 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27108796
Default Alt Text
D4324.diff (14 KB)

Event Timeline