浏览代码

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: Alain Knaff <alain@knaff.lu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Alain Knaff 16 年之前
父节点
当前提交
5b6f1eb97d
共有 1 个文件被更改,包括 13 次插入0 次删除
  1. 13 0
      fs/read_write.c

+ 13 - 0
fs/read_write.c

@@ -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)
 			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)
 		}
 		}
 		retval = offset;
 		retval = offset;
 	}
 	}
+out:
 	unlock_kernel();
 	unlock_kernel();
 	return retval;
 	return retval;
 }
 }