summary refs log tree commit diff
path: root/fs
diff options
context:
space:
mode:
authorNamjae Jeon <namjae.jeon@samsung.com>2021-07-13 17:12:41 +0900
committerNamjae Jeon <namjae.jeon@samsung.com>2021-07-13 17:22:47 +0900
commit78ad2c277af4cf503f985fd506fbb1f8576460f2 (patch)
tree0e5337a35842e3b52c8e93562bf5bc1fbe7c4f53 /fs
parentf19b3967fb0967aa02b8bfe26ce186ca7525dff7 (diff)
downloadlinux-78ad2c277af4cf503f985fd506fbb1f8576460f2.tar.gz
ksmbd: fix memory leak in ksmbd_vfs_get_sd_xattr()
Add free acl.sd_buf and n.data on error handling in
ksmbd_vfs_get_sd_xattr().

Reported-by: Coverity Scan <scan-admin@coverity.com>
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ksmbd/vfs.c101
1 files changed, 52 insertions, 49 deletions
diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c
index 88e947f69f47..612c52d7a01b 100644
--- a/fs/ksmbd/vfs.c
+++ b/fs/ksmbd/vfs.c
@@ -1498,63 +1498,66 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
 {
 	int rc;
 	struct ndr n;
+	struct inode *inode = d_inode(dentry);
+	struct ndr acl_ndr = {0};
+	struct xattr_ntacl acl;
+	struct xattr_smb_acl *smb_acl = NULL, *def_smb_acl = NULL;
+	__u8 cmp_hash[XATTR_SD_HASH_SIZE] = {0};
 
 	rc = ksmbd_vfs_getxattr(user_ns, dentry, XATTR_NAME_SD, &n.data);
-	if (rc > 0) {
-		struct inode *inode = d_inode(dentry);
-		struct ndr acl_ndr = {0};
-		struct xattr_ntacl acl;
-		struct xattr_smb_acl *smb_acl = NULL, *def_smb_acl = NULL;
-		__u8 cmp_hash[XATTR_SD_HASH_SIZE] = {0};
-
-		n.length = rc;
-		rc = ndr_decode_v4_ntacl(&n, &acl);
-		if (rc)
-			return rc;
-
-		smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode,
-							 ACL_TYPE_ACCESS);
-		if (S_ISDIR(inode->i_mode))
-			def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns,
-								     inode,
-								     ACL_TYPE_DEFAULT);
-
-		rc = ndr_encode_posix_acl(&acl_ndr, user_ns, inode,
-					  smb_acl, def_smb_acl);
-		if (rc) {
-			pr_err("failed to encode ndr to posix acl\n");
-			goto out;
-		}
+	if (rc <= 0)
+		return rc;
 
-		rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset,
-				       cmp_hash);
-		if (rc) {
-			pr_err("failed to generate hash for ndr acl\n");
-			goto out;
-		}
+	n.length = rc;
+	rc = ndr_decode_v4_ntacl(&n, &acl);
+	if (rc)
+		goto free_n_data;
 
-		if (memcmp(cmp_hash, acl.posix_acl_hash, XATTR_SD_HASH_SIZE)) {
-			pr_err("hash value diff\n");
-			rc = -EINVAL;
-			goto out;
-		}
+	smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode,
+						 ACL_TYPE_ACCESS);
+	if (S_ISDIR(inode->i_mode))
+		def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode,
+							     ACL_TYPE_DEFAULT);
+
+	rc = ndr_encode_posix_acl(&acl_ndr, user_ns, inode, smb_acl,
+				  def_smb_acl);
+	if (rc) {
+		pr_err("failed to encode ndr to posix acl\n");
+		goto out_free;
+	}
 
-		*pntsd = acl.sd_buf;
-		(*pntsd)->osidoffset =
-			cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) - NDR_NTSD_OFFSETOF);
-		(*pntsd)->gsidoffset =
-			cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) - NDR_NTSD_OFFSETOF);
-		(*pntsd)->dacloffset =
-			cpu_to_le32(le32_to_cpu((*pntsd)->dacloffset) - NDR_NTSD_OFFSETOF);
+	rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset, cmp_hash);
+	if (rc) {
+		pr_err("failed to generate hash for ndr acl\n");
+		goto out_free;
+	}
 
-		rc = acl.sd_size;
-out:
-		kfree(n.data);
-		kfree(acl_ndr.data);
-		kfree(smb_acl);
-		kfree(def_smb_acl);
+	if (memcmp(cmp_hash, acl.posix_acl_hash, XATTR_SD_HASH_SIZE)) {
+		pr_err("hash value diff\n");
+		rc = -EINVAL;
+		goto out_free;
 	}
 
+	*pntsd = acl.sd_buf;
+	(*pntsd)->osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) -
+					   NDR_NTSD_OFFSETOF);
+	(*pntsd)->gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) -
+					   NDR_NTSD_OFFSETOF);
+	(*pntsd)->dacloffset = cpu_to_le32(le32_to_cpu((*pntsd)->dacloffset) -
+					   NDR_NTSD_OFFSETOF);
+
+	rc = acl.sd_size;
+out_free:
+	kfree(acl_ndr.data);
+	kfree(smb_acl);
+	kfree(def_smb_acl);
+	if (rc < 0) {
+		kfree(acl.sd_buf);
+		*pntsd = NULL;
+	}
+
+free_n_data:
+	kfree(n.data);
 	return rc;
 }