Re: 2.0.x kernel denial of service via VFAT longnames

Gordon Chaffee (chaffee@cs.berkeley.edu)
Tue, 29 Sep 1998 11:48:58 -0700 (PDT)


Vitaly Fedrushkov writes:
> Sorry but I'm not a kernel expert. Not sure if this one is already
> known...
>
> I found a way to commit kernel denial of service via certain (strictly
> legal) file operation(s) on vfat fs.

Known problem--I've even sent fixes to someone to test and they seemed
to work for him. I'll try to dig them up... OK, here they are. Note
that namei.c gets patched twice. They were incremental patches, but
I don't think there should be a problem applying them.

- Gordon

--- linux/fs/vfat/namei.c~ Fri Jul 17 03:11:23 1998
+++ linux/fs/vfat/namei.c Thu Sep 3 23:04:15 1998
@@ -538,27 +538,51 @@
if (MSDOS_SB(dir->i_sb)->options.numtail == 0) {
res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
}
- i = 0;
- while (res > -1) {
- /* Create the next shortname to try */
- i++;
- if (i == 10000000) return -EEXIST;
- sprintf(buf, "%d", i);
- sz = strlen(buf);
- if (sz + 1 > spaces) {
- baselen = baselen - (sz + 1 - spaces);
- spaces = sz + 1;
- }

- strncpy(msdos_name, base, baselen);
- msdos_name[baselen] = '~';
- strcpy(&msdos_name[baselen+1], buf);
- msdos_name[baselen+sz+1] = '.';
- strcpy(&msdos_name[baselen+sz+2], ext);
+ if (res > -1) {
+ /*
+ * Try to find a unique alias. This used to
+ * iterate through all possibilities sequentially,
+ * but that gave extremely bad performance. Windows
+ * only tries a few cases before using random
+ * values for part of the base.
+ */

- totlen = baselen + sz + 1 + extlen + (extlen > 0);
- res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+ if (2 > spaces) {
+ baselen = baselen - (2 - spaces);
+ spaces = 2;
+ }
+ msdos_name[baselen] = '~';
+ msdos_name[baselen+2] = '.';
+ strcpy(&msdos_name[baselen+3], ext);
+ totlen = baselen + 2 + extlen + (extlen > 0);
+ for (i = 1; res > -1 && i < 10; i++) {
+ strncpy(msdos_name, base, baselen);
+ msdos_name[baselen+1] = i + '0';
+ res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+ }
}
+ if (res > -1) {
+ i = jiffies & 0xffff;
+ sz = (jiffies >> 16) & 0x7;
+ if (6 > spaces) {
+ baselen = baselen - (6 - spaces);
+ spaces = 6;
+ }
+ msdos_name[baselen+4] = '~';
+ msdos_name[baselen+5] = '1' + sz;
+ msdos_name[baselen+6] = '.';
+ strcpy(&msdos_name[baselen+7], ext);
+ totlen = baselen + 6 + extlen + (extlen > 0);
+ while (res > -1) {
+ sprintf(buf, "%04x", i);
+ memcpy(&msdos_name[baselen], buf, 4);
+ msdos_name[12] = 0;
+ res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+ i -= 11;
+ }
+ }
+
res = vfat_format_name(msdos_name, totlen, name_res, 1, utf8);
return res;
}

--- linux/fs/fat/inode.c~ Mon Dec 1 13:02:38 1997
+++ linux/fs/fat/inode.c Fri Sep 4 13:42:47 1998
@@ -521,6 +521,7 @@
MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL;
MSDOS_I(inode)->i_linked = MSDOS_I(inode)->i_oldlink = NULL;
MSDOS_I(inode)->i_binary = 1;
+ MSDOS_I(inode)->i_speedalias = 0;
inode->i_uid = MSDOS_SB(sb)->options.fs_uid;
inode->i_gid = MSDOS_SB(sb)->options.fs_gid;
inode->i_version = ++event;
--- linux/include/linux/msdos_fs_i.h~ Sat Apr 26 12:34:12 1997
+++ linux/include/linux/msdos_fs_i.h Fri Sep 4 13:40:40 1998
@@ -38,7 +38,8 @@
happens when an open file is moved */
struct inode *i_oldlink;/* pointer to open inode that references
the same file */
- int i_binary; /* file contains non-text data */
+ unsigned i_binary:1, /* file contains non-text data */
+ i_speedalias:1;/* dir has many aliases, use fast algorithm */
};

#endif
--- linux/fs/vfat/namei.c~ Thu Sep 3 23:04:15 1998
+++ linux/fs/vfat/namei.c Fri Sep 4 13:44:00 1998
@@ -539,7 +539,7 @@
res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
}

- if (res > -1) {
+ if (res > -1 && !MSDOS_I(dir)->i_speedalias) {
/*
* Try to find a unique alias. This used to
* iterate through all possibilities sequentially,
@@ -563,6 +563,7 @@
}
}
if (res > -1) {
+ MSDOS_I(dir)->i_speedalias = 1;
i = jiffies & 0xffff;
sz = (jiffies >> 16) & 0x7;
if (6 > spaces) {

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/