1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2021 Google LLC.
6 #include <linux/init.h>
7 #include <linux/highmem.h>
8 #include <linux/kobject.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/sysfs.h>
13 #include <linux/vmalloc.h>
17 static int module_extend_max_pages(struct load_info
*info
, unsigned int extent
)
19 struct page
**new_pages
;
21 new_pages
= kvmalloc_array(info
->max_pages
+ extent
,
22 sizeof(info
->pages
), GFP_KERNEL
);
26 memcpy(new_pages
, info
->pages
, info
->max_pages
* sizeof(info
->pages
));
28 info
->pages
= new_pages
;
29 info
->max_pages
+= extent
;
34 static struct page
*module_get_next_page(struct load_info
*info
)
39 if (info
->max_pages
== info
->used_pages
) {
40 error
= module_extend_max_pages(info
, info
->used_pages
);
42 return ERR_PTR(error
);
45 page
= alloc_page(GFP_KERNEL
| __GFP_HIGHMEM
);
47 return ERR_PTR(-ENOMEM
);
49 info
->pages
[info
->used_pages
++] = page
;
53 #if defined(CONFIG_MODULE_COMPRESS_GZIP)
54 #include <linux/zlib.h>
55 #define MODULE_COMPRESSION gzip
56 #define MODULE_DECOMPRESS_FN module_gzip_decompress
59 * Calculate length of the header which consists of signature, header
60 * flags, time stamp and operating system ID (10 bytes total), plus
61 * an optional filename.
63 static size_t module_gzip_header_len(const u8
*buf
, size_t size
)
65 const u8 signature
[] = { 0x1f, 0x8b, 0x08 };
68 if (size
< len
|| memcmp(buf
, signature
, sizeof(signature
)))
74 * If we can't find the end of the file name we must
75 * be dealing with a corrupted file.
79 } while (buf
[len
++] != '\0');
85 static ssize_t
module_gzip_decompress(struct load_info
*info
,
86 const void *buf
, size_t size
)
88 struct z_stream_s s
= { 0 };
94 gzip_hdr_len
= module_gzip_header_len(buf
, size
);
96 pr_err("not a gzip compressed module\n");
100 s
.next_in
= buf
+ gzip_hdr_len
;
101 s
.avail_in
= size
- gzip_hdr_len
;
103 s
.workspace
= kvmalloc(zlib_inflate_workspacesize(), GFP_KERNEL
);
107 rc
= zlib_inflateInit2(&s
, -MAX_WBITS
);
109 pr_err("failed to initialize decompressor: %d\n", rc
);
115 struct page
*page
= module_get_next_page(info
);
118 retval
= PTR_ERR(page
);
119 goto out_inflate_end
;
122 s
.next_out
= kmap_local_page(page
);
123 s
.avail_out
= PAGE_SIZE
;
124 rc
= zlib_inflate(&s
, 0);
125 kunmap_local(s
.next_out
);
127 new_size
+= PAGE_SIZE
- s
.avail_out
;
128 } while (rc
== Z_OK
);
130 if (rc
!= Z_STREAM_END
) {
131 pr_err("decompression failed with status %d\n", rc
);
133 goto out_inflate_end
;
144 #elif defined(CONFIG_MODULE_COMPRESS_XZ)
145 #include <linux/xz.h>
146 #define MODULE_COMPRESSION xz
147 #define MODULE_DECOMPRESS_FN module_xz_decompress
149 static ssize_t
module_xz_decompress(struct load_info
*info
,
150 const void *buf
, size_t size
)
152 static const u8 signature
[] = { 0xfd, '7', 'z', 'X', 'Z', 0 };
153 struct xz_dec
*xz_dec
;
154 struct xz_buf xz_buf
;
159 if (size
< sizeof(signature
) ||
160 memcmp(buf
, signature
, sizeof(signature
))) {
161 pr_err("not an xz compressed module\n");
165 xz_dec
= xz_dec_init(XZ_DYNALLOC
, (u32
)-1);
169 xz_buf
.in_size
= size
;
174 struct page
*page
= module_get_next_page(info
);
177 retval
= PTR_ERR(page
);
181 xz_buf
.out
= kmap_local_page(page
);
183 xz_buf
.out_size
= PAGE_SIZE
;
184 xz_ret
= xz_dec_run(xz_dec
, &xz_buf
);
185 kunmap_local(xz_buf
.out
);
187 new_size
+= xz_buf
.out_pos
;
188 } while (xz_buf
.out_pos
== PAGE_SIZE
&& xz_ret
== XZ_OK
);
190 if (xz_ret
!= XZ_STREAM_END
) {
191 pr_err("decompression failed with status %d\n", xz_ret
);
202 #elif defined(CONFIG_MODULE_COMPRESS_ZSTD)
203 #include <linux/zstd.h>
204 #define MODULE_COMPRESSION zstd
205 #define MODULE_DECOMPRESS_FN module_zstd_decompress
207 static ssize_t
module_zstd_decompress(struct load_info
*info
,
208 const void *buf
, size_t size
)
210 static const u8 signature
[] = { 0x28, 0xb5, 0x2f, 0xfd };
211 ZSTD_outBuffer zstd_dec
;
212 ZSTD_inBuffer zstd_buf
;
213 zstd_frame_header header
;
216 ZSTD_DStream
*dstream
;
221 if (size
< sizeof(signature
) ||
222 memcmp(buf
, signature
, sizeof(signature
))) {
223 pr_err("not a zstd compressed module\n");
229 zstd_buf
.size
= size
;
231 ret
= zstd_get_frame_header(&header
, zstd_buf
.src
, zstd_buf
.size
);
233 pr_err("ZSTD-compressed data has an incomplete frame header\n");
237 if (header
.windowSize
> (1 << ZSTD_WINDOWLOG_MAX
)) {
238 pr_err("ZSTD-compressed data has too large a window size\n");
243 wksp_size
= zstd_dstream_workspace_bound(header
.windowSize
);
244 wksp
= kvmalloc(wksp_size
, GFP_KERNEL
);
250 dstream
= zstd_init_dstream(header
.windowSize
, wksp
, wksp_size
);
252 pr_err("Can't initialize ZSTD stream\n");
258 struct page
*page
= module_get_next_page(info
);
261 retval
= PTR_ERR(page
);
265 zstd_dec
.dst
= kmap_local_page(page
);
267 zstd_dec
.size
= PAGE_SIZE
;
269 ret
= zstd_decompress_stream(dstream
, &zstd_dec
, &zstd_buf
);
270 kunmap_local(zstd_dec
.dst
);
271 retval
= zstd_get_error_code(ret
);
275 new_size
+= zstd_dec
.pos
;
276 } while (zstd_dec
.pos
== PAGE_SIZE
&& ret
!= 0);
279 pr_err("ZSTD-decompression failed with status %d\n", retval
);
291 #error "Unexpected configuration for CONFIG_MODULE_DECOMPRESS"
294 int module_decompress(struct load_info
*info
, const void *buf
, size_t size
)
296 unsigned int n_pages
;
300 #if defined(CONFIG_MODULE_STATS)
301 info
->compressed_len
= size
;
305 * Start with number of pages twice as big as needed for
308 n_pages
= DIV_ROUND_UP(size
, PAGE_SIZE
) * 2;
309 error
= module_extend_max_pages(info
, n_pages
);
311 data_size
= MODULE_DECOMPRESS_FN(info
, buf
, size
);
317 info
->hdr
= vmap(info
->pages
, info
->used_pages
, VM_MAP
, PAGE_KERNEL
);
323 info
->len
= data_size
;
327 module_decompress_cleanup(info
);
331 void module_decompress_cleanup(struct load_info
*info
)
338 for (i
= 0; i
< info
->used_pages
; i
++)
339 __free_page(info
->pages
[i
]);
344 info
->max_pages
= info
->used_pages
= 0;
348 static ssize_t
compression_show(struct kobject
*kobj
,
349 struct kobj_attribute
*attr
, char *buf
)
351 return sysfs_emit(buf
, __stringify(MODULE_COMPRESSION
) "\n");
354 static struct kobj_attribute module_compression_attr
= __ATTR_RO(compression
);
356 static int __init
module_decompress_sysfs_init(void)
360 error
= sysfs_create_file(&module_kset
->kobj
,
361 &module_compression_attr
.attr
);
363 pr_warn("Failed to create 'compression' attribute");
367 late_initcall(module_decompress_sysfs_init
);