On Wed, 8 Dec 2010 18:25:00 +0530 Harsh Prateek Bora <harsh@xxxxxxxxxxxxxxxxxx> wrote: > The existing code causes the if condition to pass when it should fail > on a *64-bit kernel* because of implicit data type conversions. It can > be observed by passing pos = -1 and count = some positive number. > This results in function returning EOVERFLOW instead of EINVAL. > > With this patch, the function returns EINVAL when pos is -1 and count > is a positive number. This can be tested by calling sendfile with > offset = -1 and count = some positive number on a 64-bit kernel. > Hmm, is this clearer ? == commit 4a3956c790290efeb647bbb0c3a90476bb57800e adds support for negative (unsigned) page offset for very large files as /proc/<pid>/mem and /dev/mem. In that patch, overlap check routine is added but it was wrong. Considering 'pos' is loff_t, a signed value, In usual case, at comparing 'pos' and 'pos+count' (positive) / (positive) OK (positive) / (nevative) EOVERFLOW (negative) / (positive) EINVAL (negative) / (negative) EINVAL In FMODE_UNSIGNED_OFFSET case, (positive) / (positive) OK (positive) / (nevative) OK (ex. 0x7fff -> 0x8000) (nevative) / (negative) OK (negative) / (positive) EOVERFLOW (ex. 0xffff -> 0x1) Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@xxxxxxxxxxxxxx> --- fs/read_write.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) Index: linux-2.6.37-rc5/fs/read_write.c =================================================================== --- linux-2.6.37-rc5.orig/fs/read_write.c +++ linux-2.6.37-rc5/fs/read_write.c @@ -37,11 +37,24 @@ __negative_fpos_check(struct file *file, * pos or pos+count is negative here, check overflow. * too big "count" will be caught in rw_verify_area(). */ - if ((pos < 0) && (pos + count < pos)) + /* negative pos is allowed only when the flag is set */ + if (!(file->f_mode & FMODE_UNSIGNED_OFFSET)) { + if ((pos > 0) && (pos + count > 0)) + return 0; + if ((pos > 0) && (pos + count < 0)) + return -EOVERFLOW; + return -EINVAL; + } + /* + * The file supports 'unsigned long' offset. (but loff_t is signed) + * When pos is negative, -1 is the biggest number. So if pos + count + * is larger than pos, it's overflow. + * (ex) -1 + 10 = 9 ...means + * 0xffff + 0xa = 0x9 => overflow. + */ + if ((pos < 0) && (pos + count > 0)) return -EOVERFLOW; - if (file->f_mode & FMODE_UNSIGNED_OFFSET) - return 0; - return -EINVAL; + return 0; } /** -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html