Skip to content

Commit

Permalink
ksmbd: replace generic_fillattr with vfs_getattr
Browse files Browse the repository at this point in the history
[ Upstream commit 5614c8c ]

generic_fillattr should not be used outside of ->getattr
implementations.

Use vfs_getattr instead, and adapt functions to return an
error code to the caller.

Cc: stable@vger.kernel.org
Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Marios Makassikis authored and gregkh committed Apr 3, 2024
1 parent dc79bb9 commit 88779f0
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 66 deletions.
170 changes: 110 additions & 60 deletions fs/smb/server/smb2pdu.c
Expand Up @@ -3828,11 +3828,16 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv)
}

ksmbd_kstat.kstat = &kstat;
if (priv->info_level != FILE_NAMES_INFORMATION)
ksmbd_vfs_fill_dentry_attrs(priv->work,
idmap,
dent,
&ksmbd_kstat);
if (priv->info_level != FILE_NAMES_INFORMATION) {
rc = ksmbd_vfs_fill_dentry_attrs(priv->work,
idmap,
dent,
&ksmbd_kstat);
if (rc) {
dput(dent);
continue;
}
}

rc = smb2_populate_readdir_entry(priv->work->conn,
priv->info_level,
Expand Down Expand Up @@ -4480,16 +4485,20 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
struct smb2_file_basic_info *basic_info;
struct kstat stat;
u64 time;
int ret;

if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
pr_err("no right to read the attributes : 0x%x\n",
fp->daccess);
return -EACCES;
}

ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

basic_info = (struct smb2_file_basic_info *)rsp->Buffer;
generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
file_inode(fp->filp), &stat);
basic_info->CreationTime = cpu_to_le64(fp->create_time);
time = ksmbd_UnixTimeToNT(stat.atime);
basic_info->LastAccessTime = cpu_to_le64(time);
Expand All @@ -4504,27 +4513,31 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
return 0;
}

static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
static int get_file_standard_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
{
struct smb2_file_standard_info *sinfo;
unsigned int delete_pending;
struct inode *inode;
struct kstat stat;
int ret;

inode = file_inode(fp->filp);
generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
delete_pending = ksmbd_inode_pending_delete(fp);

sinfo->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);
sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);
sinfo->DeletePending = delete_pending;
sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0;
rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_standard_info));

return 0;
}

