Skip to content

Commit 378b2ea

Browse files
Daniel Vacekkdave
authored andcommitted
btrfs: harden parsing of compress mount option
Btrfs happily but incorrectly accepts the `-o compress=zlib+foo` and similar options with any random suffix. Let's handle that correctly. Signed-off-by: Daniel Vacek <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent f9a578a commit 378b2ea

File tree

1 file changed

+62
-46
lines changed

1 file changed

+62
-46
lines changed

fs/btrfs/super.c

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,67 @@ static inline blk_mode_t btrfs_open_mode(struct fs_context *fc)
267267
return sb_open_mode(fc->sb_flags) & ~BLK_OPEN_RESTRICT_WRITES;
268268
}
269269

270+
static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
271+
struct fs_parameter *param, int opt)
272+
{
273+
/*
274+
* Provide the same semantics as older kernels that don't use fs
275+
* context, specifying the "compress" option clears
276+
* "force-compress" without the need to pass
277+
* "compress-force=[no|none]" before specifying "compress".
278+
*/
279+
if (opt != Opt_compress_force && opt != Opt_compress_force_type)
280+
btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
281+
282+
if (opt == Opt_compress || opt == Opt_compress_force) {
283+
ctx->compress_type = BTRFS_COMPRESS_ZLIB;
284+
ctx->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
285+
btrfs_set_opt(ctx->mount_opt, COMPRESS);
286+
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
287+
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
288+
} else if (strncmp(param->string, "zlib", 4) == 0 &&
289+
(param->string[4] == ':' ||
290+
param->string[4] == '\0')) {
291+
ctx->compress_type = BTRFS_COMPRESS_ZLIB;
292+
ctx->compress_level =
293+
btrfs_compress_str2level(BTRFS_COMPRESS_ZLIB,
294+
param->string + 4);
295+
btrfs_set_opt(ctx->mount_opt, COMPRESS);
296+
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
297+
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
298+
} else if (strncmp(param->string, "lzo", 3) == 0 &&
299+
param->string[3] == '\0') {
300+
ctx->compress_type = BTRFS_COMPRESS_LZO;
301+
ctx->compress_level = 0;
302+
btrfs_set_opt(ctx->mount_opt, COMPRESS);
303+
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
304+
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
305+
} else if (strncmp(param->string, "zstd", 4) == 0 &&
306+
(param->string[4] == ':' ||
307+
param->string[4] == '\0')) {
308+
ctx->compress_type = BTRFS_COMPRESS_ZSTD;
309+
ctx->compress_level =
310+
btrfs_compress_str2level(BTRFS_COMPRESS_ZSTD,
311+
param->string + 4);
312+
btrfs_set_opt(ctx->mount_opt, COMPRESS);
313+
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
314+
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
315+
} else if ((strncmp(param->string, "no", 2) == 0 &&
316+
param->string[2] == '\0') ||
317+
(strncmp(param->string, "none", 4) == 0 &&
318+
param->string[4] == '\0')) {
319+
ctx->compress_level = 0;
320+
ctx->compress_type = 0;
321+
btrfs_clear_opt(ctx->mount_opt, COMPRESS);
322+
btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
323+
} else {
324+
btrfs_err(NULL, "unrecognized compression value %s",
325+
param->string);
326+
return -EINVAL;
327+
}
328+
return 0;
329+
}
330+
270331
static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
271332
{
272333
struct btrfs_fs_context *ctx = fc->fs_private;
@@ -336,53 +397,8 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
336397
fallthrough;
337398
case Opt_compress:
338399
case Opt_compress_type:
339-
/*
340-
* Provide the same semantics as older kernels that don't use fs
341-
* context, specifying the "compress" option clears
342-
* "force-compress" without the need to pass
343-
* "compress-force=[no|none]" before specifying "compress".
344-
*/
345-
if (opt != Opt_compress_force && opt != Opt_compress_force_type)
346-
btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
347-
348-
if (opt == Opt_compress || opt == Opt_compress_force) {
349-
ctx->compress_type = BTRFS_COMPRESS_ZLIB;
350-
ctx->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
351-
btrfs_set_opt(ctx->mount_opt, COMPRESS);
352-
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
353-
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
354-
} else if (strncmp(param->string, "zlib", 4) == 0) {
355-
ctx->compress_type = BTRFS_COMPRESS_ZLIB;
356-
ctx->compress_level =
357-
btrfs_compress_str2level(BTRFS_COMPRESS_ZLIB,
358-
param->string + 4);
359-
btrfs_set_opt(ctx->mount_opt, COMPRESS);
360-
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
361-
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
362-
} else if (strncmp(param->string, "lzo", 3) == 0) {
363-
ctx->compress_type = BTRFS_COMPRESS_LZO;
364-
ctx->compress_level = 0;
365-
btrfs_set_opt(ctx->mount_opt, COMPRESS);
366-
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
367-
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
368-
} else if (strncmp(param->string, "zstd", 4) == 0) {
369-
ctx->compress_type = BTRFS_COMPRESS_ZSTD;
370-
ctx->compress_level =
371-
btrfs_compress_str2level(BTRFS_COMPRESS_ZSTD,
372-
param->string + 4);
373-
btrfs_set_opt(ctx->mount_opt, COMPRESS);
374-
btrfs_clear_opt(ctx->mount_opt, NODATACOW);
375-
btrfs_clear_opt(ctx->mount_opt, NODATASUM);
376-
} else if (strncmp(param->string, "no", 2) == 0) {
377-
ctx->compress_level = 0;
378-
ctx->compress_type = 0;
379-
btrfs_clear_opt(ctx->mount_opt, COMPRESS);
380-
btrfs_clear_opt(ctx->mount_opt, FORCE_COMPRESS);
381-
} else {
382-
btrfs_err(NULL, "unrecognized compression value %s",
383-
param->string);
400+
if (btrfs_parse_compress(ctx, param, opt))
384401
return -EINVAL;
385-
}
386402
break;
387403
case Opt_ssd:
388404
if (result.negated) {

0 commit comments

Comments
 (0)