]> git.dujemihanovic.xyz Git - linux.git/commitdiff
Merge tag 'vfs-6.12.procfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2024 07:36:59 +0000 (09:36 +0200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2024 07:36:59 +0000 (09:36 +0200)
Pull procfs updates from Christian Brauner:
 "This contains the following changes for procfs:

   - Add config options and parameters to block forcing memory writes.

     This adds a Kconfig option and boot param to allow removing the
     FOLL_FORCE flag from /proc/<pid>/mem write calls as this can be
     used in various attacks.

     The traditional forcing behavior is kept as default because it can
     break GDB and some other use cases.

     This is the simpler version that you had requested.

   - Restrict overmounting of ephemeral entities.

     It is currently possible to mount on top of various ephemeral
     entities in procfs. This specifically includes magic links. To
     recap, magic links are links of the form /proc/<pid>/fd/<nr>. They
     serve as references to a target file and during path lookup they
     cause a jump to the target path. Such magic links disappear if the
     corresponding file descriptor is closed.

     Currently it is possible to overmount such magic links. This is
     mostly interesting for an attacker that wants to somehow trick a
     process into e.g., reopening something that it didn't intend to
     reopen or to hide a malicious file descriptor.

     But also it risks leaking mounts for long-running processes. When
     overmounting a magic link like above, the mount will not be
     detached when the file descriptor is closed. Only the target
     mountpoint will disappear. Which has the consequence of making it
     impossible to unmount that mount afterwards. So the mount will
     stick around until the process exits and the /proc/<pid>/ directory
     is cleaned up during proc_flush_pid() when the dentries are pruned
     and invalidated.

     That in turn means it's possible for a program to accidentally leak
     mounts and it's also possible to make a task leak mounts without
     it's knowledge if the attacker just keeps overmounting things under
     /proc/<pid>/fd/<nr>.

     Disallow overmounting of such ephemeral entities.

   - Cleanup the readdir method naming in some procfs file operations.

   - Replace kmalloc() and strcpy() with a simple kmemdup() call"

* tag 'vfs-6.12.procfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  proc: fold kmalloc() + strcpy() into kmemdup()
  proc: block mounting on top of /proc/<pid>/fdinfo/*
  proc: block mounting on top of /proc/<pid>/fd/*
  proc: block mounting on top of /proc/<pid>/map_files/*
  proc: add proc_splice_unmountable()
  proc: proc_readfdinfo() -> proc_fdinfo_iterate()
  proc: proc_readfd() -> proc_fd_iterate()
  proc: add config & param to block forcing mem writes

1  2 
Documentation/admin-guide/kernel-parameters.txt
fs/proc/base.c
fs/proc/fd.c

diff --cc fs/proc/base.c
index 7f3abc3de49fbd7d09c5006254fc32bf2b035d02,a2ff8e1c9bbea9fb22465d5a1cc193dc723c8917..1ad51858528f7c744c0a687c0aeab7d0d277019a
@@@ -827,11 -862,36 +862,33 @@@ static int __mem_open(struct inode *ino
  
  static int mem_open(struct inode *inode, struct file *file)
  {
 -      int ret = __mem_open(inode, file, PTRACE_MODE_ATTACH);
 -
 -      /* OK to pass negative loff_t, we can catch out-of-range */
 -      file->f_mode |= FMODE_UNSIGNED_OFFSET;
 -
 -      return ret;
 +      if (WARN_ON_ONCE(!(file->f_op->fop_flags & FOP_UNSIGNED_OFFSET)))
 +              return -EINVAL;
 +      return __mem_open(inode, file, PTRACE_MODE_ATTACH);
  }
  
+ static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
+ {
+       struct task_struct *task;
+       bool ptrace_active = false;
+       switch (proc_mem_force_override) {
+       case PROC_MEM_FORCE_NEVER:
+               return false;
+       case PROC_MEM_FORCE_PTRACE:
+               task = get_proc_task(file_inode(file));
+               if (task) {
+                       ptrace_active = READ_ONCE(task->ptrace) &&
+                                       READ_ONCE(task->mm) == mm &&
+                                       READ_ONCE(task->parent) == current;
+                       put_task_struct(task);
+               }
+               return ptrace_active;
+       default:
+               return true;
+       }
+ }
  static ssize_t mem_rw(struct file *file, char __user *buf,
                        size_t count, loff_t *ppos, int write)
  {
diff --cc fs/proc/fd.c
Simple merge