On Wed, Sep 21, 2022 at 3:21 AM David Laight <David.Laight@xxxxxxxxxx> wrote: > > From: Ivan Babrou > > Sent: 20 September 2022 20:06 > ... > > > > +static int proc_readfd_count(struct inode *inode) > > +{ > > + struct task_struct *p = get_proc_task(inode); > > + struct fdtable *fdt; > > + unsigned int i, size, open_fds = 0; > > + > > + if (!p) > > + return -ENOENT; > > + > > + if (p->files) { > > + fdt = files_fdtable(p->files); > > + size = fdt->max_fds; > > + > > + for (i = size / BITS_PER_LONG; i > 0;) > > + open_fds += hweight64(fdt->open_fds[--i]); > > + } I'm missing put_task_struct(p) here. > > + > > + return open_fds; > > +} > > + > > Doesn't that need (at least) rcu protection? Should I enclose the "if" in rcu_read_lock() / rcu_read_unlock()? files_fdtable() is this: * https://elixir.bootlin.com/linux/v6.0-rc6/source/include/linux/fdtable.h#L77 #define files_fdtable(files) \ rcu_dereference_check_fdtable((files), (files)->fdt) And rcu_dereference_check_fdtable() is #define rcu_dereference_check_fdtable(files, fdtfd) \ rcu_dereference_check((fdtfd), lockdep_is_held(&(files)->file_lock)) I definitely need some help with locking here. > There might also be issues reading p->files twice. This block for reading twice: if (p->files) { fdt = files_fdtable(p->files); Already exists in fs/proc/array.c in task_state(): * https://elixir.bootlin.com/linux/v6.0-rc6/source/fs/proc/array.c#L173 There's task_lock(p) there, so maybe that's why it's allowed. Should I run files_fdtable(p->files) unconditionally and then check the result instead? I'm happy to change it to something else if you can tell me what it should be. If there are kernel options I should enable for testing this, I'd be happy to hear them. So far we've tried running with KASAN with no issues.