Skip to content

Commit f20ae9c

Browse files
committed
Merge tag 'filelock-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux
Pull file locking updates from Jeff Layton: - new functionality for F_OFD_GETLK: requesting a type of F_UNLCK will find info about whatever lock happens to be first in the given range, regardless of type. - an OFD lock selftest - bugfix involving a UAF in a tracepoint - comment typo fix * tag 'filelock-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux: locks: fix KASAN: use-after-free in trace_event_raw_event_filelock_lock fs/locks: Fix typo selftests: add OFD lock tests fs/locks: F_UNLCK extension for F_OFD_GETLK
2 parents b4a04f9 + 74f6f59 commit f20ae9c

File tree

3 files changed

+159
-5
lines changed

3 files changed

+159
-5
lines changed

fs/locks.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,21 @@ static bool posix_locks_conflict(struct file_lock *caller_fl,
868868
return locks_conflict(caller_fl, sys_fl);
869869
}
870870

871+
/* Determine if lock sys_fl blocks lock caller_fl. Used on xx_GETLK
872+
* path so checks for additional GETLK-specific things like F_UNLCK.
873+
*/
874+
static bool posix_test_locks_conflict(struct file_lock *caller_fl,
875+
struct file_lock *sys_fl)
876+
{
877+
/* F_UNLCK checks any locks on the same fd. */
878+
if (caller_fl->fl_type == F_UNLCK) {
879+
if (!posix_same_owner(caller_fl, sys_fl))
880+
return false;
881+
return locks_overlap(caller_fl, sys_fl);
882+
}
883+
return posix_locks_conflict(caller_fl, sys_fl);
884+
}
885+
871886
/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
872887
* checking before calling the locks_conflict().
873888
*/
@@ -901,7 +916,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
901916
retry:
902917
spin_lock(&ctx->flc_lock);
903918
list_for_each_entry(cfl, &ctx->flc_posix, fl_list) {
904-
if (!posix_locks_conflict(fl, cfl))
919+
if (!posix_test_locks_conflict(fl, cfl))
905920
continue;
906921
if (cfl->fl_lmops && cfl->fl_lmops->lm_lock_expirable
907922
&& (*cfl->fl_lmops->lm_lock_expirable)(cfl)) {
@@ -1301,6 +1316,7 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
13011316
out:
13021317
spin_unlock(&ctx->flc_lock);
13031318
percpu_up_read(&file_rwsem);
1319+
trace_posix_lock_inode(inode, request, error);
13041320
/*
13051321
* Free any unused locks.
13061322
*/
@@ -1309,7 +1325,6 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request,
13091325
if (new_fl2)
13101326
locks_free_lock(new_fl2);
13111327
locks_dispose_list(&dispose);
1312-
trace_posix_lock_inode(inode, request, error);
13131328

13141329
return error;
13151330
}
@@ -2136,7 +2151,7 @@ EXPORT_SYMBOL_GPL(vfs_test_lock);
21362151
* @fl: The file_lock who's fl_pid should be translated
21372152
* @ns: The namespace into which the pid should be translated
21382153
*
2139-
* Used to tranlate a fl_pid into a namespace virtual pid number
2154+
* Used to translate a fl_pid into a namespace virtual pid number
21402155
*/
21412156
static pid_t locks_translate_pid(struct file_lock *fl, struct pid_namespace *ns)
21422157
{
@@ -2207,7 +2222,8 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
22072222
if (fl == NULL)
22082223
return -ENOMEM;
22092224
error = -EINVAL;
2210-
if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
2225+
if (cmd != F_OFD_GETLK && flock->l_type != F_RDLCK
2226+
&& flock->l_type != F_WRLCK)
22112227
goto out;
22122228

22132229
error = flock_to_posix_lock(filp, fl, flock);
@@ -2414,7 +2430,8 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
24142430
return -ENOMEM;
24152431

24162432
error = -EINVAL;
2417-
if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
2433+
if (cmd != F_OFD_GETLK && flock->l_type != F_RDLCK
2434+
&& flock->l_type != F_WRLCK)
24182435
goto out;
24192436

24202437
error = flock64_to_posix_lock(filp, fl, flock);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
TEST_GEN_PROGS := ofdlocks
4+
5+
include ../lib.mk
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#define _GNU_SOURCE
4+
#include <fcntl.h>
5+
#include <assert.h>
6+
#include <stdio.h>
7+
#include <unistd.h>
8+
#include <string.h>
9+
#include "../kselftest.h"
10+
11+
static int lock_set(int fd, struct flock *fl)
12+
{
13+
int ret;
14+
15+
fl->l_pid = 0; // needed for OFD locks
16+
fl->l_whence = SEEK_SET;
17+
ret = fcntl(fd, F_OFD_SETLK, fl);
18+
if (ret)
19+
perror("fcntl()");
20+
return ret;
21+
}
22+
23+
static int lock_get(int fd, struct flock *fl)
24+
{
25+
int ret;
26+
27+
fl->l_pid = 0; // needed for OFD locks
28+
fl->l_whence = SEEK_SET;
29+
ret = fcntl(fd, F_OFD_GETLK, fl);
30+
if (ret)
31+
perror("fcntl()");
32+
return ret;
33+
}
34+
35+
int main(void)
36+
{
37+
int rc;
38+
struct flock fl, fl2;
39+
int fd = open("/tmp/aa", O_RDWR | O_CREAT | O_EXCL, 0600);
40+
int fd2 = open("/tmp/aa", O_RDONLY);
41+
42+
unlink("/tmp/aa");
43+
assert(fd != -1);
44+
assert(fd2 != -1);
45+
ksft_print_msg("[INFO] opened fds %i %i\n", fd, fd2);
46+
47+
/* Set some read lock */
48+
fl.l_type = F_RDLCK;
49+
fl.l_start = 5;
50+
fl.l_len = 3;
51+
rc = lock_set(fd, &fl);
52+
if (rc == 0) {
53+
ksft_print_msg
54+
("[SUCCESS] set OFD read lock on first fd\n");
55+
} else {
56+
ksft_print_msg("[FAIL] to set OFD read lock on first fd\n");
57+
return -1;
58+
}
59+
/* Make sure read locks do not conflict on different fds. */
60+
fl.l_type = F_RDLCK;
61+
fl.l_start = 5;
62+
fl.l_len = 1;
63+
rc = lock_get(fd2, &fl);
64+
if (rc != 0)
65+
return -1;
66+
if (fl.l_type != F_UNLCK) {
67+
ksft_print_msg("[FAIL] read locks conflicted\n");
68+
return -1;
69+
}
70+
/* Make sure read/write locks do conflict on different fds. */
71+
fl.l_type = F_WRLCK;
72+
fl.l_start = 5;
73+
fl.l_len = 1;
74+
rc = lock_get(fd2, &fl);
75+
if (rc != 0)
76+
return -1;
77+
if (fl.l_type != F_UNLCK) {
78+
ksft_print_msg
79+
("[SUCCESS] read and write locks conflicted\n");
80+
} else {
81+
ksft_print_msg
82+
("[SUCCESS] read and write locks not conflicted\n");
83+
return -1;
84+
}
85+
/* Get info about the lock on first fd. */
86+
fl.l_type = F_UNLCK;
87+
fl.l_start = 5;
88+
fl.l_len = 1;
89+
rc = lock_get(fd, &fl);
90+
if (rc != 0) {
91+
ksft_print_msg
92+
("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n");
93+
return -1;
94+
}
95+
if (fl.l_type != F_UNLCK) {
96+
ksft_print_msg
97+
("[SUCCESS] F_UNLCK test returns: locked, type %i pid %i len %zi\n",
98+
fl.l_type, fl.l_pid, fl.l_len);
99+
} else {
100+
ksft_print_msg
101+
("[FAIL] F_OFD_GETLK with F_UNLCK did not return lock info\n");
102+
return -1;
103+
}
104+
/* Try the same but by locking everything by len==0. */
105+
fl2.l_type = F_UNLCK;
106+
fl2.l_start = 0;
107+
fl2.l_len = 0;
108+
rc = lock_get(fd, &fl2);
109+
if (rc != 0) {
110+
ksft_print_msg
111+
("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n");
112+
return -1;
113+
}
114+
if (memcmp(&fl, &fl2, sizeof(fl))) {
115+
ksft_print_msg
116+
("[FAIL] F_UNLCK test returns: locked, type %i pid %i len %zi\n",
117+
fl.l_type, fl.l_pid, fl.l_len);
118+
return -1;
119+
}
120+
ksft_print_msg("[SUCCESS] F_UNLCK with len==0 returned the same\n");
121+
/* Get info about the lock on second fd - no locks on it. */
122+
fl.l_type = F_UNLCK;
123+
fl.l_start = 0;
124+
fl.l_len = 0;
125+
lock_get(fd2, &fl);
126+
if (fl.l_type != F_UNLCK) {
127+
ksft_print_msg
128+
("[FAIL] F_OFD_GETLK with F_UNLCK return lock info from another fd\n");
129+
return -1;
130+
}
131+
return 0;
132+
}

0 commit comments

Comments
 (0)