]> git.hungrycats.org Git - linux/commitdiff
udf: Check component length before reading it
authorJan Kara <jack@suse.cz>
Fri, 19 Dec 2014 13:27:55 +0000 (14:27 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Fri, 20 Feb 2015 00:49:32 +0000 (00:49 +0000)
commit e237ec37ec154564f8690c5bd1795339955eeef9 upstream.

Check that length specified in a component of a symlink fits in the
input buffer we are reading. Also properly ignore component length for
component types that do not use it. Otherwise we read memory after end
of buffer for corrupted udf image.

Reported-by: Carl Henrik Lunde <chlunde@ping.uio.no>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
fs/udf/symlink.c

index 2d0c3720e9afd3b066c8d27752c817b219bf5b04..0422b7b8369f079b45a5bb631c9d3bd826f6a6ca 100644 (file)
@@ -42,14 +42,17 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
        tolen--;
        while (elen < fromlen) {
                pc = (struct pathComponent *)(from + elen);
+               elen += sizeof(struct pathComponent);
                switch (pc->componentType) {
                case 1:
                        /*
                         * Symlink points to some place which should be agreed
                         * upon between originator and receiver of the media. Ignore.
                         */
-                       if (pc->lengthComponentIdent > 0)
+                       if (pc->lengthComponentIdent > 0) {
+                               elen += pc->lengthComponentIdent;
                                break;
+                       }
                        /* Fall through */
                case 2:
                        if (tolen == 0)
@@ -74,6 +77,9 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
                        /* that would be . - just ignore */
                        break;
                case 5:
+                       elen += pc->lengthComponentIdent;
+                       if (elen > fromlen)
+                               return -EIO;
                        comp_len = udf_get_filename(sb, pc->componentIdent,
                                                    pc->lengthComponentIdent,
                                                    p, tolen);
@@ -85,7 +91,6 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
                        tolen--;
                        break;
                }
-               elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
        }
        if (p > to + 1)
                p[-1] = '\0';