syzbot found that touch /proc/testfile causes NULL pointer dereference at tomoyo_get_local_path() because inode of the dentry is NULL. Before c59f415a7cb6, Tomoyo received pid_ns from proc's s_fs_info directly. Since proc_pid_ns() can only work with inode, using it in the tomoyo_get_local_path() was wrong. To avoid creating more functions for getting proc_ns, change the argument type of the proc_pid_ns() function. Then, Tomoyo can use the existing super_block to get pid_ns.
Unified · Split
| @@ -2823,7 +2823,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, · 2822 unmodified lines | ||
| 2823 | 2823 | { |
| 2824 | 2824 | struct inode *inode = NULL; |
| 2825 | 2825 | unsigned int fl_pid; |
| 2826 | − struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)); | |
| 2826 | + struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb); | |
| 2827 | 2827 | |
| 2828 | 2828 | fl_pid = locks_translate_pid(fl, proc_pidns); |
| 2829 | 2829 | /* |
| @@ -2901,7 +2901,7 @@ static int locks_show(struct seq_file *f, void *v) · 71 unmodified lines | ||
| 2901 | 2901 | { |
| 2902 | 2902 | struct locks_iterator *iter = f->private; |
| 2903 | 2903 | struct file_lock *fl, *bfl; |
| 2904 | − struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)); | |
| 2904 | + struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb); | |
| 2905 | 2905 | |
| 2906 | 2906 | fl = hlist_entry(v, struct file_lock, fl_link); |
| 2907 | 2907 | |
| @@ -728,7 +728,7 @@ static int children_seq_show(struct seq_file *seq, void *v) · 727 unmodified lines | ||
| 728 | 728 | { |
| 729 | 729 | struct inode *inode = file_inode(seq->file); |
| 730 | 730 | |
| 731 | − seq_printf(seq, "%d ", pid_nr_ns(v, proc_pid_ns(inode))); | |
| 731 | + seq_printf(seq, "%d ", pid_nr_ns(v, proc_pid_ns(inode->i_sb))); | |
| 732 | 732 | return 0; |
| 733 | 733 | } |
| 734 | 734 | |
| @@ -754,7 +754,7 @@ static const struct inode_operations proc_def_inode_operations = { · 753 unmodified lines | ||
| 754 | 754 | static int proc_single_show(struct seq_file *m, void *v) |
| 755 | 755 | { |
| 756 | 756 | struct inode *inode = m->private; |
| 757 | − struct pid_namespace *ns = proc_pid_ns(inode); | |
| 757 | + struct pid_namespace *ns = proc_pid_ns(inode->i_sb); | |
| 758 | 758 | struct pid *pid = proc_pid(inode); |
| 759 | 759 | struct task_struct *task; |
| 760 | 760 | int ret; |
| @@ -1423,7 +1423,7 @@ static const struct file_operations proc_fail_nth_operations = { · 662 unmodified lines | ||
| 1423 | 1423 | static int sched_show(struct seq_file *m, void *v) |
| 1424 | 1424 | { |
| 1425 | 1425 | struct inode *inode = m->private; |
| 1426 | − struct pid_namespace *ns = proc_pid_ns(inode); | |
| 1426 | + struct pid_namespace *ns = proc_pid_ns(inode->i_sb); | |
| 1427 | 1427 | struct task_struct *p; |
| 1428 | 1428 | |
| 1429 | 1429 | p = get_proc_task(inode); |
| @@ -2466,7 +2466,7 @@ static int proc_timers_open(struct inode *inode, struct file *file) · 1036 unmodified lines | ||
| 2466 | 2466 | return -ENOMEM; |
| 2467 | 2467 | |
| 2468 | 2468 | tp->pid = proc_pid(inode); |
| 2469 | − tp->ns = proc_pid_ns(inode); | |
| 2469 | + tp->ns = proc_pid_ns(inode->i_sb); | |
| 2470 | 2470 | return 0; |
| 2471 | 2471 | } |
| 2472 | 2472 | |
| @@ -3377,7 +3377,7 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) · 904 unmodified lines | ||
| 3377 | 3377 | { |
| 3378 | 3378 | struct tgid_iter iter; |
| 3379 | 3379 | struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb); |
| 3380 | − struct pid_namespace *ns = proc_pid_ns(file_inode(file)); | |
| 3380 | + struct pid_namespace *ns = proc_pid_ns(file_inode(file)->i_sb); | |
| 3381 | 3381 | loff_t pos = ctx->pos; |
| 3382 | 3382 | |
| 3383 | 3383 | if (pos >= PID_MAX_LIMIT + TGID_OFFSET) |
| @@ -3730,7 +3730,7 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx) · 346 unmodified lines | ||
| 3730 | 3730 | /* f_version caches the tgid value that the last readdir call couldn't |
| 3731 | 3731 | * return. lseek aka telldir automagically resets f_version to 0. |
| 3732 | 3732 | */ |
| 3733 | − ns = proc_pid_ns(inode); | |
| 3733 | + ns = proc_pid_ns(inode->i_sb); | |
| 3734 | 3734 | tid = (int)file->f_version; |
| 3735 | 3735 | file->f_version = 0; |
| 3736 | 3736 | for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns); |
| @@ -12,7 +12,7 @@ static const char *proc_self_get_link(struct dentry *dentry, · 11 unmodified lines | ||
| 12 | 12 | struct inode *inode, |
| 13 | 13 | struct delayed_call *done) |
| 14 | 14 | { |
| 15 | − struct pid_namespace *ns = proc_pid_ns(inode); | |
| 15 | + struct pid_namespace *ns = proc_pid_ns(inode->i_sb); | |
| 16 | 16 | pid_t tgid = task_tgid_nr_ns(current, ns); |
| 17 | 17 | char *name; |
| 18 | 18 | |
| @@ -12,7 +12,7 @@ static const char *proc_thread_self_get_link(struct dentry *dentry, · 11 unmodified lines | ||
| 12 | 12 | struct inode *inode, |
| 13 | 13 | struct delayed_call *done) |
| 14 | 14 | { |
| 15 | − struct pid_namespace *ns = proc_pid_ns(inode); | |
| 15 | + struct pid_namespace *ns = proc_pid_ns(inode->i_sb); | |
| 16 | 16 | pid_t tgid = task_tgid_nr_ns(current, ns); |
| 17 | 17 | pid_t pid = task_pid_nr_ns(current, ns); |
| 18 | 18 | char *name; |
| @@ -202,9 +202,9 @@ int open_related_ns(struct ns_common *ns, · 201 unmodified lines | ||
| 202 | 202 | struct ns_common *(*get_ns)(struct ns_common *ns)); |
| 203 | 203 | |
| 204 | 204 | /* get the associated pid namespace for a file in procfs */ |
| 205 | −static inline struct pid_namespace *proc_pid_ns(const struct inode *inode) | |
| 205 | +static inline struct pid_namespace *proc_pid_ns(struct super_block *sb) | |
| 206 | 206 | { |
| 207 | − return proc_sb_info(inode->i_sb)->pid_ns; | |
| 207 | + return proc_sb_info(sb)->pid_ns; | |
| 208 | 208 | } |
| 209 | 209 | |
| 210 | 210 | #endif /* _LINUX_PROC_FS_H */ |
| @@ -1745,7 +1745,7 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f) · 1744 unmodified lines | ||
| 1745 | 1745 | pid_t nr = -1; |
| 1746 | 1746 | |
| 1747 | 1747 | if (likely(pid_has_task(pid, PIDTYPE_PID))) { |
| 1748 | − ns = proc_pid_ns(file_inode(m->file)); | |
| 1748 | + ns = proc_pid_ns(file_inode(m->file)->i_sb); | |
| 1749 | 1749 | nr = pid_nr_ns(pid, ns); |
| 1750 | 1750 | } |
| 1751 | 1751 | |
| @@ -779,7 +779,7 @@ static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos) · 778 unmodified lines | ||
| 779 | 779 | { |
| 780 | 780 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); |
| 781 | 781 | |
| 782 | − state->pid_ns = proc_pid_ns(file_inode(seq->file)); | |
| 782 | + state->pid_ns = proc_pid_ns(file_inode(seq->file)->i_sb); | |
| 783 | 783 | |
| 784 | 784 | rcu_read_lock_bh(); |
| 785 | 785 | return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
| @@ -162,7 +162,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer, · 161 unmodified lines | ||
| 162 | 162 | if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') { |
| 163 | 163 | char *ep; |
| 164 | 164 | const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10); |
| 165 | − struct pid_namespace *proc_pidns = proc_pid_ns(d_inode(dentry)); | |
| 165 | + struct pid_namespace *proc_pidns = proc_pid_ns(sb); | |
| 166 | 166 | |
| 167 | 167 | if (*ep == '/' && pid && pid == |
| 168 | 168 | task_tgid_nr_ns(current, proc_pidns)) { |