mirror of
https://github.com/kmod-project/kmod.git
synced 2026-01-27 01:44:26 +00:00
Currently our codebase has a mix of explicitly using ENOMEM and propagating the errno... The latter of which is guaranteed to be ENOMEM as documented in the manual pages. Consolidate on ENOMEM, both for consistency sake and to remove a few bytes off our binaries ;-) Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com> Link: https://github.com/kmod-project/kmod/pull/368 Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
121 lines
2.4 KiB
C
121 lines
2.4 KiB
C
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
/*
|
|
* Copyright © 2024 Intel Corporation
|
|
*/
|
|
|
|
#define DLSYM_LOCALLY_ENABLED ENABLE_ZSTD_DLOPEN
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <zstd.h>
|
|
|
|
#include <shared/elf-note.h>
|
|
#include <shared/util.h>
|
|
|
|
#include "libkmod.h"
|
|
#include "libkmod-internal.h"
|
|
#include "libkmod-internal-file.h"
|
|
|
|
#define DL_SYMBOL_TABLE(M) \
|
|
M(ZSTD_decompress) \
|
|
M(ZSTD_getErrorName) \
|
|
M(ZSTD_getFrameContentSize) \
|
|
M(ZSTD_isError)
|
|
|
|
DL_SYMBOL_TABLE(DECLARE_SYM)
|
|
|
|
static int dlopen_zstd(void)
|
|
{
|
|
#if !DLSYM_LOCALLY_ENABLED
|
|
return 0;
|
|
#else
|
|
static void *dl;
|
|
|
|
ELF_NOTE_DLOPEN("zstd", "Support for uncompressing zstd-compressed modules",
|
|
ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, "libzstd.so.1");
|
|
|
|
return dlsym_many(&dl, "libzstd.so.1", DL_SYMBOL_TABLE(DLSYM_ARG) NULL);
|
|
#endif
|
|
}
|
|
|
|
int kmod_file_load_zstd(struct kmod_file *file)
|
|
{
|
|
void *src_buf = MAP_FAILED, *dst_buf = NULL;
|
|
size_t src_size, dst_size;
|
|
unsigned long long frame_size;
|
|
struct stat st;
|
|
int ret;
|
|
|
|
ret = dlopen_zstd();
|
|
if (ret < 0) {
|
|
ERR(file->ctx, "zstd: can't load and resolve symbols (%s)",
|
|
strerror(-ret));
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (fstat(file->fd, &st) < 0) {
|
|
ret = -errno;
|
|
ERR(file->ctx, "zstd: %m\n");
|
|
goto out;
|
|
}
|
|
|
|
if ((uintmax_t)st.st_size > SIZE_MAX) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
src_size = st.st_size;
|
|
src_buf = mmap(NULL, src_size, PROT_READ, MAP_PRIVATE, file->fd, 0);
|
|
if (src_buf == MAP_FAILED) {
|
|
ret = -errno;
|
|
goto out;
|
|
}
|
|
|
|
frame_size = sym_ZSTD_getFrameContentSize(src_buf, src_size);
|
|
if (frame_size == 0 || frame_size == ZSTD_CONTENTSIZE_UNKNOWN ||
|
|
frame_size == ZSTD_CONTENTSIZE_ERROR) {
|
|
ret = -EINVAL;
|
|
ERR(file->ctx, "zstd: Failed to determine decompression size\n");
|
|
goto out;
|
|
}
|
|
|
|
if (frame_size > SIZE_MAX) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
dst_size = frame_size;
|
|
dst_buf = malloc(dst_size);
|
|
if (dst_buf == NULL) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
dst_size = sym_ZSTD_decompress(dst_buf, dst_size, src_buf, src_size);
|
|
if (sym_ZSTD_isError(dst_size)) {
|
|
ERR(file->ctx, "zstd: %s\n", sym_ZSTD_getErrorName(dst_size));
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
file->memory = dst_buf;
|
|
file->size = dst_size;
|
|
|
|
ret = 0;
|
|
dst_buf = NULL;
|
|
|
|
out:
|
|
free(dst_buf);
|
|
|
|
if (src_buf != MAP_FAILED)
|
|
munmap(src_buf, src_size);
|
|
|
|
return ret;
|
|
}
|