static void get_file_alignment_info(struct smb2_query_info_rsp *rsp,
Expand All @@ -4546,11 +4559,11 @@ static int get_file_all_info(struct ksmbd_work *work,
struct ksmbd_conn *conn = work->conn;
struct smb2_file_all_info *file_info;
unsigned int delete_pending;
struct inode *inode;
struct kstat stat;
int conv_len;
char *filename;
u64 time;
int ret;

if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n",
Expand All @@ -4562,8 +4575,10 @@ static int get_file_all_info(struct ksmbd_work *work,
if (IS_ERR(filename))
return PTR_ERR(filename);

inode = file_inode(fp->filp);
generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

ksmbd_debug(SMB, "filename = %s\n", filename);
delete_pending = ksmbd_inode_pending_delete(fp);
Expand All @@ -4579,7 +4594,7 @@ static int get_file_all_info(struct ksmbd_work *work,
file_info->Attributes = fp->f_ci->m_fattr;
file_info->Pad1 = 0;
file_info->AllocationSize =
cpu_to_le64(inode->i_blocks << 9);
cpu_to_le64(stat.blocks << 9);
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
file_info->NumberOfLinks =
cpu_to_le32(get_nlink(&stat) - delete_pending);
Expand Down Expand Up @@ -4623,10 +4638,10 @@ static void get_file_alternate_info(struct ksmbd_work *work,
cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len);
}

static void get_file_stream_info(struct ksmbd_work *work,
struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp,
void *rsp_org)
static int get_file_stream_info(struct ksmbd_work *work,
struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp,
void *rsp_org)
{
struct ksmbd_conn *conn = work->conn;
struct smb2_file_stream_info *file_info;
Expand All @@ -4637,9 +4652,13 @@ static void get_file_stream_info(struct ksmbd_work *work,
int nbytes = 0, streamlen, stream_name_len, next, idx = 0;
int buf_free_len;
struct smb2_query_info_req *req = ksmbd_req_buf_next(work);
int ret;

ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
file_inode(fp->filp), &stat);
file_info = (struct smb2_file_stream_info *)rsp->Buffer;

buf_free_len =
Expand Down Expand Up @@ -4720,40 +4739,50 @@ static void get_file_stream_info(struct ksmbd_work *work,
kvfree(xattr_list);

rsp->OutputBufferLength = cpu_to_le32(nbytes);

return 0;
}

static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
static int get_file_internal_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
{
struct smb2_file_internal_info *file_info;
struct kstat stat;
int ret;

ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
file_inode(fp->filp), &stat);
file_info = (struct smb2_file_internal_info *)rsp->Buffer;
file_info->IndexNumber = cpu_to_le64(stat.ino);
rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_internal_info));

return 0;
}

static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
{
struct smb2_file_ntwrk_info *file_info;
struct inode *inode;
struct kstat stat;
u64 time;
int ret;

if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
pr_err("no right to read the attributes : 0x%x\n",
fp->daccess);
return -EACCES;
}

file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;
ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

inode = file_inode(fp->filp);
generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;

file_info->CreationTime = cpu_to_le64(fp->create_time);
time = ksmbd_UnixTimeToNT(stat.atime);
Expand All @@ -4763,8 +4792,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
time = ksmbd_UnixTimeToNT(stat.ctime);
file_info->ChangeTime = cpu_to_le64(time);
file_info->Attributes = fp->f_ci->m_fattr;
file_info->AllocationSize =
cpu_to_le64(inode->i_blocks << 9);
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
file_info->Reserved = cpu_to_le32(0);
rsp->OutputBufferLength =
Expand Down Expand Up @@ -4804,14 +4832,17 @@ static void get_file_mode_info(struct smb2_query_info_rsp *rsp,
cpu_to_le32(sizeof(struct smb2_file_mode_info));
}

static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
static int get_file_compression_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
{
struct smb2_file_comp_info *file_info;
struct kstat stat;
int ret;

generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
file_inode(fp->filp), &stat);
ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

file_info = (struct smb2_file_comp_info *)rsp->Buffer;
file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9);
Expand All @@ -4823,6 +4854,8 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp,

rsp->OutputBufferLength =
cpu_to_le32(sizeof(struct smb2_file_comp_info));

return 0;
}

static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,
Expand All @@ -4844,32 +4877,39 @@ static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,
return 0;
}

static void find_file_posix_info(struct smb2_query_info_rsp *rsp,
static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
struct ksmbd_file *fp, void *rsp_org)
{
struct smb311_posix_qinfo *file_info;
struct inode *inode = file_inode(fp->filp);
struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);
vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);
vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
struct kstat stat;
u64 time;
int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32;
int ret;

ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret)
return ret;

file_info = (struct smb311_posix_qinfo *)rsp->Buffer;
file_info->CreationTime = cpu_to_le64(fp->create_time);
time = ksmbd_UnixTimeToNT(inode_get_atime(inode));
time = ksmbd_UnixTimeToNT(stat.atime);
file_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(inode_get_mtime(inode));
time = ksmbd_UnixTimeToNT(stat.mtime);
file_info->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(inode_get_ctime(inode));
time = ksmbd_UnixTimeToNT(stat.ctime);
file_info->ChangeTime = cpu_to_le64(time);
file_info->DosAttributes = fp->f_ci->m_fattr;
file_info->Inode = cpu_to_le64(inode->i_ino);
file_info->EndOfFile = cpu_to_le64(inode->i_size);
file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
file_info->HardLinks = cpu_to_le32(inode->i_nlink);
file_info->Mode = cpu_to_le32(inode->i_mode & 0777);
file_info->DeviceId = cpu_to_le32(inode->i_rdev);
file_info->Inode = cpu_to_le64(stat.ino);
file_info->EndOfFile = cpu_to_le64(stat.size);
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
file_info->HardLinks = cpu_to_le32(stat.nlink);
file_info->Mode = cpu_to_le32(stat.mode & 0777);
file_info->DeviceId = cpu_to_le32(stat.rdev);

