diff options
| -rw-r--r-- | fs/squashfs/xz_wrapper.c | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c index 397adea72eb9..06d0d11b482a 100644 --- a/fs/squashfs/xz_wrapper.c +++ b/fs/squashfs/xz_wrapper.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include <linux/xz.h> | 28 | #include <linux/xz.h> |
| 29 | #include <linux/bitops.h> | ||
| 29 | 30 | ||
| 30 | #include "squashfs_fs.h" | 31 | #include "squashfs_fs.h" |
| 31 | #include "squashfs_fs_sb.h" | 32 | #include "squashfs_fs_sb.h" |
| @@ -38,25 +39,57 @@ struct squashfs_xz { | |||
| 38 | struct xz_buf buf; | 39 | struct xz_buf buf; |
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| 42 | struct comp_opts { | ||
| 43 | __le32 dictionary_size; | ||
| 44 | __le32 flags; | ||
| 45 | }; | ||
| 46 | |||
| 41 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, | 47 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, |
| 42 | int len) | 48 | int len) |
| 43 | { | 49 | { |
| 44 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | 50 | struct comp_opts *comp_opts = buff; |
| 51 | struct squashfs_xz *stream; | ||
| 52 | int dict_size = msblk->block_size; | ||
| 53 | int err, n; | ||
| 54 | |||
| 55 | if (comp_opts) { | ||
| 56 | /* check compressor options are the expected length */ | ||
| 57 | if (len < sizeof(*comp_opts)) { | ||
| 58 | err = -EIO; | ||
| 59 | goto failed; | ||
| 60 | } | ||
| 45 | 61 | ||
| 46 | struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL); | 62 | dict_size = le32_to_cpu(comp_opts->dictionary_size); |
| 47 | if (stream == NULL) | 63 | |
| 64 | /* the dictionary size should be 2^n or 2^n+2^(n+1) */ | ||
| 65 | n = ffs(dict_size) - 1; | ||
| 66 | if (dict_size != (1 << n) && dict_size != (1 << n) + | ||
| 67 | (1 << (n + 1))) { | ||
| 68 | err = -EIO; | ||
| 69 | goto failed; | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); | ||
| 74 | |||
| 75 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); | ||
| 76 | if (stream == NULL) { | ||
| 77 | err = -ENOMEM; | ||
| 48 | goto failed; | 78 | goto failed; |
| 79 | } | ||
| 49 | 80 | ||
| 50 | stream->state = xz_dec_init(XZ_PREALLOC, block_size); | 81 | stream->state = xz_dec_init(XZ_PREALLOC, dict_size); |
| 51 | if (stream->state == NULL) | 82 | if (stream->state == NULL) { |
| 83 | kfree(stream); | ||
| 84 | err = -ENOMEM; | ||
| 52 | goto failed; | 85 | goto failed; |
| 86 | } | ||
| 53 | 87 | ||
| 54 | return stream; | 88 | return stream; |
| 55 | 89 | ||
| 56 | failed: | 90 | failed: |
| 57 | ERROR("Failed to allocate xz workspace\n"); | 91 | ERROR("Failed to initialise xz decompressor\n"); |
| 58 | kfree(stream); | 92 | return ERR_PTR(err); |
| 59 | return ERR_PTR(-ENOMEM); | ||
| 60 | } | 93 | } |
| 61 | 94 | ||
| 62 | 95 | ||
