[Devel] [patch] ext: prevent panic inside of containers
Dmitry
dmonakhov at openvz.org
Mon Jan 24 04:40:46 PST 2011
On Mon, 24 Jan 2011 13:50:35 +0300, Vasiliy Kulikov <segoon at openwall.com> wrote:
> Hi,
>
> Currently root inside of container may mount crappy ext2/ext3 filesystem
> with option errors=panic and cause global HN panic. It can be triggered
> with either loop forwarding enabled or any writable block device. E.g.
> with loop device:
>
> dd if=/dev/zero of=image bs=1024 count=1024
> mkfs.ext2 -F image
> head -c 10000 image >image2
> mount -o loop,errors=panic image2 /mnt
> ls /mnt => kernel panic
>
> The patch forbids setting panic option via both "mount -o" and
> in-superblock option inside of containers. Mount option would fail;
> in-superblock option would be skipped and default "errors=continue"
> would be set. Both event types are logged.
This is no sufficient to make loopdev safe.
Loop devices inside container is very dangerous thing because
others filesystems (except ext234) has no well defined panic semantics,
so there is no guaranties what system survives after critical fs error.
BTW: in case of bad will frequent loop device corruption inside
container result in massive dangerous messages which makes HW-node
administrator's life a complete nightmare.
That's why loop device is prohibited inside container by default.
>
> Ideally full emulation should reboot/shutdown container in case of panic'able
> error, but it doesn't worth it :-)
>
>
> Tested on 194.26.1.el5.028stab079.1.
>
>
> Signed-off-by: Vasiliy Kulikov <segoon at openwall.com>
>
> diff --git a/fs/ext2/super.c b/fs/ext2/super.c
> index 65035cc..3e35dde 100644
> --- a/fs/ext2/super.c
> +++ b/fs/ext2/super.c
> @@ -366,6 +366,7 @@ static int parse_options (char * options,
> char * p;
> substring_t args[MAX_OPT_ARGS];
> int option;
> + struct ve_struct *env;
>
> if (!options)
> return 1;
> @@ -404,6 +405,12 @@ static int parse_options (char * options,
> /* *sb_block = match_int(&args[0]); */
> break;
> case Opt_err_panic:
> + env = get_exec_env();
> + if (!ve_is_super(env)) {
> + printk(KERN_ERR "EXT2 may not be mounted with "
> + "errors=panic inside of container (VEID=%d)\n", env->veid);
> + return 0;
> + }
> clear_opt (sbi->s_mount_opt, ERRORS_CONT);
> clear_opt (sbi->s_mount_opt, ERRORS_RO);
> set_opt (sbi->s_mount_opt, ERRORS_PANIC);
> @@ -651,6 +658,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
> int db_count;
> int i, j;
> __le32 features;
> + struct ve_struct *env = get_exec_env();
>
> sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
> if (!sbi)
> @@ -715,9 +723,16 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
> #endif
> }
>
> - if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
> - set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO)
> + if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) {
> + if (!ve_is_super(env)) {
> + printk(KERN_WARNING "EXT2 may not be mounted with "
> + "errors=panic inside of container (VEID=%d), "
> + "ignoring option in superblock.\n", env->veid);
> + set_opt(sbi->s_mount_opt, ERRORS_CONT);
> + } else {
> + set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> + }
> + } else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO)
> set_opt(sbi->s_mount_opt, ERRORS_RO);
> else
> set_opt(sbi->s_mount_opt, ERRORS_CONT);
> diff --git a/fs/ext3/super.c b/fs/ext3/super.c
> index b15212b..2817f2b 100644
> --- a/fs/ext3/super.c
> +++ b/fs/ext3/super.c
> @@ -792,6 +792,7 @@ static int parse_options (char *options, struct super_block *sb,
> int qtype;
> char *qname;
> #endif
> + struct ve_struct *env;
>
> if (!options)
> return 1;
> @@ -830,6 +831,12 @@ static int parse_options (char *options, struct super_block *sb,
> /* *sb_block = match_int(&args[0]); */
> break;
> case Opt_err_panic:
> + env = get_exec_env();
> + if (!ve_is_super(env)) {
> + printk(KERN_ERR "EXT3 may not be mounted with "
> + "errors=panic inside of container (VEID=%d)\n", env->veid);
> + return 0;
> + }
> clear_opt (sbi->s_mount_opt, ERRORS_CONT);
> clear_opt (sbi->s_mount_opt, ERRORS_RO);
> set_opt (sbi->s_mount_opt, ERRORS_PANIC);
> @@ -1438,6 +1445,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
> int i;
> int needs_recovery;
> __le32 features;
> + struct ve_struct *env = get_exec_env();
>
> sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
> if (!sbi)
> @@ -1505,9 +1513,16 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
> else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_WBACK)
> sbi->s_mount_opt |= EXT3_MOUNT_WRITEBACK_DATA;
>
> - if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC)
> - set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
> + if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) {
> + if (!ve_is_super(env)) {
> + printk(KERN_WARNING "EXT3 may not be mounted with "
> + "errors=panic inside of container (VEID=%d), "
> + "ignoring option in superblock.\n", env->veid);
> + set_opt(sbi->s_mount_opt, ERRORS_CONT);
> + } else {
> + set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> + }
> + } else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
> set_opt(sbi->s_mount_opt, ERRORS_RO);
> else
> set_opt(sbi->s_mount_opt, ERRORS_CONT);
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 7e546bc..076b762 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1192,6 +1192,7 @@ static int parse_options(char *options, struct super_block *sb,
> int qtype, qfmt;
> char *qname;
> #endif
> + struct ve_struct *env;
>
> if (!options)
> return 1;
> @@ -1230,6 +1231,12 @@ static int parse_options(char *options, struct super_block *sb,
> /* *sb_block = match_int(&args[0]); */
> break;
> case Opt_err_panic:
> + env = get_exec_env();
> + if (!ve_is_super(env)) {
> + printk(KERN_ERR "EXT4 may not be mounted with "
> + "errors=panic inside of container (VEID=%d)\n", env->veid);
> + return 0;
> + }
> clear_opt(sbi->s_mount_opt, ERRORS_CONT);
> clear_opt(sbi->s_mount_opt, ERRORS_RO);
> set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> @@ -2351,6 +2358,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> __u64 blocks_count;
> int err;
> unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
> + struct ve_struct *env = get_exec_env();
>
> sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
> if (!sbi)
> @@ -2435,9 +2443,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK)
> sbi->s_mount_opt |= EXT4_MOUNT_WRITEBACK_DATA;
>
> - if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC)
> - set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_CONTINUE)
> + if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC) {
> + if (!ve_is_super(env)) {
> + printk(KERN_WARNING "EXT4 may not be mounted with "
> + "errors=panic inside of container (VEID=%d), "
> + "ignoring option in superblock.\n", env->veid);
> + set_opt(sbi->s_mount_opt, ERRORS_CONT);
> + } else {
> + set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> + }
> + } else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_CONTINUE)
> set_opt(sbi->s_mount_opt, ERRORS_CONT);
> else
> set_opt(sbi->s_mount_opt, ERRORS_RO);
>
> --
> Vasiliy Kulikov
> http://www.openwall.com - bringing security into open computing environments
>
> _______________________________________________
> Devel mailing list
> Devel at openvz.org
> https://openvz.org/mailman/listinfo/devel
More information about the Devel
mailing list