diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/fs/locks.c b/fs/locks.c index f7daa5f48949..a1e8b2248014 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -316,21 +316,22 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, | |||
316 | /* POSIX-1996 leaves the case l->l_len < 0 undefined; | 316 | /* POSIX-1996 leaves the case l->l_len < 0 undefined; |
317 | POSIX-2001 defines it. */ | 317 | POSIX-2001 defines it. */ |
318 | start += l->l_start; | 318 | start += l->l_start; |
319 | end = start + l->l_len - 1; | 319 | if (start < 0) |
320 | if (l->l_len < 0) { | 320 | return -EINVAL; |
321 | fl->fl_end = OFFSET_MAX; | ||
322 | if (l->l_len > 0) { | ||
323 | end = start + l->l_len - 1; | ||
324 | fl->fl_end = end; | ||
325 | } else if (l->l_len < 0) { | ||
321 | end = start - 1; | 326 | end = start - 1; |
327 | fl->fl_end = end; | ||
322 | start += l->l_len; | 328 | start += l->l_len; |
329 | if (start < 0) | ||
330 | return -EINVAL; | ||
323 | } | 331 | } |
324 | |||
325 | if (start < 0) | ||
326 | return -EINVAL; | ||
327 | if (l->l_len > 0 && end < 0) | ||
328 | return -EOVERFLOW; | ||
329 | |||
330 | fl->fl_start = start; /* we record the absolute position */ | 332 | fl->fl_start = start; /* we record the absolute position */ |
331 | fl->fl_end = end; | 333 | if (fl->fl_end < fl->fl_start) |
332 | if (l->l_len == 0) | 334 | return -EOVERFLOW; |
333 | fl->fl_end = OFFSET_MAX; | ||
334 | 335 | ||
335 | fl->fl_owner = current->files; | 336 | fl->fl_owner = current->files; |
336 | fl->fl_pid = current->tgid; | 337 | fl->fl_pid = current->tgid; |
@@ -362,14 +363,21 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, | |||
362 | return -EINVAL; | 363 | return -EINVAL; |
363 | } | 364 | } |
364 | 365 | ||
365 | if (((start += l->l_start) < 0) || (l->l_len < 0)) | 366 | start += l->l_start; |
367 | if (start < 0) | ||
366 | return -EINVAL; | 368 | return -EINVAL; |
367 | fl->fl_end = start + l->l_len - 1; | 369 | fl->fl_end = OFFSET_MAX; |
368 | if (l->l_len > 0 && fl->fl_end < 0) | 370 | if (l->l_len > 0) { |
369 | return -EOVERFLOW; | 371 | fl->fl_end = start + l->l_len - 1; |
372 | } else if (l->l_len < 0) { | ||
373 | fl->fl_end = start - 1; | ||
374 | start += l->l_len; | ||
375 | if (start < 0) | ||
376 | return -EINVAL; | ||
377 | } | ||
370 | fl->fl_start = start; /* we record the absolute position */ | 378 | fl->fl_start = start; /* we record the absolute position */ |
371 | if (l->l_len == 0) | 379 | if (fl->fl_end < fl->fl_start) |
372 | fl->fl_end = OFFSET_MAX; | 380 | return -EOVERFLOW; |
373 | 381 | ||
374 | fl->fl_owner = current->files; | 382 | fl->fl_owner = current->files; |
375 | fl->fl_pid = current->tgid; | 383 | fl->fl_pid = current->tgid; |
@@ -829,12 +837,16 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) | |||
829 | /* Detect adjacent or overlapping regions (if same lock type) | 837 | /* Detect adjacent or overlapping regions (if same lock type) |
830 | */ | 838 | */ |
831 | if (request->fl_type == fl->fl_type) { | 839 | if (request->fl_type == fl->fl_type) { |
840 | /* In all comparisons of start vs end, use | ||
841 | * "start - 1" rather than "end + 1". If end | ||
842 | * is OFFSET_MAX, end + 1 will become negative. | ||
843 | */ | ||
832 | if (fl->fl_end < request->fl_start - 1) | 844 | if (fl->fl_end < request->fl_start - 1) |
833 | goto next_lock; | 845 | goto next_lock; |
834 | /* If the next lock in the list has entirely bigger | 846 | /* If the next lock in the list has entirely bigger |
835 | * addresses than the new one, insert the lock here. | 847 | * addresses than the new one, insert the lock here. |
836 | */ | 848 | */ |
837 | if (fl->fl_start > request->fl_end + 1) | 849 | if (fl->fl_start - 1 > request->fl_end) |
838 | break; | 850 | break; |
839 | 851 | ||
840 | /* If we come here, the new and old lock are of the | 852 | /* If we come here, the new and old lock are of the |