diff options
author | Aaron Tomlin <atomlin@redhat.com> | 2022-03-22 14:03:31 +0000 |
---|---|---|
committer | Luis Chamberlain <mcgrof@kernel.org> | 2022-04-04 12:57:54 -0700 |
commit | cfc1d277891eb499b3b5354df33b30f598683e90 (patch) | |
tree | 18ab4d95c01c03aecb020d1458854871a649fba3 /kernel/module_decompress.c | |
parent | 3123109284176b1532874591f7c81f3837bbdc17 (diff) |
module: Move all into module/
No functional changes.
This patch moves all module related code into a separate directory,
modifies each file name and creates a new Makefile. Note: this effort
is in preparation to refactor core module code.
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Diffstat (limited to 'kernel/module_decompress.c')
-rw-r--r-- | kernel/module_decompress.c | 273 |
1 files changed, 0 insertions, 273 deletions
diff --git a/kernel/module_decompress.c b/kernel/module_decompress.c deleted file mode 100644 index ffef98a20320..000000000000 --- a/kernel/module_decompress.c +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2021 Google LLC. - */ - -#include <linux/init.h> -#include <linux/highmem.h> -#include <linux/kobject.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/vmalloc.h> - -#include "module-internal.h" - -static int module_extend_max_pages(struct load_info *info, unsigned int extent) -{ - struct page **new_pages; - - new_pages = kvmalloc_array(info->max_pages + extent, - sizeof(info->pages), GFP_KERNEL); - if (!new_pages) - return -ENOMEM; - - memcpy(new_pages, info->pages, info->max_pages * sizeof(info->pages)); - kvfree(info->pages); - info->pages = new_pages; - info->max_pages += extent; - - return 0; -} - -static struct page *module_get_next_page(struct load_info *info) -{ - struct page *page; - int error; - - if (info->max_pages == info->used_pages) { - error = module_extend_max_pages(info, info->used_pages); - if (error) - return ERR_PTR(error); - } - - page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (!page) - return ERR_PTR(-ENOMEM); - - info->pages[info->used_pages++] = page; - return page; -} - -#ifdef CONFIG_MODULE_COMPRESS_GZIP -#include <linux/zlib.h> -#define MODULE_COMPRESSION gzip -#define MODULE_DECOMPRESS_FN module_gzip_decompress - -/* - * Calculate length of the header which consists of signature, header - * flags, time stamp and operating system ID (10 bytes total), plus - * an optional filename. - */ -static size_t module_gzip_header_len(const u8 *buf, size_t size) -{ - const u8 signature[] = { 0x1f, 0x8b, 0x08 }; - size_t len = 10; - - if (size < len || memcmp(buf, signature, sizeof(signature))) - return 0; - - if (buf[3] & 0x08) { - do { - /* - * If we can't find the end of the file name we must - * be dealing with a corrupted file. - */ - if (len == size) - return 0; - } while (buf[len++] != '\0'); - } - - return len; -} - -static ssize_t module_gzip_decompress(struct load_info *info, - const void *buf, size_t size) -{ - struct z_stream_s s = { 0 }; - size_t new_size = 0; - size_t gzip_hdr_len; - ssize_t retval; - int rc; - - gzip_hdr_len = module_gzip_header_len(buf, size); - if (!gzip_hdr_len) { - pr_err("not a gzip compressed module\n"); - return -EINVAL; - } - - s.next_in = buf + gzip_hdr_len; - s.avail_in = size - gzip_hdr_len; - - s.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (!s.workspace) - return -ENOMEM; - - rc = zlib_inflateInit2(&s, -MAX_WBITS); - if (rc != Z_OK) { - pr_err("failed to initialize decompressor: %d\n", rc); - retval = -EINVAL; - goto out; - } - - do { - struct page *page = module_get_next_page(info); - if (!page) { - retval = -ENOMEM; - goto out_inflate_end; - } - - s.next_out = kmap(page); - s.avail_out = PAGE_SIZE; - rc = zlib_inflate(&s, 0); - kunmap(page); - - new_size += PAGE_SIZE - s.avail_out; - } while (rc == Z_OK); - - if (rc != Z_STREAM_END) { - pr_err("decompression failed with status %d\n", rc); - retval = -EINVAL; - goto out_inflate_end; - } - - retval = new_size; - -out_inflate_end: - zlib_inflateEnd(&s); -out: - kfree(s.workspace); - return retval; -} -#elif CONFIG_MODULE_COMPRESS_XZ -#include <linux/xz.h> -#define MODULE_COMPRESSION xz -#define MODULE_DECOMPRESS_FN module_xz_decompress - -static ssize_t module_xz_decompress(struct load_info *info, - const void *buf, size_t size) -{ - static const u8 signature[] = { 0xfd, '7', 'z', 'X', 'Z', 0 }; - struct xz_dec *xz_dec; - struct xz_buf xz_buf; - enum xz_ret xz_ret; - size_t new_size = 0; - ssize_t retval; - - if (size < sizeof(signature) || - memcmp(buf, signature, sizeof(signature))) { - pr_err("not an xz compressed module\n"); - return -EINVAL; - } - - xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1); - if (!xz_dec) - return -ENOMEM; - - xz_buf.in_size = size; - xz_buf.in = buf; - xz_buf.in_pos = 0; - - do { - struct page *page = module_get_next_page(info); - if (!page) { - retval = -ENOMEM; - goto out; - } - - xz_buf.out = kmap(page); - xz_buf.out_pos = 0; - xz_buf.out_size = PAGE_SIZE; - xz_ret = xz_dec_run(xz_dec, &xz_buf); - kunmap(page); - - new_size += xz_buf.out_pos; - } while (xz_buf.out_pos == PAGE_SIZE && xz_ret == XZ_OK); - - if (xz_ret != XZ_STREAM_END) { - pr_err("decompression failed with status %d\n", xz_ret); - retval = -EINVAL; - goto out; - } - - retval = new_size; - - out: - xz_dec_end(xz_dec); - return retval; -} -#else -#error "Unexpected configuration for CONFIG_MODULE_DECOMPRESS" -#endif - -int module_decompress(struct load_info *info, const void *buf, size_t size) -{ - unsigned int n_pages; - ssize_t data_size; - int error; - - /* - * Start with number of pages twice as big as needed for - * compressed data. - */ - n_pages = DIV_ROUND_UP(size, PAGE_SIZE) * 2; - error = module_extend_max_pages(info, n_pages); - - data_size = MODULE_DECOMPRESS_FN(info, buf, size); - if (data_size < 0) { - error = data_size; - goto err; - } - - info->hdr = vmap(info->pages, info->used_pages, VM_MAP, PAGE_KERNEL); - if (!info->hdr) { - error = -ENOMEM; - goto err; - } - - info->len = data_size; - return 0; - -err: - module_decompress_cleanup(info); - return error; -} - -void module_decompress_cleanup(struct load_info *info) -{ - int i; - - if (info->hdr) - vunmap(info->hdr); - - for (i = 0; i < info->used_pages; i++) - __free_page(info->pages[i]); - - kvfree(info->pages); - - info->pages = NULL; - info->max_pages = info->used_pages = 0; -} - -#ifdef CONFIG_SYSFS -static ssize_t compression_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "%s\n", __stringify(MODULE_COMPRESSION)); -} -static struct kobj_attribute module_compression_attr = __ATTR_RO(compression); - -static int __init module_decompress_sysfs_init(void) -{ - int error; - - error = sysfs_create_file(&module_kset->kobj, - &module_compression_attr.attr); - if (error) - pr_warn("Failed to create 'compression' attribute"); - - return 0; -} -late_initcall(module_decompress_sysfs_init); -#endif |