From d0872de7351c41321c363fc6dc65a4b18a218e8c Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Fri, 22 Nov 2024 01:42:51 +0900 Subject: [PATCH] sys/linux, executor: Add KSMBD subsystem support Introduces a new pseudo-syscall `syz_ksmbd_send_req` to fuzzing of the KSMBD module. The added functionality enables sending custom SMB2/3 requests to the KSMBD server on 127.0.0.1:445. Cc: linux-cifs@vger.kernel.org Cc: notselwyn@pwning.tech Cc: Namjae Jeon Signed-off-by: Yunseong Kim --- executor/common_linux.h | 61 +++++++++++++ pkg/vminfo/linux_syscalls.go | 1 + sys/linux/ksmbd.txt | 168 +++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 sys/linux/ksmbd.txt diff --git a/executor/common_linux.h b/executor/common_linux.h index 562fe703b9b0..7471faee240b 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -5833,3 +5833,64 @@ static long syz_pidfd_open(volatile long pid, volatile long flags) } #endif + +#if SYZ_EXECUTOR || __NR_syz_ksmbd_send_req +#include +#include +#include +#include +#include + +#define KSMBD_BUF_SIZE 16000 + +static long syz_ksmbd_send_req(volatile long a0, volatile long a1, volatile long a2, volatile long a3) +{ + int sockfd; + int packet_reqlen; + int errno; + struct sockaddr_in serv_addr; + char packet_req[KSMBD_BUF_SIZE]; // max frame size + + debug("[*]{syz_ksmbd_send_req} entered ksmbd send...\n"); + + if (a0 == 0 || a1 == 0) { + debug("[!]{syz_ksmbd_send_req} param empty\n"); + return -7; + } + + sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd < 0) { + debug("[!]{syz_ksmbd_send_req} failed to create socket\n"); + return -1; + } + + memset(&serv_addr, '\0', sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + serv_addr.sin_port = htons(445); + + errno = connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); + if (errno < 0) { + debug("[!]{syz_ksmbd_send_req} failed to connect (err: %d)\n", errno); + return errno ^ 0xff80000; + } + + // prepend kcov handle to packet + packet_reqlen = a1 + 8 > KSMBD_BUF_SIZE ? KSMBD_BUF_SIZE - 8 : a1; + *(unsigned long*)packet_req = procid + 1; + memcpy(packet_req + 8, (char*)a0, packet_reqlen); + + if (write(sockfd, (char*)packet_req, packet_reqlen + 8) < 0) + return -4; + + if (read(sockfd, (char*)a2, a3) < 0) + return -5; + + if (close(sockfd) < 0) + return -6; + + debug("[+]{syz_ksmbd_send_req} successfully returned\n"); + + return 0; +} +#endif diff --git a/pkg/vminfo/linux_syscalls.go b/pkg/vminfo/linux_syscalls.go index 95e3e54eba4c..25fc2fc69012 100644 --- a/pkg/vminfo/linux_syscalls.go +++ b/pkg/vminfo/linux_syscalls.go @@ -103,6 +103,7 @@ var linuxSyscallChecks = map[string]func(*checkContext, *prog.Syscall) string{ "syz_socket_connect_nvme_tcp": linuxSyzSocketConnectNvmeTCPSupported, "syz_pidfd_open": alwaysSupported, "syz_create_resource": alwaysSupported, + "syz_ksmbd_send_req": alwaysSupported, } func linuxSyzOpenDevSupported(ctx *checkContext, call *prog.Syscall) string { diff --git a/sys/linux/ksmbd.txt b/sys/linux/ksmbd.txt new file mode 100644 index 000000000000..6cfba509110a --- /dev/null +++ b/sys/linux/ksmbd.txt @@ -0,0 +1,168 @@ +include +include +include +include +include +include +include + +sync_id { + ProcessId int32 + TreeId int32 +} [packed] + +_union_smb_req_id [ + sync_id sync_id + async_id int64 +] + +negotiate_message { + Signature array[int8, 8] +# NtLmNegotiate = 1 + MessageType int32 + NegotiateFlags int32 +# MBZ unless SMB3.02 or later + DomainName_Length len[DomainString, int16] + DomainName_MaximumLength len[DomainString, int16] + DomainName_Offset offsetof[DomainString, int32] +# RFC 1001 and ASCII + WorkstationName_Length len[Workstationname_Buffer, int16] + WorkstationName_MaximumLength len[Workstationname_Buffer, int16] + WorkstationName_Offset offsetof[Workstationname_Buffer, int32] + +# struct security_buffer for version info not present since we +# do not set the version is present flag + DomainString string + +# followed by WorkstationString + Workstationname_Buffer string +} [packed] + +_smb2_hdr_pre { + ProtocolId const[0xfe534d42, int32be] + StructureSize const[0x40, int16] + CreditCharge int16 + Status int32 +} [packed] + +_smb2_hdr_post { + CreditRequest int16 + Flags int32 + NextCommand int32 + MessageId int64 + Id _union_smb_req_id + SessionId int64 + Signature array[int8, 16] +} [packed] + +#_smb3_hdr_pre { +# ProtocolId const[0xfe534d42, int32be] +# StructureSize const[0x40, int16] +# CreditCharge int16 +# ChannelSequence int16 +# Reserved int16 +#} [packed] + +#_smb3_hdr_post { +# CreditRequest int16 +# Flags int32 +# NextCommand int32 +# MessageId int64 +# Id _union_smb_req_id +# SessionId int64 +# Signature array[int8, 16] +#} [packed] + +smb2_negotiate_req { + _hdr_pre _smb2_hdr_pre + Command const[0x0, int16] + _hdr_post _smb2_hdr_post + StructureSize const[36, int16] + DialectCount len[Dialects, int16] + SecurityMode int16 + Reserved int16 + Capabilities int32 + ClientGUID array[int8, 16] + +# In SMB3.02 and earlier next three were MBZ le64 ClientStartTime + NegotiateContextOffset int32 + NegotiateContextCount int16 + Reserved2 int16 + Dialects buffer[in] +} [packed] + +smb2_sess_setup_req { + _hdr_pre _smb2_hdr_pre + Command const[0x1, int16] + _hdr_post _smb2_hdr_post + StructureSize const[25, int16] + Flags int8 + SecurityMode int8 + Capabilities int32 + Channel int32 + SecurityBufferOffset offsetof[Buffer, int16] + SecurityBufferLength len[Buffer, int16] + PreviousSessionId int64 + +# variable length GSS security buffer + Buffer negotiate_message +} [packed] + +smb2_echo_req { + _hdr_pre _smb2_hdr_pre + Command const[0xd, int16] + _hdr_post _smb2_hdr_post + StructureSize2 const[4, int16] + Reserved int16 +} [packed] + +smbd_buffer_descriptor_v1 { + offset int64 + token int32 + length int32 +# followed by Smbd_Buffer + smb2_read_req_buffer string +} [packed] + +smb2_read_req { + _hdr_pre _smb2_hdr_pre + Command const[0x8, int16] + _hdr_post _smb2_hdr_post +# Must be 49 + StructureSize const[49, int16] +# offset from start of SMB2 header to place read + Padding int8 +# MBZ unless SMB3.02 or later + Flags int8 + Length int32 + Offset int64 + PersistentFileId int64 + VolatileFileId int64 + MinimumCount int32 +# MBZ except for SMB3 or later + Channel int32 + RemainingBytes int32 + ReadChannelInfoOffset offsetof[Buffer, int16] + ReadChannelInfoLength len[Buffer, int16] + Buffer smbd_buffer_descriptor_v1 +} [packed] + +_union_smb2_req [ + smb2_negotiate_req smb2_negotiate_req + smb2_sess_setup_req smb2_sess_setup_req + smb2_echo_req smb2_echo_req + smb2_read_req smb2_read_req +] [varlen] + +smb2_req { + req_base _union_smb2_req + req_andx1 optional[_union_smb2_req] + req_andx2 optional[_union_smb2_req] +} [packed] + +smb2_req_pdu { + _pdu_size len[req, int32be] + req smb2_req +} [packed] + +syz_ksmbd_send_req(req_packet ptr[in, smb2_req_pdu], req_len len[req_packet], res_packet buffer[out], res_len len[res_packet])