/*
* Sids(32) contain two sids(Domain sid(16), UNIX group sid(16)).
Expand All @@ -4882,6 +4922,8 @@ static void find_file_posix_info(struct smb2_query_info_rsp *rsp,
SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]);

rsp->OutputBufferLength = cpu_to_le32(out_buf_len);

return 0;
}

static int smb2_get_info_file(struct ksmbd_work *work,
Expand Down Expand Up @@ -4930,7 +4972,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
break;

case FILE_STANDARD_INFORMATION:
get_file_standard_info(rsp, fp, work->response_buf);
rc = get_file_standard_info(rsp, fp, work->response_buf);
break;

case FILE_ALIGNMENT_INFORMATION:
Expand All @@ -4946,11 +4988,11 @@ static int smb2_get_info_file(struct ksmbd_work *work,
break;

case FILE_STREAM_INFORMATION:
get_file_stream_info(work, rsp, fp, work->response_buf);
rc = get_file_stream_info(work, rsp, fp, work->response_buf);
break;

case FILE_INTERNAL_INFORMATION:
get_file_internal_info(rsp, fp, work->response_buf);
rc = get_file_internal_info(rsp, fp, work->response_buf);
break;

case FILE_NETWORK_OPEN_INFORMATION:
Expand All @@ -4974,7 +5016,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
break;

case FILE_COMPRESSION_INFORMATION:
get_file_compression_info(rsp, fp, work->response_buf);
rc = get_file_compression_info(rsp, fp, work->response_buf);
break;

case FILE_ATTRIBUTE_TAG_INFORMATION:
Expand All @@ -4985,7 +5027,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
rc = -EOPNOTSUPP;
} else {
find_file_posix_info(rsp, fp, work->response_buf);
rc = find_file_posix_info(rsp, fp, work->response_buf);
}
break;
default:
Expand Down Expand Up @@ -5398,7 +5440,6 @@ int smb2_close(struct ksmbd_work *work)
struct smb2_close_rsp *rsp;
struct ksmbd_conn *conn = work->conn;
struct ksmbd_file *fp;
struct inode *inode;
u64 time;
int err = 0;

Expand Down Expand Up @@ -5453,24 +5494,33 @@ int smb2_close(struct ksmbd_work *work)
rsp->Reserved = 0;

if (req->Flags == SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB) {
struct kstat stat;
int ret;

fp = ksmbd_lookup_fd_fast(work, volatile_id);
if (!fp) {
err = -ENOENT;
goto out;
}

inode = file_inode(fp->filp);
ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
if (ret) {
ksmbd_fd_put(work, fp);
goto out;
}

rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
rsp->AllocationSize = S_ISDIR(inode->i_mode) ? 0 :
cpu_to_le64(inode->i_blocks << 9);
rsp->EndOfFile = cpu_to_le64(inode->i_size);
rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :
cpu_to_le64(stat.blocks << 9);
rsp->EndOfFile = cpu_to_le64(stat.size);
rsp->Attributes = fp->f_ci->m_fattr;
rsp->CreationTime = cpu_to_le64(fp->create_time);
time = ksmbd_UnixTimeToNT(inode_get_atime(inode));
time = ksmbd_UnixTimeToNT(stat.atime);
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(inode_get_mtime(inode));
time = ksmbd_UnixTimeToNT(stat.mtime);
rsp->LastWriteTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(inode_get_ctime(inode));
time = ksmbd_UnixTimeToNT(stat.ctime);
rsp->ChangeTime = cpu_to_le64(time);
ksmbd_fd_put(work, fp);
} else {
Expand Down

0 comments on commit 88779f0

Please sign in to comment.