[Devel] [patch] ext: prevent panic inside of containers

Vasiliy Kulikov segoon at openwall.com
Mon Jan 24 02:50:35 PST 2011


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.

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




More information about the Devel mailing list