Commit 31abdab9 authored by Al Viro's avatar Al Viro

hpfs: deadlock and race in directory lseek()

For one thing, there's an ABBA deadlock on hpfs fs-wide lock and i_mutex
in hpfs_dir_lseek() - there's a lot of methods that grab the former with
the caller already holding the latter, so it must take i_mutex first.

For another, locking the damn thing, carefully validating the offset,
then dropping locks and assigning the offset is obviously racy.

Moreover, we _must_ do hpfs_add_pos(), or the machinery in dnode.c
won't modify the sucker on B-tree surgeries.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 1d7095c7
...@@ -33,25 +33,27 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) ...@@ -33,25 +33,27 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
if (whence == SEEK_DATA || whence == SEEK_HOLE) if (whence == SEEK_DATA || whence == SEEK_HOLE)
return -EINVAL; return -EINVAL;
mutex_lock(&i->i_mutex);
hpfs_lock(s); hpfs_lock(s);
/*printk("dir lseek\n");*/ /*printk("dir lseek\n");*/
if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok; if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
mutex_lock(&i->i_mutex);
pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1; pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
while (pos != new_off) { while (pos != new_off) {
if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh); if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
else goto fail; else goto fail;
if (pos == 12) goto fail; if (pos == 12) goto fail;
} }
mutex_unlock(&i->i_mutex); hpfs_add_pos(i, &filp->f_pos);
ok: ok:
filp->f_pos = new_off;
hpfs_unlock(s); hpfs_unlock(s);
return filp->f_pos = new_off;
fail:
mutex_unlock(&i->i_mutex); mutex_unlock(&i->i_mutex);
return new_off;
fail:
/*printk("illegal lseek: %016llx\n", new_off);*/ /*printk("illegal lseek: %016llx\n", new_off);*/
hpfs_unlock(s); hpfs_unlock(s);
mutex_unlock(&i->i_mutex);
return -ESPIPE; return -ESPIPE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment