#include <linux/fs.h>
#include <linux/fs_context.h>
#include <linux/poll.h>
-#include <linux/zlib.h>
+#include <linux/zstd.h>
#include <uapi/linux/major.h>
#include <uapi/linux/magic.h>
SEQ_RAWDATA_FOPS(hash);
SEQ_RAWDATA_FOPS(compressed_size);
-static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen)
+static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen)
{
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
- if (aa_g_rawdata_compression_level != 0) {
- int error = 0;
- struct z_stream_s strm;
-
- memset(&strm, 0, sizeof(strm));
-
- strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
- if (!strm.workspace)
- return -ENOMEM;
-
- strm.next_in = src;
- strm.avail_in = slen;
-
- error = zlib_inflateInit(&strm);
- if (error != Z_OK) {
- error = -ENOMEM;
- goto fail_inflate_init;
+ if (aa_g_rawdata_compression_level == 0) {
+ const size_t wksp_len = zstd_dctx_workspace_bound();
+ zstd_dctx *ctx;
+ void *wksp;
+ size_t out_len;
+ int ret = 0;
+
+ wksp = kvzalloc(wksp_len, GFP_KERNEL);
+ if (!wksp) {
+ ret = -ENOMEM;
+ goto cleanup;
}
- strm.next_out = dst;
- strm.avail_out = dlen;
-
- error = zlib_inflate(&strm, Z_FINISH);
- if (error != Z_STREAM_END)
- error = -EINVAL;
- else
- error = 0;
-
- zlib_inflateEnd(&strm);
-fail_inflate_init:
- kvfree(strm.workspace);
-
- return error;
+ out_len = zstd_decompress_dctx(ctx, dst, dlen, src, slen);
+ if (zstd_is_error(out_len)) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+cleanup:
+ kvfree(wksp);
+ return ret;
}
#endif
private->loaddata = loaddata;
- error = deflate_decompress(loaddata->data, loaddata->compressed_size,
- RAWDATA_F_DATA_BUF(private),
- loaddata->size);
+ error = decompress_zstd(loaddata->data, loaddata->compressed_size,
+ RAWDATA_F_DATA_BUF(private),
+ loaddata->size);
if (error)
goto fail_decompress;
#include <linux/user_namespace.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
-#include <linux/zlib.h>
+#include <linux/zstd.h>
#include <net/sock.h>
#include <uapi/linux/mount.h>
#endif
/* policy loaddata compression level */
-int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION;
+int aa_g_rawdata_compression_level = ZSTD_CLEVEL_DEFAULT;
module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
aacompressionlevel, 0400);
error = param_set_int(val, kp);
aa_g_rawdata_compression_level = clamp(aa_g_rawdata_compression_level,
- Z_NO_COMPRESSION,
- Z_BEST_COMPRESSION);
- pr_info("AppArmor: policy rawdata compression level set to %u\n",
+ zstd_min_clevel(),
+ zstd_max_clevel());
+ pr_info("AppArmor: policy rawdata compression level set to %d\n",
aa_g_rawdata_compression_level);
return error;
#include <asm/unaligned.h>
#include <linux/ctype.h>
#include <linux/errno.h>
-#include <linux/zlib.h>
+#include <linux/zstd.h>
#include "include/apparmor.h"
#include "include/audit.h"
return ent;
}
-static int deflate_compress(const char *src, size_t slen, char **dst,
- size_t *dlen)
+static int compress_zstd(const char *src, size_t slen, char **dst, size_t *dlen)
{
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
- int error;
- struct z_stream_s strm;
- void *stgbuf, *dstbuf;
- size_t stglen = deflateBound(slen);
-
- memset(&strm, 0, sizeof(strm));
-
- if (stglen < slen)
- return -EFBIG;
-
- strm.workspace = kvzalloc(zlib_deflate_workspacesize(MAX_WBITS,
- MAX_MEM_LEVEL),
- GFP_KERNEL);
- if (!strm.workspace)
- return -ENOMEM;
-
- error = zlib_deflateInit(&strm, aa_g_rawdata_compression_level);
- if (error != Z_OK) {
- error = -ENOMEM;
- goto fail_deflate_init;
+ const zstd_parameters params =
+ zstd_get_params(aa_g_rawdata_compression_level, slen);
+ const size_t wksp_len = zstd_cctx_workspace_bound(¶ms.cParams);
+ void *wksp = NULL;
+ zstd_cctx *ctx = NULL;
+ size_t out_len = zstd_compress_bound(slen);
+ void *out = NULL;
+ int ret = 0;
+
+ out = kvzalloc(out_len, GFP_KERNEL);
+ if (!out) {
+ ret = -ENOMEM;
+ goto cleanup;
}
- stgbuf = kvzalloc(stglen, GFP_KERNEL);
- if (!stgbuf) {
- error = -ENOMEM;
- goto fail_stg_alloc;
+ wksp = kvzalloc(wksp_len, GFP_KERNEL);
+ if (!wksp) {
+ ret = -ENOMEM;
+ goto cleanup;
}
- strm.next_in = src;
- strm.avail_in = slen;
- strm.next_out = stgbuf;
- strm.avail_out = stglen;
+ ctx = zstd_init_cctx(wksp, wksp_len);
+ if (!ctx) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
- error = zlib_deflate(&strm, Z_FINISH);
- if (error != Z_STREAM_END) {
- error = -EINVAL;
- goto fail_deflate;
+ out_len = zstd_compress_cctx(ctx, out, out_len, src, slen, ¶ms);
+ if (zstd_is_error(out_len)) {
+ ret = -EINVAL;
+ goto cleanup;
}
- error = 0;
- if (is_vmalloc_addr(stgbuf)) {
- dstbuf = kvzalloc(strm.total_out, GFP_KERNEL);
- if (dstbuf) {
- memcpy(dstbuf, stgbuf, strm.total_out);
- kvfree(stgbuf);
+ if (is_vmalloc_addr(out)) {
+ *dst = kvzalloc(out_len, GFP_KERNEL);
+ if (*dst) {
+ memcpy(*dst, out, out_len);
+ kvfree(out);
+ out = NULL;
}
- } else
+ } else {
/*
* If the staging buffer was kmalloc'd, then using krealloc is
* probably going to be faster. The destination buffer will
* always be smaller, so it's just shrunk, avoiding a memcpy
*/
- dstbuf = krealloc(stgbuf, strm.total_out, GFP_KERNEL);
+ *dst = krealloc(out, out_len, GFP_KERNEL);
+ }
- if (!dstbuf) {
- error = -ENOMEM;
- goto fail_deflate;
+ if (!*dst) {
+ ret = -ENOMEM;
+ goto cleanup;
}
- *dst = dstbuf;
- *dlen = strm.total_out;
+ *dlen = out_len;
-fail_stg_alloc:
- zlib_deflateEnd(&strm);
-fail_deflate_init:
- kvfree(strm.workspace);
- return error;
+cleanup:
+ if (ret) {
+ kvfree(out);
+ *dst = NULL;
+ }
-fail_deflate:
- kvfree(stgbuf);
- goto fail_stg_alloc;
+ kvfree(wksp);
+ return ret;
#else
*dlen = slen;
return 0;
static int compress_loaddata(struct aa_loaddata *data)
{
-
AA_BUG(data->compressed_size > 0);
/*
*/
if (aa_g_rawdata_compression_level != 0) {
void *udata = data->data;
- int error = deflate_compress(udata, data->size, &data->data,
- &data->compressed_size);
+ int error = compress_zstd(udata, data->size, &data->data,
+ &data->compressed_size);
if (error)
return error;