diff options
-rw-r--r-- | arch/arm/kernel/sys_oabi-compat.c | 3 | ||||
-rw-r--r-- | fs/compat.c | 35 | ||||
-rw-r--r-- | fs/fcntl.c | 35 | ||||
-rw-r--r-- | fs/locks.c | 54 | ||||
-rw-r--r-- | include/uapi/asm-generic/fcntl.h | 16 | ||||
-rw-r--r-- | security/selinux/hooks.c | 3 |
6 files changed, 126 insertions, 20 deletions
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 3e94811690ce..702bd329d9d0 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c | |||
@@ -203,6 +203,9 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, | |||
203 | int ret; | 203 | int ret; |
204 | 204 | ||
205 | switch (cmd) { | 205 | switch (cmd) { |
206 | case F_GETLKP: | ||
207 | case F_SETLKP: | ||
208 | case F_SETLKPW: | ||
206 | case F_GETLK64: | 209 | case F_GETLK64: |
207 | case F_SETLK64: | 210 | case F_SETLK64: |
208 | case F_SETLKW64: | 211 | case F_SETLKW64: |
diff --git a/fs/compat.c b/fs/compat.c index 6af20de2c1a3..f340dcf11f68 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -399,12 +399,28 @@ static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *u | |||
399 | } | 399 | } |
400 | #endif | 400 | #endif |
401 | 401 | ||
402 | static unsigned int | ||
403 | convert_fcntl_cmd(unsigned int cmd) | ||
404 | { | ||
405 | switch (cmd) { | ||
406 | case F_GETLK64: | ||
407 | return F_GETLK; | ||
408 | case F_SETLK64: | ||
409 | return F_SETLK; | ||
410 | case F_SETLKW64: | ||
411 | return F_SETLKW; | ||
412 | } | ||
413 | |||
414 | return cmd; | ||
415 | } | ||
416 | |||
402 | asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, | 417 | asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, |
403 | unsigned long arg) | 418 | unsigned long arg) |
404 | { | 419 | { |
405 | mm_segment_t old_fs; | 420 | mm_segment_t old_fs; |
406 | struct flock f; | 421 | struct flock f; |
407 | long ret; | 422 | long ret; |
423 | unsigned int conv_cmd; | ||
408 | 424 | ||
409 | switch (cmd) { | 425 | switch (cmd) { |
410 | case F_GETLK: | 426 | case F_GETLK: |
@@ -441,16 +457,18 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, | |||
441 | case F_GETLK64: | 457 | case F_GETLK64: |
442 | case F_SETLK64: | 458 | case F_SETLK64: |
443 | case F_SETLKW64: | 459 | case F_SETLKW64: |
460 | case F_GETLKP: | ||
461 | case F_SETLKP: | ||
462 | case F_SETLKPW: | ||
444 | ret = get_compat_flock64(&f, compat_ptr(arg)); | 463 | ret = get_compat_flock64(&f, compat_ptr(arg)); |
445 | if (ret != 0) | 464 | if (ret != 0) |
446 | break; | 465 | break; |
447 | old_fs = get_fs(); | 466 | old_fs = get_fs(); |
448 | set_fs(KERNEL_DS); | 467 | set_fs(KERNEL_DS); |
449 | ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK : | 468 | conv_cmd = convert_fcntl_cmd(cmd); |
450 | ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW), | 469 | ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f); |
451 | (unsigned long)&f); | ||
452 | set_fs(old_fs); | 470 | set_fs(old_fs); |
453 | if (cmd == F_GETLK64 && ret == 0) { | 471 | if ((conv_cmd == F_GETLK || conv_cmd == F_GETLKP) && ret == 0) { |
454 | /* need to return lock information - see above for commentary */ | 472 | /* need to return lock information - see above for commentary */ |
455 | if (f.l_start > COMPAT_LOFF_T_MAX) | 473 | if (f.l_start > COMPAT_LOFF_T_MAX) |
456 | ret = -EOVERFLOW; | 474 | ret = -EOVERFLOW; |
@@ -471,8 +489,15 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, | |||
471 | asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd, | 489 | asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd, |
472 | unsigned long arg) | 490 | unsigned long arg) |
473 | { | 491 | { |
474 | if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64)) | 492 | switch (cmd) { |
493 | case F_GETLK64: | ||
494 | case F_SETLK64: | ||
495 | case F_SETLKW64: | ||
496 | case F_GETLKP: | ||
497 | case F_SETLKP: | ||
498 | case F_SETLKPW: | ||
475 | return -EINVAL; | 499 | return -EINVAL; |
500 | } | ||
476 | return compat_sys_fcntl64(fd, cmd, arg); | 501 | return compat_sys_fcntl64(fd, cmd, arg); |
477 | } | 502 | } |
478 | 503 | ||
diff --git a/fs/fcntl.c b/fs/fcntl.c index 7ef7f2d2b608..9ead1596399a 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -272,9 +272,19 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
272 | case F_SETFL: | 272 | case F_SETFL: |
273 | err = setfl(fd, filp, arg); | 273 | err = setfl(fd, filp, arg); |
274 | break; | 274 | break; |
275 | #if BITS_PER_LONG != 32 | ||
276 | /* 32-bit arches must use fcntl64() */ | ||
277 | case F_GETLKP: | ||
278 | #endif | ||
275 | case F_GETLK: | 279 | case F_GETLK: |
276 | err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); | 280 | err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); |
277 | break; | 281 | break; |
282 | #if BITS_PER_LONG != 32 | ||
283 | /* 32-bit arches must use fcntl64() */ | ||
284 | case F_SETLKP: | ||
285 | case F_SETLKPW: | ||
286 | #endif | ||
287 | /* Fallthrough */ | ||
278 | case F_SETLK: | 288 | case F_SETLK: |
279 | case F_SETLKW: | 289 | case F_SETLKW: |
280 | err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); | 290 | err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); |
@@ -388,17 +398,20 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, | |||
388 | goto out1; | 398 | goto out1; |
389 | 399 | ||
390 | switch (cmd) { | 400 | switch (cmd) { |
391 | case F_GETLK64: | 401 | case F_GETLK64: |
392 | err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); | 402 | case F_GETLKP: |
393 | break; | 403 | err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); |
394 | case F_SETLK64: | 404 | break; |
395 | case F_SETLKW64: | 405 | case F_SETLK64: |
396 | err = fcntl_setlk64(fd, f.file, cmd, | 406 | case F_SETLKW64: |
397 | (struct flock64 __user *) arg); | 407 | case F_SETLKP: |
398 | break; | 408 | case F_SETLKPW: |
399 | default: | 409 | err = fcntl_setlk64(fd, f.file, cmd, |
400 | err = do_fcntl(fd, cmd, arg, f.file); | 410 | (struct flock64 __user *) arg); |
401 | break; | 411 | break; |
412 | default: | ||
413 | err = do_fcntl(fd, cmd, arg, f.file); | ||
414 | break; | ||
402 | } | 415 | } |
403 | out1: | 416 | out1: |
404 | fdput(f); | 417 | fdput(f); |
diff --git a/fs/locks.c b/fs/locks.c index ed9fb769b88e..3b54b98236ee 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1930,6 +1930,12 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l) | |||
1930 | if (error) | 1930 | if (error) |
1931 | goto out; | 1931 | goto out; |
1932 | 1932 | ||
1933 | if (cmd == F_GETLKP) { | ||
1934 | cmd = F_GETLK; | ||
1935 | file_lock.fl_flags |= FL_FILE_PVT; | ||
1936 | file_lock.fl_owner = (fl_owner_t)filp; | ||
1937 | } | ||
1938 | |||
1933 | error = vfs_test_lock(filp, &file_lock); | 1939 | error = vfs_test_lock(filp, &file_lock); |
1934 | if (error) | 1940 | if (error) |
1935 | goto out; | 1941 | goto out; |
@@ -2049,10 +2055,26 @@ again: | |||
2049 | error = flock_to_posix_lock(filp, file_lock, &flock); | 2055 | error = flock_to_posix_lock(filp, file_lock, &flock); |
2050 | if (error) | 2056 | if (error) |
2051 | goto out; | 2057 | goto out; |
2052 | if (cmd == F_SETLKW) { | 2058 | |
2059 | /* | ||
2060 | * If the cmd is requesting file-private locks, then set the | ||
2061 | * FL_FILE_PVT flag and override the owner. | ||
2062 | */ | ||
2063 | switch (cmd) { | ||
2064 | case F_SETLKP: | ||
2065 | cmd = F_SETLK; | ||
2066 | file_lock->fl_flags |= FL_FILE_PVT; | ||
2067 | file_lock->fl_owner = (fl_owner_t)filp; | ||
2068 | break; | ||
2069 | case F_SETLKPW: | ||
2070 | cmd = F_SETLKW; | ||
2071 | file_lock->fl_flags |= FL_FILE_PVT; | ||
2072 | file_lock->fl_owner = (fl_owner_t)filp; | ||
2073 | /* Fallthrough */ | ||
2074 | case F_SETLKW: | ||
2053 | file_lock->fl_flags |= FL_SLEEP; | 2075 | file_lock->fl_flags |= FL_SLEEP; |
2054 | } | 2076 | } |
2055 | 2077 | ||
2056 | error = do_lock_file_wait(filp, cmd, file_lock); | 2078 | error = do_lock_file_wait(filp, cmd, file_lock); |
2057 | 2079 | ||
2058 | /* | 2080 | /* |
@@ -2098,6 +2120,12 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) | |||
2098 | if (error) | 2120 | if (error) |
2099 | goto out; | 2121 | goto out; |
2100 | 2122 | ||
2123 | if (cmd == F_GETLKP) { | ||
2124 | cmd = F_GETLK64; | ||
2125 | file_lock.fl_flags |= FL_FILE_PVT; | ||
2126 | file_lock.fl_owner = (fl_owner_t)filp; | ||
2127 | } | ||
2128 | |||
2101 | error = vfs_test_lock(filp, &file_lock); | 2129 | error = vfs_test_lock(filp, &file_lock); |
2102 | if (error) | 2130 | if (error) |
2103 | goto out; | 2131 | goto out; |
@@ -2150,10 +2178,26 @@ again: | |||
2150 | error = flock64_to_posix_lock(filp, file_lock, &flock); | 2178 | error = flock64_to_posix_lock(filp, file_lock, &flock); |
2151 | if (error) | 2179 | if (error) |
2152 | goto out; | 2180 | goto out; |
2153 | if (cmd == F_SETLKW64) { | 2181 | |
2182 | /* | ||
2183 | * If the cmd is requesting file-private locks, then set the | ||
2184 | * FL_FILE_PVT flag and override the owner. | ||
2185 | */ | ||
2186 | switch (cmd) { | ||
2187 | case F_SETLKP: | ||
2188 | cmd = F_SETLK64; | ||
2189 | file_lock->fl_flags |= FL_FILE_PVT; | ||
2190 | file_lock->fl_owner = (fl_owner_t)filp; | ||
2191 | break; | ||
2192 | case F_SETLKPW: | ||
2193 | cmd = F_SETLKW64; | ||
2194 | file_lock->fl_flags |= FL_FILE_PVT; | ||
2195 | file_lock->fl_owner = (fl_owner_t)filp; | ||
2196 | /* Fallthrough */ | ||
2197 | case F_SETLKW64: | ||
2154 | file_lock->fl_flags |= FL_SLEEP; | 2198 | file_lock->fl_flags |= FL_SLEEP; |
2155 | } | 2199 | } |
2156 | 2200 | ||
2157 | error = do_lock_file_wait(filp, cmd, file_lock); | 2201 | error = do_lock_file_wait(filp, cmd, file_lock); |
2158 | 2202 | ||
2159 | /* | 2203 | /* |
@@ -2221,6 +2265,8 @@ void locks_remove_file(struct file *filp) | |||
2221 | if (!inode->i_flock) | 2265 | if (!inode->i_flock) |
2222 | return; | 2266 | return; |
2223 | 2267 | ||
2268 | locks_remove_posix(filp, (fl_owner_t)filp); | ||
2269 | |||
2224 | if (filp->f_op->flock) { | 2270 | if (filp->f_op->flock) { |
2225 | struct file_lock fl = { | 2271 | struct file_lock fl = { |
2226 | .fl_pid = current->tgid, | 2272 | .fl_pid = current->tgid, |
diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 36025f77c6ed..a9b13f8b3595 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h | |||
@@ -132,6 +132,22 @@ | |||
132 | #define F_GETOWNER_UIDS 17 | 132 | #define F_GETOWNER_UIDS 17 |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | /* | ||
136 | * fd "private" POSIX locks. | ||
137 | * | ||
138 | * Usually POSIX locks held by a process are released on *any* close and are | ||
139 | * not inherited across a fork(). | ||
140 | * | ||
141 | * These cmd values will set locks that conflict with normal POSIX locks, but | ||
142 | * are "owned" by the opened file, not the process. This means that they are | ||
143 | * inherited across fork() like BSD (flock) locks, and they are only released | ||
144 | * automatically when the last reference to the the open file against which | ||
145 | * they were acquired is put. | ||
146 | */ | ||
147 | #define F_GETLKP 36 | ||
148 | #define F_SETLKP 37 | ||
149 | #define F_SETLKPW 38 | ||
150 | |||
135 | #define F_OWNER_TID 0 | 151 | #define F_OWNER_TID 0 |
136 | #define F_OWNER_PID 1 | 152 | #define F_OWNER_PID 1 |
137 | #define F_OWNER_PGRP 2 | 153 | #define F_OWNER_PGRP 2 |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4b34847208cc..3aa876374883 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3302,6 +3302,9 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, | |||
3302 | case F_GETLK: | 3302 | case F_GETLK: |
3303 | case F_SETLK: | 3303 | case F_SETLK: |
3304 | case F_SETLKW: | 3304 | case F_SETLKW: |
3305 | case F_GETLKP: | ||
3306 | case F_SETLKP: | ||
3307 | case F_SETLKPW: | ||
3305 | #if BITS_PER_LONG == 32 | 3308 | #if BITS_PER_LONG == 32 |
3306 | case F_GETLK64: | 3309 | case F_GETLK64: |
3307 | case F_SETLK64: | 3310 | case F_SETLK64: |