On 22/04/30 10:08PM, Eric Biggers wrote:
> From: Eric Biggers <[email protected]>
>
> Since ext4 was converted to the new mount API, the test_dummy_encryption
> mount option isn't being handled entirely correctly, because the needed
> fscrypt_set_test_dummy_encryption() helper function combines
> parsing/checking/applying into one function.  That doesn't work well
> with the new mount API, which split these into separate steps.
>
> This was sort of okay anyway, due to the parsing logic that was copied
> from fscrypt_set_test_dummy_encryption() into ext4_parse_param(),
> combined with an additional check in ext4_check_test_dummy_encryption().
> However, these overlooked the case of changing the value of
> test_dummy_encryption on remount, which isn't allowed but ext4 wasn't
> detecting until ext4_apply_options() when it's too late to fail.
> Another bug is that if test_dummy_encryption was specified multiple
> times with an argument, memory was leaked.
>
> Fix this up properly by using the new helper functions that allow
> splitting up the parse/check/apply steps for test_dummy_encryption.
>
> Fixes: cebe85d570cf ("ext4: switch to the new mount api")
> Signed-off-by: Eric Biggers <[email protected]>

I just had a small observation. Feel free to check it at your end too.


> ---
>  fs/ext4/ext4.h  |   6 ---
>  fs/ext4/super.c | 131 +++++++++++++++++++++++++-----------------------
>  2 files changed, 67 insertions(+), 70 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index a743b1e3b89ec..f6d6661817b63 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -1440,12 +1440,6 @@ struct ext4_super_block {
>
>  #ifdef __KERNEL__
>
> -#ifdef CONFIG_FS_ENCRYPTION
> -#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != 
> NULL)
> -#else
> -#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
> -#endif
> -
>  /* Number of quota types we support */
>  #define EXT4_MAXQUOTAS 3
>
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 64ce17714e193..43e4cd358b33b 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -87,7 +87,7 @@ static struct inode *ext4_get_journal_inode(struct 
> super_block *sb,
>  static int ext4_validate_options(struct fs_context *fc);
>  static int ext4_check_opt_consistency(struct fs_context *fc,
>                                     struct super_block *sb);
> -static int ext4_apply_options(struct fs_context *fc, struct super_block *sb);
> +static void ext4_apply_options(struct fs_context *fc, struct super_block 
> *sb);
>  static int ext4_parse_param(struct fs_context *fc, struct fs_parameter 
> *param);
>  static int ext4_get_tree(struct fs_context *fc);
>  static int ext4_reconfigure(struct fs_context *fc);
> @@ -1989,31 +1989,12 @@ ext4_sb_read_encoding(const struct ext4_super_block 
> *es)
>  }
>  #endif
>
> -static int ext4_set_test_dummy_encryption(struct super_block *sb, char *arg)
> -{
> -#ifdef CONFIG_FS_ENCRYPTION
> -     struct ext4_sb_info *sbi = EXT4_SB(sb);
> -     int err;
> -
> -     err = fscrypt_set_test_dummy_encryption(sb, arg,
> -                                             &sbi->s_dummy_enc_policy);
> -     if (err) {
> -             ext4_msg(sb, KERN_WARNING,
> -                      "Error while setting test dummy encryption [%d]", err);
> -             return err;
> -     }
> -     ext4_msg(sb, KERN_WARNING, "Test dummy encryption mode enabled");
> -#endif
> -     return 0;
> -}
> -
>  #define EXT4_SPEC_JQUOTA                     (1 <<  0)
>  #define EXT4_SPEC_JQFMT                              (1 <<  1)
>  #define EXT4_SPEC_DATAJ                              (1 <<  2)
>  #define EXT4_SPEC_SB_BLOCK                   (1 <<  3)
>  #define EXT4_SPEC_JOURNAL_DEV                        (1 <<  4)
>  #define EXT4_SPEC_JOURNAL_IOPRIO             (1 <<  5)
> -#define EXT4_SPEC_DUMMY_ENCRYPTION           (1 <<  6)
>  #define EXT4_SPEC_s_want_extra_isize         (1 <<  7)
>  #define EXT4_SPEC_s_max_batch_time           (1 <<  8)
>  #define EXT4_SPEC_s_min_batch_time           (1 <<  9)
> @@ -2030,7 +2011,7 @@ static int ext4_set_test_dummy_encryption(struct 
> super_block *sb, char *arg)
>
>  struct ext4_fs_context {
>       char            *s_qf_names[EXT4_MAXQUOTAS];
> -     char            *test_dummy_enc_arg;
> +     struct fscrypt_dummy_policy dummy_enc_policy;
>       int             s_jquota_fmt;   /* Format of quota to use */
>  #ifdef CONFIG_EXT4_DEBUG
>       int s_fc_debug_max_replay;
> @@ -2061,9 +2042,8 @@ struct ext4_fs_context {
>       ext4_fsblk_t    s_sb_block;
>  };
>
> -static void ext4_fc_free(struct fs_context *fc)
> +static void __ext4_fc_free(struct ext4_fs_context *ctx)
>  {
> -     struct ext4_fs_context *ctx = fc->fs_private;
>       int i;
>
>       if (!ctx)
> @@ -2072,10 +2052,15 @@ static void ext4_fc_free(struct fs_context *fc)
>       for (i = 0; i < EXT4_MAXQUOTAS; i++)
>               kfree(ctx->s_qf_names[i]);
>
> -     kfree(ctx->test_dummy_enc_arg);
> +     fscrypt_free_dummy_policy(&ctx->dummy_enc_policy);
>       kfree(ctx);
>  }
>
> +static void ext4_fc_free(struct fs_context *fc)
> +{
> +     __ext4_fc_free(fc->fs_private);
> +}
> +
>  int ext4_init_fs_context(struct fs_context *fc)
>  {
>       struct ext4_fs_context *ctx;
> @@ -2148,6 +2133,29 @@ static int unnote_qf_name(struct fs_context *fc, int 
> qtype)
>  }
>  #endif
>
> +static int ext4_parse_test_dummy_encryption(const struct fs_parameter *param,
> +                                         struct ext4_fs_context *ctx)
> +{
> +     int err;
> +
> +     if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) {
> +             ext4_msg(NULL, KERN_WARNING,
> +                      "test_dummy_encryption option not supported");
> +             return -EINVAL;
> +     }
> +     err = fscrypt_parse_test_dummy_encryption(param,
> +                                               &ctx->dummy_enc_policy);
> +     if (err == -EINVAL) {
> +             ext4_msg(NULL, KERN_WARNING,
> +                      "Value of option \"%s\" is unrecognized", param->key);
> +     } else if (err == -EEXIST) {
> +             ext4_msg(NULL, KERN_WARNING,
> +                      "Conflicting test_dummy_encryption options");
> +             return -EINVAL;
> +     }
> +     return err;
> +}
> +
>  #define EXT4_SET_CTX(name)                                           \
>  static inline void ctx_set_##name(struct ext4_fs_context *ctx,               
> \
>                                 unsigned long flag)                   \
> @@ -2410,29 +2418,7 @@ static int ext4_parse_param(struct fs_context *fc, 
> struct fs_parameter *param)
>               ctx->spec |= EXT4_SPEC_JOURNAL_IOPRIO;
>               return 0;
>       case Opt_test_dummy_encryption:
> -#ifdef CONFIG_FS_ENCRYPTION
> -             if (param->type == fs_value_is_flag) {
> -                     ctx->spec |= EXT4_SPEC_DUMMY_ENCRYPTION;
> -                     ctx->test_dummy_enc_arg = NULL;
> -                     return 0;
> -             }
> -             if (*param->string &&
> -                 !(!strcmp(param->string, "v1") ||
> -                   !strcmp(param->string, "v2"))) {
> -                     ext4_msg(NULL, KERN_WARNING,
> -                              "Value of option \"%s\" is unrecognized",
> -                              param->key);
> -                     return -EINVAL;
> -             }
> -             ctx->spec |= EXT4_SPEC_DUMMY_ENCRYPTION;
> -             ctx->test_dummy_enc_arg = kmemdup_nul(param->string, 
> param->size,
> -                                                   GFP_KERNEL);
> -             return 0;
> -#else
> -             ext4_msg(NULL, KERN_WARNING,
> -                      "test_dummy_encryption option not supported");
> -             return -EINVAL;
> -#endif
> +             return ext4_parse_test_dummy_encryption(param, ctx);
>       case Opt_dax:
>       case Opt_dax_type:
>  #ifdef CONFIG_FS_DAX
> @@ -2623,10 +2609,11 @@ static int parse_apply_sb_mount_options(struct 
> super_block *sb,
>       if (s_ctx->spec & EXT4_SPEC_JOURNAL_IOPRIO)
>               m_ctx->journal_ioprio = s_ctx->journal_ioprio;
>
> -     ret = ext4_apply_options(fc, sb);
> +     ext4_apply_options(fc, sb);
> +     ret = 0;
>
>  out_free:
> -     kfree(s_ctx);
> +     __ext4_fc_free(s_ctx);

I think we can still call ext4_fc_free(fc) and we don't need __ext4_fc_free().
Right?

-ritesh


>       kfree(fc);
>       kfree(s_mount_opts);
>       return ret;
> @@ -2792,9 +2779,9 @@ static int ext4_check_test_dummy_encryption(const 
> struct fs_context *fc,
>  {
>       const struct ext4_fs_context *ctx = fc->fs_private;
>       const struct ext4_sb_info *sbi = EXT4_SB(sb);
> +     int err;
>
> -     if (!IS_ENABLED(CONFIG_FS_ENCRYPTION) ||
> -         !(ctx->spec & EXT4_SPEC_DUMMY_ENCRYPTION))
> +     if (!fscrypt_is_dummy_policy_set(&ctx->dummy_enc_policy))
>               return 0;
>
>       if (!ext4_has_feature_encrypt(sb)) {
> @@ -2808,13 +2795,35 @@ static int ext4_check_test_dummy_encryption(const 
> struct fs_context *fc,
>        * needed to allow it to be set or changed during remount.  We do allow
>        * it to be specified during remount, but only if there is no change.
>        */
> -     if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE &&
> -         !DUMMY_ENCRYPTION_ENABLED(sbi)) {
> +     if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
> +             if (fscrypt_dummy_policies_equal(&sbi->s_dummy_enc_policy,
> +                                              &ctx->dummy_enc_policy))
> +                     return 0;
>               ext4_msg(NULL, KERN_WARNING,
> -                      "Can't set test_dummy_encryption on remount");
> +                      "Can't set or change test_dummy_encryption on 
> remount");
>               return -EINVAL;
>       }
> -     return 0;
> +     /*
> +      * fscrypt_add_test_dummy_key() technically changes the super_block, so
> +      * it technically should be delayed until ext4_apply_options() like the
> +      * other changes.  But since we never get here for remounts (see above),
> +      * and this is the last chance to report errors, we do it here.
> +      */
> +     err = fscrypt_add_test_dummy_key(sb, &ctx->dummy_enc_policy);
> +     if (err)
> +             ext4_msg(NULL, KERN_WARNING,
> +                      "Error adding test dummy encryption key [%d]", err);
> +     return err;
> +}
> +
> +static void ext4_apply_test_dummy_encryption(struct ext4_fs_context *ctx,
> +                                          struct super_block *sb)
> +{
> +     if (!fscrypt_is_dummy_policy_set(&ctx->dummy_enc_policy))
> +             return;
> +     EXT4_SB(sb)->s_dummy_enc_policy = ctx->dummy_enc_policy;
> +     memset(&ctx->dummy_enc_policy, 0, sizeof(ctx->dummy_enc_policy));
> +     ext4_msg(sb, KERN_WARNING, "Test dummy encryption mode enabled");
>  }
>
>  static int ext4_check_opt_consistency(struct fs_context *fc,
> @@ -2901,11 +2910,10 @@ static int ext4_check_opt_consistency(struct 
> fs_context *fc,
>       return ext4_check_quota_consistency(fc, sb);
>  }
>
> -static int ext4_apply_options(struct fs_context *fc, struct super_block *sb)
> +static void ext4_apply_options(struct fs_context *fc, struct super_block *sb)
>  {
>       struct ext4_fs_context *ctx = fc->fs_private;
>       struct ext4_sb_info *sbi = fc->s_fs_info;
> -     int ret = 0;
>
>       sbi->s_mount_opt &= ~ctx->mask_s_mount_opt;
>       sbi->s_mount_opt |= ctx->vals_s_mount_opt;
> @@ -2942,10 +2950,7 @@ static int ext4_apply_options(struct fs_context *fc, 
> struct super_block *sb)
>
>       ext4_apply_quota_options(fc, sb);
>
> -     if (ctx->spec & EXT4_SPEC_DUMMY_ENCRYPTION)
> -             ret = ext4_set_test_dummy_encryption(sb, 
> ctx->test_dummy_enc_arg);
> -
> -     return ret;
> +     ext4_apply_test_dummy_encryption(ctx, sb);
>  }
>
>
> @@ -4667,9 +4672,7 @@ static int __ext4_fill_super(struct fs_context *fc, 
> struct super_block *sb)
>       if (err < 0)
>               goto failed_mount;
>
> -     err = ext4_apply_options(fc, sb);
> -     if (err < 0)
> -             goto failed_mount;
> +     ext4_apply_options(fc, sb);
>
>  #if IS_ENABLED(CONFIG_UNICODE)
>       if (ext4_has_feature_casefold(sb) && !sb->s_encoding) {
> --
> 2.36.0
>


_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to