hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/fs/file.c
....@@ -677,6 +677,7 @@
677677 fdt = files_fdtable(files);
678678 if (fd >= fdt->max_fds)
679679 goto out_unlock;
680
+ fd = array_index_nospec(fd, fdt->max_fds);
680681 file = fdt->fd[fd];
681682 if (!file)
682683 goto out_unlock;
....@@ -1006,16 +1007,30 @@
10061007 return __fget_light(fd, 0);
10071008 }
10081009
1010
+/*
1011
+ * Try to avoid f_pos locking. We only need it if the
1012
+ * file is marked for FMODE_ATOMIC_POS, and it can be
1013
+ * accessed multiple ways.
1014
+ *
1015
+ * Always do it for directories, because pidfd_getfd()
1016
+ * can make a file accessible even if it otherwise would
1017
+ * not be, and for directories this is a correctness
1018
+ * issue, not a "POSIX requirement".
1019
+ */
1020
+static inline bool file_needs_f_pos_lock(struct file *file)
1021
+{
1022
+ return (file->f_mode & FMODE_ATOMIC_POS) &&
1023
+ (file_count(file) > 1 || S_ISDIR(file_inode(file)->i_mode));
1024
+}
1025
+
10091026 unsigned long __fdget_pos(unsigned int fd)
10101027 {
10111028 unsigned long v = __fdget(fd);
10121029 struct file *file = (struct file *)(v & ~3);
10131030
1014
- if (file && (file->f_mode & FMODE_ATOMIC_POS)) {
1015
- if (file_count(file) > 1) {
1016
- v |= FDPUT_POS_UNLOCK;
1017
- mutex_lock(&file->f_pos_lock);
1018
- }
1031
+ if (file && file_needs_f_pos_lock(file)) {
1032
+ v |= FDPUT_POS_UNLOCK;
1033
+ mutex_lock(&file->f_pos_lock);
10191034 }
10201035 return v;
10211036 }