0001
0002
0003
0004
0005
0006 #include <linux/init.h>
0007 #include <linux/highmem.h>
0008 #include <linux/kobject.h>
0009 #include <linux/mm.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/sysfs.h>
0013 #include <linux/vmalloc.h>
0014
0015 #include "internal.h"
0016
0017 static int module_extend_max_pages(struct load_info *info, unsigned int extent)
0018 {
0019 struct page **new_pages;
0020
0021 new_pages = kvmalloc_array(info->max_pages + extent,
0022 sizeof(info->pages), GFP_KERNEL);
0023 if (!new_pages)
0024 return -ENOMEM;
0025
0026 memcpy(new_pages, info->pages, info->max_pages * sizeof(info->pages));
0027 kvfree(info->pages);
0028 info->pages = new_pages;
0029 info->max_pages += extent;
0030
0031 return 0;
0032 }
0033
0034 static struct page *module_get_next_page(struct load_info *info)
0035 {
0036 struct page *page;
0037 int error;
0038
0039 if (info->max_pages == info->used_pages) {
0040 error = module_extend_max_pages(info, info->used_pages);
0041 if (error)
0042 return ERR_PTR(error);
0043 }
0044
0045 page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
0046 if (!page)
0047 return ERR_PTR(-ENOMEM);
0048
0049 info->pages[info->used_pages++] = page;
0050 return page;
0051 }
0052
0053 #ifdef CONFIG_MODULE_COMPRESS_GZIP
0054 #include <linux/zlib.h>
0055 #define MODULE_COMPRESSION gzip
0056 #define MODULE_DECOMPRESS_FN module_gzip_decompress
0057
0058
0059
0060
0061
0062
0063 static size_t module_gzip_header_len(const u8 *buf, size_t size)
0064 {
0065 const u8 signature[] = { 0x1f, 0x8b, 0x08 };
0066 size_t len = 10;
0067
0068 if (size < len || memcmp(buf, signature, sizeof(signature)))
0069 return 0;
0070
0071 if (buf[3] & 0x08) {
0072 do {
0073
0074
0075
0076
0077 if (len == size)
0078 return 0;
0079 } while (buf[len++] != '\0');
0080 }
0081
0082 return len;
0083 }
0084
0085 static ssize_t module_gzip_decompress(struct load_info *info,
0086 const void *buf, size_t size)
0087 {
0088 struct z_stream_s s = { 0 };
0089 size_t new_size = 0;
0090 size_t gzip_hdr_len;
0091 ssize_t retval;
0092 int rc;
0093
0094 gzip_hdr_len = module_gzip_header_len(buf, size);
0095 if (!gzip_hdr_len) {
0096 pr_err("not a gzip compressed module\n");
0097 return -EINVAL;
0098 }
0099
0100 s.next_in = buf + gzip_hdr_len;
0101 s.avail_in = size - gzip_hdr_len;
0102
0103 s.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
0104 if (!s.workspace)
0105 return -ENOMEM;
0106
0107 rc = zlib_inflateInit2(&s, -MAX_WBITS);
0108 if (rc != Z_OK) {
0109 pr_err("failed to initialize decompressor: %d\n", rc);
0110 retval = -EINVAL;
0111 goto out;
0112 }
0113
0114 do {
0115 struct page *page = module_get_next_page(info);
0116
0117 if (!page) {
0118 retval = -ENOMEM;
0119 goto out_inflate_end;
0120 }
0121
0122 s.next_out = kmap_local_page(page);
0123 s.avail_out = PAGE_SIZE;
0124 rc = zlib_inflate(&s, 0);
0125 kunmap_local(s.next_out);
0126
0127 new_size += PAGE_SIZE - s.avail_out;
0128 } while (rc == Z_OK);
0129
0130 if (rc != Z_STREAM_END) {
0131 pr_err("decompression failed with status %d\n", rc);
0132 retval = -EINVAL;
0133 goto out_inflate_end;
0134 }
0135
0136 retval = new_size;
0137
0138 out_inflate_end:
0139 zlib_inflateEnd(&s);
0140 out:
0141 kfree(s.workspace);
0142 return retval;
0143 }
0144 #elif CONFIG_MODULE_COMPRESS_XZ
0145 #include <linux/xz.h>
0146 #define MODULE_COMPRESSION xz
0147 #define MODULE_DECOMPRESS_FN module_xz_decompress
0148
0149 static ssize_t module_xz_decompress(struct load_info *info,
0150 const void *buf, size_t size)
0151 {
0152 static const u8 signature[] = { 0xfd, '7', 'z', 'X', 'Z', 0 };
0153 struct xz_dec *xz_dec;
0154 struct xz_buf xz_buf;
0155 enum xz_ret xz_ret;
0156 size_t new_size = 0;
0157 ssize_t retval;
0158
0159 if (size < sizeof(signature) ||
0160 memcmp(buf, signature, sizeof(signature))) {
0161 pr_err("not an xz compressed module\n");
0162 return -EINVAL;
0163 }
0164
0165 xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1);
0166 if (!xz_dec)
0167 return -ENOMEM;
0168
0169 xz_buf.in_size = size;
0170 xz_buf.in = buf;
0171 xz_buf.in_pos = 0;
0172
0173 do {
0174 struct page *page = module_get_next_page(info);
0175
0176 if (!page) {
0177 retval = -ENOMEM;
0178 goto out;
0179 }
0180
0181 xz_buf.out = kmap_local_page(page);
0182 xz_buf.out_pos = 0;
0183 xz_buf.out_size = PAGE_SIZE;
0184 xz_ret = xz_dec_run(xz_dec, &xz_buf);
0185 kunmap_local(xz_buf.out);
0186
0187 new_size += xz_buf.out_pos;
0188 } while (xz_buf.out_pos == PAGE_SIZE && xz_ret == XZ_OK);
0189
0190 if (xz_ret != XZ_STREAM_END) {
0191 pr_err("decompression failed with status %d\n", xz_ret);
0192 retval = -EINVAL;
0193 goto out;
0194 }
0195
0196 retval = new_size;
0197
0198 out:
0199 xz_dec_end(xz_dec);
0200 return retval;
0201 }
0202 #else
0203 #error "Unexpected configuration for CONFIG_MODULE_DECOMPRESS"
0204 #endif
0205
0206 int module_decompress(struct load_info *info, const void *buf, size_t size)
0207 {
0208 unsigned int n_pages;
0209 ssize_t data_size;
0210 int error;
0211
0212
0213
0214
0215
0216 n_pages = DIV_ROUND_UP(size, PAGE_SIZE) * 2;
0217 error = module_extend_max_pages(info, n_pages);
0218
0219 data_size = MODULE_DECOMPRESS_FN(info, buf, size);
0220 if (data_size < 0) {
0221 error = data_size;
0222 goto err;
0223 }
0224
0225 info->hdr = vmap(info->pages, info->used_pages, VM_MAP, PAGE_KERNEL);
0226 if (!info->hdr) {
0227 error = -ENOMEM;
0228 goto err;
0229 }
0230
0231 info->len = data_size;
0232 return 0;
0233
0234 err:
0235 module_decompress_cleanup(info);
0236 return error;
0237 }
0238
0239 void module_decompress_cleanup(struct load_info *info)
0240 {
0241 int i;
0242
0243 if (info->hdr)
0244 vunmap(info->hdr);
0245
0246 for (i = 0; i < info->used_pages; i++)
0247 __free_page(info->pages[i]);
0248
0249 kvfree(info->pages);
0250
0251 info->pages = NULL;
0252 info->max_pages = info->used_pages = 0;
0253 }
0254
0255 #ifdef CONFIG_SYSFS
0256 static ssize_t compression_show(struct kobject *kobj,
0257 struct kobj_attribute *attr, char *buf)
0258 {
0259 return sysfs_emit(buf, "%s\n", __stringify(MODULE_COMPRESSION));
0260 }
0261
0262 static struct kobj_attribute module_compression_attr = __ATTR_RO(compression);
0263
0264 static int __init module_decompress_sysfs_init(void)
0265 {
0266 int error;
0267
0268 error = sysfs_create_file(&module_kset->kobj,
0269 &module_compression_attr.attr);
0270 if (error)
0271 pr_warn("Failed to create 'compression' attribute");
0272
0273 return 0;
0274 }
0275 late_initcall(module_decompress_sysfs_init);
0276 #endif