Commit 5b6f1eb9 authored by Alain Knaff's avatar Alain Knaff Committed by Al Viro

vfs: lseek(fd, 0, SEEK_CUR) race condition

This patch fixes a race condition in lseek. While it is expected that
unpredictable behaviour may result while repositioning the offset of a
file descriptor concurrently with reading/writing to the same file
descriptor, this should not happen when merely *reading* the file
descriptor's offset.

Unfortunately, the only portable way in Unix to read a file
descriptor's offset is lseek(fd, 0, SEEK_CUR); however executing this
concurrently with read/write may mess up the position.

[with fixes from akpm]
Signed-off-by: default avatarAlain Knaff <alain@knaff.lu>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 7d3b56ba
...@@ -50,6 +50,14 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) ...@@ -50,6 +50,14 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
offset += inode->i_size; offset += inode->i_size;
break; break;
case SEEK_CUR: case SEEK_CUR:
/*
* Here we special-case the lseek(fd, 0, SEEK_CUR)
* position-querying operation. Avoid rewriting the "same"
* f_pos value back to the file because a concurrent read(),
* write() or lseek() might have altered it
*/
if (offset == 0)
return file->f_pos;
offset += file->f_pos; offset += file->f_pos;
break; break;
} }
...@@ -105,6 +113,10 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) ...@@ -105,6 +113,10 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin)
offset += i_size_read(file->f_path.dentry->d_inode); offset += i_size_read(file->f_path.dentry->d_inode);
break; break;
case SEEK_CUR: case SEEK_CUR:
if (offset == 0) {
retval = file->f_pos;
goto out;
}
offset += file->f_pos; offset += file->f_pos;
} }
retval = -EINVAL; retval = -EINVAL;
...@@ -115,6 +127,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) ...@@ -115,6 +127,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin)
} }
retval = offset; retval = offset;
} }
out:
unlock_kernel(); unlock_kernel();
return retval; return retval;
} }
......
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