Message ID | 20240929140343.9147-1-pali@kernel.org |
---|---|
State | New |
Headers | show |
Series | [v2] cifs: Remove intermediate object of failed create reparse call | expand |
Running regression tests on these currently. Let me know if additional patches to add for these experiments 1c2fcb28ce99 (HEAD -> for-next, origin/for-next, origin/HEAD) cifs: Do not convert delimiter when parsing NFS-style symlinks 92484193d70a cifs: Validate content of NFS reparse point buffer c77a8e49f2d3 cifs: Fix buffer overflow when parsing NFS reparse points ab7d68fd4bcc cifs: Remove intermediate object of failed create reparse call ab50485ea1b4 smb: Update comments about some reparse point tags 1600fe2d42a1 smb: client: stop flooding dmesg with automounts f7a33d56e52f smb: client: stop flooding dmesg on failed session setups e1b72ef3ba03 cifs: Check for UTF-16 null codepoint in SFU symlink target location 9717d5343849 Merge tag 'v6.12-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd On Sun, Sep 29, 2024 at 9:04 AM Pali Rohár <pali@kernel.org> wrote: > > If CREATE was successful but SMB2_OP_SET_REPARSE failed then remove the > intermediate object created by CREATE. Otherwise empty object stay on the > server when reparse call failed. > > This ensures that if the creating of special files is unsupported by the > server then no empty file stay on the server as a result of unsupported > operation. > > Fixes: 102466f303ff ("smb: client: allow creating special files via reparse points") > Signed-off-by: Pali Rohár <pali@kernel.org> > --- > Changes in v2: > * Increase out_buftype[] and out_iov[] members from 2 to 4 as required by smb2_compound_op > * Call free_rsp_buf() for all members of out_buftype[]/out_iov[] > > I would like if you double check this smb2_compound_op() usage if there > is not some other memory issue. As V1 contained both memory leak and > buffer overflow (smb2_compound_op wrote out of those two arrays). > > --- > fs/smb/client/smb2inode.c | 22 ++++++++++++++++++++-- > 1 file changed, 20 insertions(+), 2 deletions(-) > > diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c > index 11a1c53c64e0..6e69a3b98be3 100644 > --- a/fs/smb/client/smb2inode.c > +++ b/fs/smb/client/smb2inode.c > @@ -1205,9 +1205,12 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, > struct cifs_sb_info *cifs_sb = CIFS_SB(sb); > struct cifsFileInfo *cfile; > struct inode *new = NULL; > + int out_buftype[4] = {}; > + struct kvec out_iov[4] = {}; > struct kvec in_iov[2]; > int cmds[2]; > int rc; > + int i; > > oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, > SYNCHRONIZE | DELETE | > @@ -1228,7 +1231,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, > cmds[1] = SMB2_OP_POSIX_QUERY_INFO; > cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); > rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, > - in_iov, cmds, 2, cfile, NULL, NULL, NULL); > + in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); > if (!rc) { > rc = smb311_posix_get_inode_info(&new, full_path, > data, sb, xid); > @@ -1237,12 +1240,27 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, > cmds[1] = SMB2_OP_QUERY_INFO; > cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); > rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, > - in_iov, cmds, 2, cfile, NULL, NULL, NULL); > + in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); > if (!rc) { > rc = cifs_get_inode_info(&new, full_path, > data, sb, xid, NULL); > } > } > + > + if (rc) { > + /* > + * If CREATE was successful but SMB2_OP_SET_REPARSE failed then > + * remove the intermediate object created by CREATE. Otherwise > + * empty object stay on the server when reparse call failed. > + */ > + if (((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS && > + ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS) > + smb2_unlink(xid, tcon, full_path, cifs_sb, NULL); > + } > + > + for (i = 0; i < ARRAY_SIZE(out_buftype); i++) > + free_rsp_buf(out_buftype[i], out_iov[i].iov_base); > + > return rc ? ERR_PTR(rc) : new; > } > > -- > 2.20.1 > >
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 11a1c53c64e0..6e69a3b98be3 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -1205,9 +1205,12 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifsFileInfo *cfile; struct inode *new = NULL; + int out_buftype[4] = {}; + struct kvec out_iov[4] = {}; struct kvec in_iov[2]; int cmds[2]; int rc; + int i; oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, SYNCHRONIZE | DELETE | @@ -1228,7 +1231,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, cmds[1] = SMB2_OP_POSIX_QUERY_INFO; cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, - in_iov, cmds, 2, cfile, NULL, NULL, NULL); + in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); if (!rc) { rc = smb311_posix_get_inode_info(&new, full_path, data, sb, xid); @@ -1237,12 +1240,27 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, cmds[1] = SMB2_OP_QUERY_INFO; cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, - in_iov, cmds, 2, cfile, NULL, NULL, NULL); + in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL); if (!rc) { rc = cifs_get_inode_info(&new, full_path, data, sb, xid, NULL); } } + + if (rc) { + /* + * If CREATE was successful but SMB2_OP_SET_REPARSE failed then + * remove the intermediate object created by CREATE. Otherwise + * empty object stay on the server when reparse call failed. + */ + if (((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS && + ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS) + smb2_unlink(xid, tcon, full_path, cifs_sb, NULL); + } + + for (i = 0; i < ARRAY_SIZE(out_buftype); i++) + free_rsp_buf(out_buftype[i], out_iov[i].iov_base); + return rc ? ERR_PTR(rc) : new; }
If CREATE was successful but SMB2_OP_SET_REPARSE failed then remove the intermediate object created by CREATE. Otherwise empty object stay on the server when reparse call failed. This ensures that if the creating of special files is unsupported by the server then no empty file stay on the server as a result of unsupported operation. Fixes: 102466f303ff ("smb: client: allow creating special files via reparse points") Signed-off-by: Pali Rohár <pali@kernel.org> --- Changes in v2: * Increase out_buftype[] and out_iov[] members from 2 to 4 as required by smb2_compound_op * Call free_rsp_buf() for all members of out_buftype[]/out_iov[] I would like if you double check this smb2_compound_op() usage if there is not some other memory issue. As V1 contained both memory leak and buffer overflow (smb2_compound_op wrote out of those two arrays). --- fs/smb/client/smb2inode.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)