This introduces a function which can be used to fetch a file, given an arbitrary task. As long as the user holds a reference (refcnt) to the task_struct it is safe to call, and will either return NULL on failure, or a pointer to the file, with a refcnt. This patch is based on Oleg Nesterov's (cf. [1]) patch from September 2018. [1]: Link: https://lore.kernel.org/r/20180915160423.GA31461@redhat.com
Unified · Split
| @@ -706,9 +706,9 @@ void do_close_on_exec(struct files_struct *files) · 705 unmodified lines | |||
| 706 | spin_unlock(&files->file_lock); | 706 | spin_unlock(&files->file_lock); |
| 707 | } | 707 | } |
| 708 | 708 | ||
| 709 | static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs) | 709 | static struct file *__fget_files(struct files_struct *files, unsigned int fd, |
| 710 | fmode_t mask, unsigned int refs) | ||
| 710 | { | 711 | { |
| 711 | struct files_struct *files = current->files; | ||
| 712 | struct file *file; | 712 | struct file *file; |
| 713 | 713 | ||
| 714 | rcu_read_lock(); | 714 | rcu_read_lock(); |
| @@ -729,6 +729,12 @@ loop: · 14 unmodified lines | |||
| 729 | return file; | 729 | return file; |
| 730 | } | 730 | } |
| 731 | 731 | ||
| 732 | static inline struct file *__fget(unsigned int fd, fmode_t mask, | ||
| 733 | unsigned int refs) | ||
| 734 | { | ||
| 735 | return __fget_files(current->files, fd, mask, refs); | ||
| 736 | } | ||
| 737 | |||
| 732 | struct file *fget_many(unsigned int fd, unsigned int refs) | 738 | struct file *fget_many(unsigned int fd, unsigned int refs) |
| 733 | { | 739 | { |
| 734 | return __fget(fd, FMODE_PATH, refs); | 740 | return __fget(fd, FMODE_PATH, refs); |
| @@ -746,6 +752,18 @@ struct file *fget_raw(unsigned int fd) · 11 unmodified lines | |||
| 746 | } | 752 | } |
| 747 | EXPORT_SYMBOL(fget_raw); | 753 | EXPORT_SYMBOL(fget_raw); |
| 748 | 754 | ||
| 755 | struct file *fget_task(struct task_struct *task, unsigned int fd) | ||
| 756 | { | ||
| 757 | struct file *file = NULL; | ||
| 758 | |||
| 759 | task_lock(task); | ||
| 760 | if (task->files) | ||
| 761 | file = __fget_files(task->files, fd, 0, 1); | ||
| 762 | task_unlock(task); | ||
| 763 | |||
| 764 | return file; | ||
| 765 | } | ||
| 766 | |||
| 749 | /* | 767 | /* |
| 750 | * Lightweight file lookup - no refcnt increment if fd table isn't shared. | 768 | * Lightweight file lookup - no refcnt increment if fd table isn't shared. |
| 751 | * | 769 | * |
| @@ -16,6 +16,7 @@ extern void fput(struct file *); · 15 unmodified lines | |||
| 16 | extern void fput_many(struct file *, unsigned int); | 16 | extern void fput_many(struct file *, unsigned int); |
| 17 | 17 | ||
| 18 | struct file_operations; | 18 | struct file_operations; |
| 19 | struct task_struct; | ||
| 19 | struct vfsmount; | 20 | struct vfsmount; |
| 20 | struct dentry; | 21 | struct dentry; |
| 21 | struct inode; | 22 | struct inode; |
| @@ -47,6 +48,7 @@ static inline void fdput(struct fd fd) · 25 unmodified lines | |||
| 47 | extern struct file *fget(unsigned int fd); | 48 | extern struct file *fget(unsigned int fd); |
| 48 | extern struct file *fget_many(unsigned int fd, unsigned int refs); | 49 | extern struct file *fget_many(unsigned int fd, unsigned int refs); |
| 49 | extern struct file *fget_raw(unsigned int fd); | 50 | extern struct file *fget_raw(unsigned int fd); |
| 51 | extern struct file *fget_task(struct task_struct *task, unsigned int fd); | ||
| 50 | extern unsigned long __fdget(unsigned int fd); | 52 | extern unsigned long __fdget(unsigned int fd); |
| 51 | extern unsigned long __fdget_raw(unsigned int fd); | 53 | extern unsigned long __fdget_raw(unsigned int fd); |
| 52 | extern unsigned long __fdget_pos(unsigned int fd); | 54 | extern unsigned long __fdget_pos(unsigned int fd); |