Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

locks: only validate the lock vs. f_mode in F_SETLK codepaths

v2: replace missing break in switch statement (as pointed out by Dave
Jones)

commit bce7560d4946 (locks: consolidate checks for compatible
filp->f_mode values in setlk handlers) introduced a regression in the
F_GETLK handler.

flock64_to_posix_lock is a shared codepath between F_GETLK and F_SETLK,
but the f_mode checks should only be applicable to the F_SETLK codepaths
according to POSIX.

Instead of just reverting the patch, add a new function to do this
checking and have the F_SETLK handlers call it.

Cc: Dave Jones <davej@redhat.com>
Reported-and-Tested-by: Reuben Farrelly <reuben@reub.net>
Signed-off-by: Jeff Layton <jlayton@poochiereds.net>

+24 -12
+24 -12
fs/locks.c
··· 389 389 fl->fl_ops = NULL; 390 390 fl->fl_lmops = NULL; 391 391 392 - /* Ensure that fl->fl_filp has compatible f_mode */ 393 - switch (l->l_type) { 394 - case F_RDLCK: 395 - if (!(filp->f_mode & FMODE_READ)) 396 - return -EBADF; 397 - break; 398 - case F_WRLCK: 399 - if (!(filp->f_mode & FMODE_WRITE)) 400 - return -EBADF; 401 - break; 402 - } 403 - 404 392 return assign_type(fl, l->l_type); 405 393 } 406 394 ··· 2022 2034 return error; 2023 2035 } 2024 2036 2037 + /* Ensure that fl->fl_filp has compatible f_mode for F_SETLK calls */ 2038 + static int 2039 + check_fmode_for_setlk(struct file_lock *fl) 2040 + { 2041 + switch (fl->fl_type) { 2042 + case F_RDLCK: 2043 + if (!(fl->fl_file->f_mode & FMODE_READ)) 2044 + return -EBADF; 2045 + break; 2046 + case F_WRLCK: 2047 + if (!(fl->fl_file->f_mode & FMODE_WRITE)) 2048 + return -EBADF; 2049 + } 2050 + return 0; 2051 + } 2052 + 2025 2053 /* Apply the lock described by l to an open file descriptor. 2026 2054 * This implements both the F_SETLK and F_SETLKW commands of fcntl(). 2027 2055 */ ··· 2072 2068 2073 2069 again: 2074 2070 error = flock_to_posix_lock(filp, file_lock, &flock); 2071 + if (error) 2072 + goto out; 2073 + 2074 + error = check_fmode_for_setlk(file_lock); 2075 2075 if (error) 2076 2076 goto out; 2077 2077 ··· 2211 2203 2212 2204 again: 2213 2205 error = flock64_to_posix_lock(filp, file_lock, &flock); 2206 + if (error) 2207 + goto out; 2208 + 2209 + error = check_fmode_for_setlk(file_lock); 2214 2210 if (error) 2215 2211 goto out; 2216 2212