lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 9 Jul 2018 05:53:20 +0100
From:   Al Viro <viro@...IV.linux.org.uk>
To:     Linus Torvalds <torvalds@...ux-foundation.org>
Cc:     linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org
Subject: [RFC][PATCHES] open()-related cleanups

	This is an update of open()-related work last posted a month
ago.  Series lives in vfs.git#work.open (and its beginning is in
#fixes).  Individual patches are in followups, shortlog (with outlines)
follows:
1) some prep fixes:
	* drm_lease.c uses alloc_file() for no good reason - it's
open-coding filp_clone_open() and gets failure handling wrong; failing
->open() should *not* be followed by fput().  Use the real thing instead.
	* cxl_getfile() also buggers failure exits around alloc_file() -
it follows path_put() with iput(), resulting in double iput()
	* ocxlflash_getfile(): same story.

      drm_mode_create_lease_ioctl(): fix open-coded filp_clone_open()
      cxl_getfile(): fix double-iput() on alloc_file() failures
      ocxlflash_getfile(): fix double-iput() on alloc_file() failures

2) We want saner rules for put_filp()/fput() logics.  At some point in
struct file lifecycle it switches from 'clean the things up manually and
do put_filp()' to 'just use fput() from now on'.  Choosing the right one
during the open (especially when ->atomic_open() is involved) is painful
and convoluted.  Things become much simpler if we use struct file itself
to carry that information.
	* make it provable that do_dentry_open() is never called on the
same struct file twice.  That's certainly what we intended all along;
the problems could happen if bogus ->open() returned *positive* for an
error.  That could confuse the living hell out of atomic_open() and friends;
make sure it won't happen.
	* mark the 'should we just use fput() from now on' in ->f_mode.
	* don't pass 'opened' to ->atomic_open()/finish_open(); make the
(very few) callers pick the information we would've passed via
*opened & FILE_OPENED from file->f_mode & FMODE_OPENED instead.
	* massage path_openat() and the helpers it calls, consolidate all
fput()-causing failure handling into path_openat() itself and switch all
checks to FMODE_OPENED.

      make sure do_dentry_open() won't return positive as an error
      introduce FMODE_OPENED
      get rid of 'opened' argument of finish_open()
      lift fput() on late failures into path_openat()
      switch all remaining checks for FILE_OPENED to FMODE_OPENED

3) first payoff: now we can fold open_check_o_direct() into do_dentry_open().
The problem with doing that had been exactly in fput()/put_filp() rules -
we relied upon "failures without do_dentry_open() ever called => put_filp(),
failure after do_dentry_open() succeeded => fput(), failure in do_dentry_open()
itself => put_filp()" (and heaven help us to keep track which case had it
been).  O_DIRECT checks are done past the point where we need fput() and
doing those in do_dentry_open() would've made for "failure in do_dentry_open()
means put_filp(), except when it's a late failure, in which case we want
fput()", without any way for caller of do_dentry_open() to tell which one
it is.  With FMODE_OPENED we *can* tell.

      now we can fold open_check_o_direct() into do_dentry_open()

4) ->atomic_open() and friends are passing two bits of state ("did we get past
opening it" and "did we create it") in a very ugly way - pointer to int
('opened') is passed as an argument, and the variable it points to is used
to store those two bits.  We are not far from getting rid of it for good -
one bit (FILE_OPENED) is already replaced with ->f_mode & FMODE_OPENED and 
and we can use ->f_mode to get rid of FILE_CREATED as well.
	* introduce FMODE_CREATED, set it to parallel *opened & FILE_CREATED
	* get rid of FILE_CREATED in checks
	* get rid of now unused 'opened' in ->atomic_open() and its callers
	* kill now unused FILE_{OPENED,CREATED}

      introduce FMODE_CREATED and switch to it
      IMA: don't propagate opened through the entire thing
      Preparation to killing ->atomic_open() 'opened' argument.
      get rid of 'opened' argument of ->atomic_open()
      get rid of 'opened' in path_openat() and the helpers downstream
      kill FILE_{CREATED,OPENED}

5) sort alloc_file() callers out.  Calling conventions, especially wrt cleanups
on failure, are convoluted (and easy to get wrong).  Callers fall into two
classes and we'd be better off with a couple of wrappers suited for those.
	* introduce alloc_file_pseudo(), convert to its use
	* introduce alloc_file_clone(), convert to its use
	* make alloc_file() itself static

      new wrapper: alloc_file_pseudo()
      __shmem_file_setup(): reorder allocations
      ... and switch shmem_file_setup() to alloc_file_pseudo()
      cxl_getfile(): switch to alloc_file_pseudo()
      ocxlflash_getfile(): switch to alloc_file_pseudo()
      hugetlb_file_setup(): switch to alloc_file_pseudo()
      anon_inode_getfile(): switch to alloc_file_pseudo()
      create_pipe_files(): switch the first allocation to alloc_file_pseudo()
      new helper: alloc_file_clone()
      do_shmat(): grab shp->shm_file earlier, switch to alloc_file_clone()
      make alloc_file() static

6) turn filp_clone_open() into a wrapper for dentry_open(), rename it to
file_clone_open().

      turn filp_clone_open() into inline wrapper for dentry_open()

Diffstat:
 arch/ia64/kernel/perfmon.c            |  1 +
 drivers/gpu/drm/drm_lease.c           | 16 +------
 drivers/misc/cxl/api.c                | 21 ++-------
 drivers/scsi/cxlflash/ocxl_hw.c       | 24 ++--------
 fs/9p/vfs_inode.c                     |  7 ++-
 fs/9p/vfs_inode_dotl.c                |  7 ++-
 fs/aio.c                              | 26 +++--------
 fs/anon_inodes.c                      | 29 +++----------
 fs/bad_inode.c                        |  2 +-
 fs/binfmt_misc.c                      |  2 +-
 fs/ceph/file.c                        |  7 ++-
 fs/ceph/super.h                       |  3 +-
 fs/cifs/cifsfs.h                      |  3 +-
 fs/cifs/dir.c                         |  7 ++-
 fs/file_table.c                       | 41 +++++++++++++++++-
 fs/fuse/dir.c                         | 10 ++---
 fs/gfs2/inode.c                       | 32 +++++++-------
 fs/hugetlbfs/inode.c                  | 55 ++++++++---------------
 fs/internal.h                         |  2 -
 fs/namei.c                            | 82 ++++++++++++++---------------------
 fs/nfs/dir.c                          | 14 +++---
 fs/nfs/nfs4_fs.h                      |  2 +-
 fs/nfs/nfs4proc.c                     |  2 +-
 fs/nfsd/vfs.c                         |  2 +-
 fs/open.c                             | 68 ++++++++---------------------
 fs/pipe.c                             | 38 ++++------------
 include/linux/file.h                  |  7 ++-
 include/linux/fs.h                    | 17 +++++---
 include/linux/ima.h                   |  4 +-
 ipc/shm.c                             | 39 ++++++++---------
 mm/shmem.c                            | 50 +++++----------------
 net/socket.c                          | 27 ++----------
 security/integrity/ima/ima.h          |  4 +-
 security/integrity/ima/ima_appraise.c |  4 +-
 security/integrity/ima/ima_main.c     | 16 +++----
 35 files changed, 247 insertions(+), 423 deletions(-)

Please, review:

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