| From 3cb6ee991496b67ee284c6895a0ba007e2d7bac3 Mon Sep 17 00:00:00 2001 |
| From: Christian Brauner <christian.brauner@ubuntu.com> |
| Date: Mon, 29 Nov 2021 12:44:34 +0100 |
| Subject: 9p: only copy valid iattrs in 9P2000.L setattr implementation |
| |
| From: Christian Brauner <christian.brauner@ubuntu.com> |
| |
| commit 3cb6ee991496b67ee284c6895a0ba007e2d7bac3 upstream. |
| |
| The 9P2000.L setattr method v9fs_vfs_setattr_dotl() copies struct iattr |
| values without checking whether they are valid causing unitialized |
| values to be copied. The 9P2000 setattr method v9fs_vfs_setattr() method |
| gets this right. Check whether struct iattr fields are valid first |
| before copying in v9fs_vfs_setattr_dotl() too and make sure that all |
| other fields are set to 0 apart from {g,u}id which should be set to |
| INVALID_{G,U}ID. This ensure that they can be safely sent over the wire |
| or printed for debugging later on. |
| |
| Link: https://lkml.kernel.org/r/20211129114434.3637938-1-brauner@kernel.org |
| Link: https://lkml.kernel.org/r/000000000000a0d53f05d1c72a4c%40google.com |
| Cc: Eric Van Hensbergen <ericvh@gmail.com> |
| Cc: Latchesar Ionkov <lucho@ionkov.net> |
| Cc: Dominique Martinet <asmadeus@codewreck.org> |
| Cc: stable@kernel.org |
| Cc: v9fs-developer@lists.sourceforge.net |
| Reported-by: syzbot+dfac92a50024b54acaa4@syzkaller.appspotmail.com |
| Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com> |
| [Dominique: do not set a/mtime with just ATTR_A/MTIME as discussed] |
| Signed-off-by: Dominique Martinet <asmadeus@codewreck.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/9p/vfs_inode_dotl.c | 29 ++++++++++++++++++++--------- |
| 1 file changed, 20 insertions(+), 9 deletions(-) |
| |
| --- a/fs/9p/vfs_inode_dotl.c |
| +++ b/fs/9p/vfs_inode_dotl.c |
| @@ -553,7 +553,10 @@ int v9fs_vfs_setattr_dotl(struct user_na |
| { |
| int retval, use_dentry = 0; |
| struct p9_fid *fid = NULL; |
| - struct p9_iattr_dotl p9attr; |
| + struct p9_iattr_dotl p9attr = { |
| + .uid = INVALID_UID, |
| + .gid = INVALID_GID, |
| + }; |
| struct inode *inode = d_inode(dentry); |
| |
| p9_debug(P9_DEBUG_VFS, "\n"); |
| @@ -563,14 +566,22 @@ int v9fs_vfs_setattr_dotl(struct user_na |
| return retval; |
| |
| p9attr.valid = v9fs_mapped_iattr_valid(iattr->ia_valid); |
| - p9attr.mode = iattr->ia_mode; |
| - p9attr.uid = iattr->ia_uid; |
| - p9attr.gid = iattr->ia_gid; |
| - p9attr.size = iattr->ia_size; |
| - p9attr.atime_sec = iattr->ia_atime.tv_sec; |
| - p9attr.atime_nsec = iattr->ia_atime.tv_nsec; |
| - p9attr.mtime_sec = iattr->ia_mtime.tv_sec; |
| - p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; |
| + if (iattr->ia_valid & ATTR_MODE) |
| + p9attr.mode = iattr->ia_mode; |
| + if (iattr->ia_valid & ATTR_UID) |
| + p9attr.uid = iattr->ia_uid; |
| + if (iattr->ia_valid & ATTR_GID) |
| + p9attr.gid = iattr->ia_gid; |
| + if (iattr->ia_valid & ATTR_SIZE) |
| + p9attr.size = iattr->ia_size; |
| + if (iattr->ia_valid & ATTR_ATIME_SET) { |
| + p9attr.atime_sec = iattr->ia_atime.tv_sec; |
| + p9attr.atime_nsec = iattr->ia_atime.tv_nsec; |
| + } |
| + if (iattr->ia_valid & ATTR_MTIME_SET) { |
| + p9attr.mtime_sec = iattr->ia_mtime.tv_sec; |
| + p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; |
| + } |
| |
| if (iattr->ia_valid & ATTR_FILE) { |
| fid = iattr->ia_file->private_data; |