1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Copyright © 2024 Intel Corporation
*/
#define DLSYM_LOCALLY_ENABLED ENABLE_ZLIB_DLOPEN
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <zlib.h>
#include <shared/elf-note.h>
#include <shared/util.h>
#include "libkmod.h"
#include "libkmod-internal.h"
#include "libkmod-internal-file.h"
#define READ_STEP (4 * 1024 * 1024)
#define DL_SYMBOL_TABLE(M) \
M(gzclose) \
M(gzdopen) \
M(gzerror) \
M(gzread)
DL_SYMBOL_TABLE(DECLARE_SYM)
static int dlopen_zlib(void)
{
#if !DLSYM_LOCALLY_ENABLED
return 0;
#else
static void *dl = NULL;
ELF_NOTE_DLOPEN("zlib", "Support for uncompressing zlib-compressed modules",
ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, "libz.so.1");
return dlsym_many(&dl, "libz.so.1", DL_SYMBOL_TABLE(DLSYM_ARG) NULL);
#endif
}
int kmod_file_load_zlib(struct kmod_file *file)
{
_cleanup_free_ unsigned char *p = NULL;
int ret = 0;
off_t did = 0, total = 0;
gzFile gzf;
int gzfd;
ret = dlopen_zlib();
if (ret < 0) {
ERR(file->ctx, "zlib: can't load and resolve symbols (%s)",
strerror(-ret));
return -EINVAL;
}
errno = 0;
gzfd = fcntl(file->fd, F_DUPFD_CLOEXEC, 3);
if (gzfd < 0)
return -errno;
gzf = sym_gzdopen(gzfd, "rb"); /* takes ownership of the fd */
if (gzf == NULL) {
close(gzfd);
return -errno;
}
for (;;) {
int r;
if (did == total) {
void *tmp = realloc(p, total + READ_STEP);
if (tmp == NULL) {
ret = -errno;
goto error;
}
total += READ_STEP;
p = tmp;
}
r = sym_gzread(gzf, p + did, total - did);
if (r == 0)
break;
else if (r < 0) {
int gzerr;
const char *gz_errmsg = sym_gzerror(gzf, &gzerr);
ERR(file->ctx, "gzip: %s\n", gz_errmsg);
/* gzip might not set errno here */
ret = gzerr == Z_ERRNO ? -errno : -EINVAL;
goto error;
}
did += r;
}
file->memory = TAKE_PTR(p);
file->size = did;
sym_gzclose(gzf);
return 0;
error:
sym_gzclose(gzf);
return ret;
}
|