Patch "coredump: require O_WRONLY instead of O_RDWR" has been added to the 6.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    coredump: require O_WRONLY instead of O_RDWR

to the 6.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     coredump-require-o_wronly-instead-of-o_rdwr.patch
and it can be found in the queue-6.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 84cf980dd4db7ee769fb717d38e7496946be5988
Author: Vladimir Sementsov-Ogievskiy <vsementsov@xxxxxxxxxxxxxx>
Date:   Thu Apr 20 15:04:09 2023 +0300

    coredump: require O_WRONLY instead of O_RDWR
    
    [ Upstream commit 88e4607034ee49e09e32d91d083dced5c2f4f127 ]
    
    The motivation for this patch has been to enable using a stricter
    apparmor profile to prevent programs from reading any coredump in the
    system.
    
    However, this became something else. The following details are based on
    Christian's and Linus' archeology into the history of the number "2" in
    the coredump handling code.
    
    To make sure we're not accidently introducing some subtle behavioral
    change into the coredump code we set out on a voyage into the depths of
    history.git to figure out why this was O_RDWR in the first place.
    
    Coredump handling was introduced over 30 years ago in commit
    ddc733f452e0 ("[PATCH] Linux-0.97 (August 1, 1992)").
    The original code used O_WRONLY:
    
        open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode,NULL)
    
    However, this changed in 1993 and starting with commit
    9cb9f18b5d26 ("[PATCH] Linux-0.99.10 (June 7, 1993)") the coredump code
    suddenly used the constant "2":
    
        open_namei("core",O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)
    
    This was curious as in the same commit the kernel switched from
    constants to proper defines in other places such as KERNEL_DS and
    USER_DS and O_RDWR did already exist.
    
    So why was "2" used? It turns out that open_namei() - an early version
    of what later turned into filp_open() - didn't accept O_RDWR.
    
    A semantic quirk of the open() uapi is the definition of the O_RDONLY
    flag. It would seem natural to define:
    
        #define O_RDWR (O_RDONLY | O_WRONLY)
    
    but that isn't possible because:
    
        #define O_RDONLY 0
    
    This makes O_RDONLY effectively meaningless when passed to the kernel.
    In other words, there has never been a way - until O_PATH at least - to
    open a file without any permission; O_RDONLY was always implied on the
    uapi side while the kernel does in fact allow opening files without
    permissions.
    
    The trouble comes when trying to map the uapi flags onto the
    corresponding file mode flags FMODE_{READ,WRITE}. This mapping still
    happens today and is causing issues to this day (We ran into this
    during additions for openat2() for example.).
    
    So the special value "3" was used to indicate that the file was opened
    for special access:
    
        f->f_flags = flag = flags;
        f->f_mode = (flag+1) & O_ACCMODE;
        if (f->f_mode)
                flag++;
    
    This allowed the file mode to be set to FMODE_READ | FMODE_WRITE mapping
    the O_{RDONLY,WRONLY,RDWR} flags into the FMODE_{READ,WRITE} flags. The
    special access then required read-write permissions and 0 was used to
    access symlinks.
    
    But back when ddc733f452e0 ("[PATCH] Linux-0.97 (August 1, 1992)") added
    coredump handling open_namei() took the FMODE_{READ,WRITE} flags as an
    argument. So the coredump handling introduced in
    ddc733f452e0 ("[PATCH] Linux-0.97 (August 1, 1992)") was buggy because
    O_WRONLY shouldn't have been passed. Since O_WRONLY is 1 but
    open_namei() took FMODE_{READ,WRITE} it was passed FMODE_READ on
    accident.
    
    So 9cb9f18b5d26 ("[PATCH] Linux-0.99.10 (June 7, 1993)") was a bugfix
    for this and the 2 didn't really mean O_RDWR, it meant FMODE_WRITE which
    was correct.
    
    The clue is that FMODE_{READ,WRITE} didn't exist yet and thus a raw "2"
    value was passed.
    
    Fast forward 5 years when around 2.2.4pre4 (February 16, 1999) this code
    was changed to:
    
        -       dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
        ...
        +       file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
    
    At this point the raw "2" should have become O_WRONLY again as
    filp_open() didn't take FMODE_{READ,WRITE} but O_{RDONLY,WRONLY,RDWR}.
    
    Another 17 years later, the code was changed again cementing the mistake
    and making it almost impossible to detect when commit
    378c6520e7d2 ("fs/coredump: prevent fsuid=0 dumps into user-controlled directories")
    replaced the raw "2" with O_RDWR.
    
    And now, here we are with this patch that sent us on a quest to answer
    the big questions in life such as "Why are coredump files opened with
    O_RDWR?" and "Is it safe to just use O_WRONLY?".
    
    So with this commit we're reintroducing O_WRONLY again and bringing this
    code back to its original state when it was first introduced in commit
    ddc733f452e0 ("[PATCH] Linux-0.97 (August 1, 1992)") over 30 years ago.
    
    Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@xxxxxxxxxxxxxx>
    Message-Id: <20230420120409.602576-1-vsementsov@xxxxxxxxxxxxxx>
    [brauner@xxxxxxxxxx: completely rewritten commit message]
    Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/coredump.c b/fs/coredump.c
index 88740c51b9420..9d235fa14ab98 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -648,7 +648,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
 	} else {
 		struct mnt_idmap *idmap;
 		struct inode *inode;
-		int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
+		int open_flags = O_CREAT | O_WRONLY | O_NOFOLLOW |
 				 O_LARGEFILE | O_EXCL;
 
 		if (cprm.limit < binfmt->min_coredump)



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux