From a1d288086fd7cd9b3835343073ce2d627bb6f56b Mon Sep 17 00:00:00 2001 From: nbd Date: Wed, 2 Sep 2009 17:42:35 +0000 Subject: [PATCH] get rid of dynamic buffer struct allocation during pcomp lzma decompression and instead force the caller to provide the maximum buffer list size git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17475 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../052-pcomp_lzma_support.patch | 70 +++++++++++++++---- .../patches-2.6.30/053-squashfs_lzma.patch | 46 +++++++++--- 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch b/target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch index 75dfc376a..afb37a80c 100644 --- a/target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch +++ b/target/linux/generic-2.6/patches-2.6.30/052-pcomp_lzma_support.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/crypto/unlzma.c -@@ -0,0 +1,723 @@ +@@ -0,0 +1,748 @@ +/* + * LZMA uncompresion module for pcomp + * Copyright (C) 2009 Felix Fietkau @@ -36,12 +36,12 @@ +#include + +#include ++#include +#include "unlzma.h" + +static int instance = 0; + +struct unlzma_buffer { -+ struct unlzma_buffer *last; + int offset; + int size; + u8 *ptr; @@ -68,8 +68,10 @@ + /* writer state */ + u8 previous_byte; + ssize_t pos; -+ struct unlzma_buffer *head; + int buf_full; ++ int n_buffers; ++ int buffers_max; ++ struct unlzma_buffer *buffers; + + /* cstate */ + int state; @@ -92,12 +94,11 @@ +{ + struct unlzma_buffer *bh; + -+ bh = kzalloc(sizeof(struct unlzma_buffer), GFP_KERNEL); ++ BUG_ON(ctx->n_buffers >= ctx->buffers_max); ++ bh = &ctx->buffers[ctx->n_buffers++]; + bh->ptr = ctx->next_out; + bh->offset = ctx->pos; -+ bh->last = ctx->head; + bh->size = ctx->avail_out; -+ ctx->head = bh; + ctx->buf_full = 0; +} + @@ -208,17 +209,20 @@ +static u8 +peek_old_byte(struct unlzma_ctx *ctx, u32 offs) +{ -+ struct unlzma_buffer *bh = ctx->head; ++ struct unlzma_buffer *bh = &ctx->buffers[ctx->n_buffers - 1]; ++ int i = ctx->n_buffers; + u32 pos; + ++ BUG_ON(!ctx->n_buffers); + pos = ctx->pos - offs; + if (pos >= ctx->dict_size) { + pos = (~pos % ctx->dict_size); + } + + while (bh->offset > pos) { -+ bh = bh->last; -+ BUG_ON(!bh); ++ bh--; ++ i--; ++ BUG_ON(!i); + } + + pos -= bh->offset; @@ -460,6 +464,7 @@ + hdr_buf[i] = rc_read(ctx); + } + ++ ctx->n_buffers = 0; + ctx->pos = 0; + get_buffer(ctx); + ctx->active = true; @@ -554,11 +559,6 @@ + unlzma_reset_buf(ctx); + ctx->cancel = false; + ctx->active = false; -+ while (ctx->head) { -+ struct unlzma_buffer *bh = ctx->head; -+ ctx->head = bh->last; -+ kfree(bh); -+ } + } while (!kthread_should_stop()); + mutex_unlock(&ctx->mutex); + return 0; @@ -598,6 +598,10 @@ + unlzma_cancel(ctx); + kthread_stop(ctx->thread); + ctx->thread = NULL; ++ if (ctx->buffers) ++ kfree(ctx->buffers); ++ ctx->buffers_max = 0; ++ ctx->buffers = NULL; + } +} + @@ -605,10 +609,31 @@ +unlzma_decompress_setup(struct crypto_pcomp *tfm, void *p, unsigned int len) +{ + struct unlzma_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); ++ struct nlattr *tb[UNLZMA_DECOMP_MAX + 1]; + int ret = 0; + + if (ctx->thread) -+ return 0; ++ return -EINVAL; ++ ++ if (!p) ++ return -EINVAL; ++ ++ ret = nla_parse(tb, UNLZMA_DECOMP_MAX, p, len, NULL); ++ if (!tb[UNLZMA_DECOMP_OUT_BUFFERS]) ++ return -EINVAL; ++ ++ if (ctx->buffers_max && (ctx->buffers_max < ++ nla_get_u32(tb[UNLZMA_DECOMP_OUT_BUFFERS]))) { ++ kfree(ctx->buffers); ++ ctx->buffers_max = 0; ++ ctx->buffers = NULL; ++ } ++ if (!ctx->buffers) { ++ ctx->buffers_max = nla_get_u32(tb[UNLZMA_DECOMP_OUT_BUFFERS]); ++ ctx->buffers = kzalloc(sizeof(struct unlzma_buffer) * ctx->buffers_max, GFP_KERNEL); ++ } ++ if (!ctx->buffers) ++ return -ENOMEM; + + mutex_init(&ctx->mutex); + init_waitqueue_head(&ctx->next_req); @@ -832,3 +857,18 @@ +#define LZMA_LITERAL (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS) + +#endif +--- a/include/crypto/compress.h ++++ b/include/crypto/compress.h +@@ -49,6 +49,12 @@ enum zlib_decomp_params { + + #define ZLIB_DECOMP_MAX (__ZLIB_DECOMP_MAX - 1) + ++enum unlzma_decomp_params { ++ UNLZMA_DECOMP_OUT_BUFFERS = 1, /* naximum number of output buffers */ ++ __UNLZMA_DECOMP_MAX, ++}; ++#define UNLZMA_DECOMP_MAX (__UNLZMA_DECOMP_MAX - 1) ++ + + struct crypto_pcomp { + struct crypto_tfm base; diff --git a/target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch b/target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch index 35208fd7a..19deb7335 100644 --- a/target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch +++ b/target/linux/generic-2.6/patches-2.6.30/053-squashfs_lzma.patch @@ -47,7 +47,7 @@ __le32 s_magic; --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c -@@ -47,13 +47,65 @@ +@@ -47,13 +47,76 @@ #include "squashfs.h" @@ -81,7 +81,7 @@ + crypto_free_pcomp(msblk->tfm); + } +#endif - ++ + return err; +} + @@ -90,6 +90,17 @@ + int err = -EOPNOTSUPP; + +#ifdef CONFIG_SQUASHFS_SUPPORT_LZMA ++ struct { ++ struct nlattr nla; ++ int val; ++ } params = { ++ .nla = { ++ .nla_len = nla_attr_size(sizeof(int)), ++ .nla_type = UNLZMA_DECOMP_OUT_BUFFERS, ++ }, ++ .val = (msblk->block_size / PAGE_CACHE_SIZE) + 1 ++ }; + + msblk->tfm = crypto_alloc_pcomp("lzma", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(msblk->tfm)) { @@ -97,7 +108,7 @@ + return PTR_ERR(msblk->tfm); + } + -+ err = crypto_decompress_setup(msblk->tfm, NULL, 0); ++ err = crypto_decompress_setup(msblk->tfm, ¶ms, sizeof(params)); + if (err) { + ERROR("Failed to set up decompression parameters\n"); + crypto_free_pcomp(msblk->tfm); @@ -115,7 +126,7 @@ { if (major < SQUASHFS_MAJOR) { ERROR("Major/Minor mismatch, older Squashfs %d.%d " -@@ -66,9 +118,6 @@ static int supported_squashfs_filesystem +@@ -66,9 +129,6 @@ static int supported_squashfs_filesystem return -EINVAL; } @@ -125,7 +136,7 @@ return 0; } -@@ -83,16 +132,6 @@ static int squashfs_fill_super(struct su +@@ -83,16 +143,6 @@ static int squashfs_fill_super(struct su unsigned short flags; unsigned int fragments; u64 lookup_table_start; @@ -142,7 +153,7 @@ int err; TRACE("Entered squashfs_fill_superblock\n"); -@@ -104,21 +143,6 @@ static int squashfs_fill_super(struct su +@@ -104,21 +154,6 @@ static int squashfs_fill_super(struct su } msblk = sb->s_fs_info; @@ -164,8 +175,15 @@ sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); if (sblk == NULL) { ERROR("Failed to allocate squashfs_super_block\n"); -@@ -158,8 +182,21 @@ static int squashfs_fill_super(struct su +@@ -156,10 +191,28 @@ static int squashfs_fill_super(struct su + goto failed_mount; + } ++ /* Check block size for sanity */ ++ msblk->block_size = le32_to_cpu(sblk->block_size); ++ if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE) ++ goto failed_mount; ++ /* Check the MAJOR & MINOR versions and compression type */ err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major), - le16_to_cpu(sblk->s_minor), @@ -188,7 +206,19 @@ if (err < 0) goto failed_mount; -@@ -315,21 +352,16 @@ allocate_root: +@@ -179,11 +232,6 @@ static int squashfs_fill_super(struct su + i_size_read(sb->s_bdev->bd_inode)) + goto failed_mount; + +- /* Check block size for sanity */ +- msblk->block_size = le32_to_cpu(sblk->block_size); +- if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE) +- goto failed_mount; +- + /* + * Check the system page size is not larger than the filesystem + * block size (by default 128K). This is currently not supported. +@@ -315,21 +363,16 @@ allocate_root: return 0; failed_mount: