Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F140102606
D4324.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D4324.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D4324: Support for GZIP compressed modules within kldload
Attached
Detach File
Event Timeline
Log In to Comment