lkml.org 
[lkml]   [1999]   [Mar]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] Bad races in sysvfs (fs and icache corruption)
	Linus, Krzysztof - we have several holes is sysvfs, some of them
exploitable (patch is in the end of posting). Details:

1) sysv_link() doesn't increase i_count. Result: dcache corruption
(dangling ->d_inode).
Fix: do it ;-)

2) sysv_put_inode() tries to do ->delete_inode() job.
Scenario:

link("a","b");
fd1=open("a",O_RDWR);
fd2=open("b",O_RDWR);
unlink("a");
unlink("b");
/* Now i_nlink is 0 */
close(fd1);
/*
* iput() is called. sysv_put_inode() sees that i_nlink is 0 and does its
* thing. I.e. truncates the file and marks the on-disk inode free.
* The rest is left as an exercise for readers.
*/
Fix: separate put_inode() and delete_inode(), indeed.

3) Race: sysv_free_inode() (called by sysv_put_inode()) marks on-disk
inode free and only after that calls clear_inode(). Suppose the inode was
in I_LOCKED state at the moment of last iput() (and had i_nlink==0).
clear_inode() does wait_on_inode(), so it will block. sysv_write_inode()
that was called back when the inode was moved to I_LOCKED state might
block before writing to disk (on bread()). There we go: somebody ask
sysvfs to create a new inode. It gives back the same inumber. And *new*
in-core inode. Fine, we fill the inode, mark it dirty, find that block
with on-disk inode is already in core, fill the thing and request writing
it on the disk. The thing that requested sync_one() on original inode
wakes up. Fills the on-disk inode. And writes it back to disk. On-disk
inode is trashed.
Fix: call clear_inode() *before* marking the on-disk inode free.

Patch (against 2.2.3 - pre-4 doesn't touch files in question) follows:

diff -urN linux-2.2.3/fs/sysv/ialloc.c linux-bird.sysv-fix/fs/sysv/ialloc.c
--- linux-2.2.3/fs/sysv/ialloc.c Fri Nov 13 18:02:04 1998
+++ linux-bird.sysv-fix/fs/sysv/ialloc.c Sun Mar 21 02:52:04 1999
@@ -86,6 +86,7 @@
return;
}
raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
+ clear_inode(inode);
lock_super(sb);
if (*sb->sv_sb_fic_count < sb->sv_fic_size)
*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino;
@@ -97,7 +98,6 @@
mark_buffer_dirty(bh, 1);
unlock_super(sb);
brelse(bh);
- clear_inode(inode);
}

struct inode * sysv_new_inode(const struct inode * dir)
diff -urN linux-2.2.3/fs/sysv/inode.c linux-bird.sysv-fix/fs/sysv/inode.c
--- linux-2.2.3/fs/sysv/inode.c Thu Dec 31 20:06:00 1998
+++ linux-bird.sysv-fix/fs/sysv/inode.c Sun Mar 21 02:52:39 1999
@@ -55,10 +55,8 @@
}
#endif

-void sysv_put_inode(struct inode *inode)
+static void sysv_delete_inode(struct inode *inode)
{
- if (inode->i_nlink)
- return;
inode->i_size = 0;
sysv_truncate(inode);
sysv_free_inode(inode);
@@ -68,8 +66,8 @@
static struct super_operations sysv_sops = {
sysv_read_inode,
sysv_write_inode,
- sysv_put_inode,
- NULL, /* delete_inode */
+ NULL, /* nothing special on put_inode() */
+ sysv_delete_inode,
sysv_notify_change,
sysv_put_super,
sysv_write_super,
diff -urN linux-2.2.3/fs/sysv/namei.c linux-bird.sysv-fix/fs/sysv/namei.c
--- linux-2.2.3/fs/sysv/namei.c Thu Dec 31 20:06:01 1998
+++ linux-bird.sysv-fix/fs/sysv/namei.c Sun Mar 21 02:46:33 1999
@@ -576,6 +576,7 @@
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
mark_inode_dirty(oldinode);
+ inode->i_count++;
d_instantiate(dentry, oldinode);
return 0;
}
diff -urN linux-2.2.3/include/sysv_fs.h linux-bird.sysv-fix/include/sysv_fs.h
--- linux-2.2.3/include/sysv_fs.h Thu Dec 31 20:06:06 1998
+++ linux-bird.sysv-fix/include/sysv_fs.h Sun Mar 21 02:53:51 1999
@@ -398,7 +398,6 @@
extern void sysv_read_inode(struct inode *);
extern int sysv_notify_change(struct dentry *, struct iattr *);
extern void sysv_write_inode(struct inode *);
-extern void sysv_put_inode(struct inode *);
extern int sysv_statfs(struct super_block *, struct statfs *, int);
extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct file *, struct dentry *);
Please, apply it. Holes are trivially exploitable.
Cheers,
Al


-
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/

\
 
 \ /
  Last update: 2005-03-22 13:50    [W:0.030 / U:0.460 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site