Skip to content

Commit a5737a7

Browse files
authored
Merge pull request #1284 from TheManticoreProject/bugfix-trans2-setfsinfo-status
Refuse TRANS2_SET_FS_INFORMATION with the mandated status (Fixes #1215)
2 parents 5bb016e + 8bd8269 commit a5737a7

4 files changed

Lines changed: 43 additions & 11 deletions

File tree

network/smb/smb_v10/server/errors.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ var dosErrors = map[nt_status.NT_STATUS]SMBStatus{
144144
nt_status.NT_STATUS_NONEXISTENT_SECTOR: {ERRHRD, 0x001B}, // ERRbadsector
145145
nt_status.NT_STATUS_WRONG_VOLUME: {ERRHRD, 0x0022}, // ERRwrongdisk
146146
nt_status.NT_STATUS_DISK_FULL: {ERRHRD, 0x0027}, // ERRdiskfull
147+
148+
// NT_STATUS_SMB_NO_SUPPORT is tabulated rather than decomposed. It is a
149+
// [MS-CIFS] composite like the others, but its ErrorCode is 0xFFFF, so its
150+
// top byte is 0xFF and the decomposition below — which requires a zero top
151+
// byte to tell a composite from a real [MS-ERREF] NTSTATUS — cannot claim
152+
// it. Without this entry it would fall through to ERRSRV/ERRsrverror.
153+
nt_status.NT_STATUS_SMB_NO_SUPPORT: {ERRSRV, 0xFFFF}, // ERRnosupport
147154
}
148155

149156
// unmappedError is the pair sent for an NTSTATUS with no tabulated SMBSTATUS

network/smb/smb_v10/server/errors_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,32 @@ func TestDOSErrorDecomposesCIFSStatus(t *testing.T) {
121121
}
122122
}
123123

124+
// TestDOSErrorTabulatesSMBNoSupport covers the one [MS-CIFS] composite that
125+
// cannot be decomposed. NT_STATUS_SMB_NO_SUPPORT is ERRSRV/ERRnosupport, but its
126+
// ErrorCode is 0xFFFF, so the value's top byte is 0xFF and the decomposition in
127+
// DOSError — which requires a zero top byte to tell a composite apart from a
128+
// real [MS-ERREF] NTSTATUS — cannot claim it. It is tabulated instead, and
129+
// without that entry a client which did not negotiate NT status codes would be
130+
// told ERRSRV/ERRsrverror for a subcommand the specification says to refuse with
131+
// ERRnosupport.
132+
func TestDOSErrorTabulatesSMBNoSupport(t *testing.T) {
133+
got, ok := DOSError(nt_status.NT_STATUS_SMB_NO_SUPPORT)
134+
if !ok {
135+
t.Fatal("DOSError(NT_STATUS_SMB_NO_SUPPORT) reported no mapping")
136+
}
137+
if want := (SMBStatus{ERRSRV, 0xFFFF}); got != want {
138+
t.Fatalf("DOSError(NT_STATUS_SMB_NO_SUPPORT) = %s/0x%04X, want %s/0x%04X",
139+
got.Class, got.Code, want.Class, want.Code)
140+
}
141+
if got == unmappedError {
142+
t.Fatal("it fell through to the generic ERRSRV/ERRsrverror")
143+
}
144+
// It is still wire-identical to the NTSTATUS, like every other composite.
145+
if encoded := got.Encode(); encoded != uint32(nt_status.NT_STATUS_SMB_NO_SUPPORT) {
146+
t.Fatalf("re-encoding gives 0x%08X, want 0x%08X", encoded, uint32(nt_status.NT_STATUS_SMB_NO_SUPPORT))
147+
}
148+
}
149+
124150
// TestDOSErrorUnmapped asserts an NTSTATUS with no legacy equivalent reports
125151
// that fact and still yields something valid to send.
126152
func TestDOSErrorUnmapped(t *testing.T) {

network/smb/smb_v10/server/handler_remaining_subcommands.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,17 @@ func handleTrans2CreateDirectory(
142142
// than left to fall through to STATUS_NOT_IMPLEMENTED because the specification
143143
// names a different status for it than for its neighbours.
144144
//
145-
// STATUS_SMB_NO_SUPPORT has no constant in windows/errors/nt_status, so the closest
146-
// available is used: NT_STATUS_NOT_SUPPORTED, which carries the same meaning and
147-
// maps to a not-supported legacy code. Nothing sends this subcommand — it is
148-
// reserved — so the difference is a conformance detail rather than a live one.
145+
// The status is NT_STATUS_SMB_NO_SUPPORT, the [MS-CIFS] extension value that is
146+
// wire-identical to the ERRSRV/ERRnosupport pair the specification names. Nothing
147+
// sends this subcommand — it is reserved — so the refusal is a conformance
148+
// detail rather than a live path.
149149
func handleTrans2SetFsInformation(
150150
conn *Connection,
151151
_ *message.Message,
152152
_ *transactionReassembly,
153153
) ([]byte, []byte, nt_status.NT_STATUS) {
154154
logger.Debugf("SMB1 server: %s sent TRANS2_SET_FS_INFORMATION, which is reserved and refused", conn.Remote)
155-
return nil, nil, nt_status.NT_STATUS_NOT_SUPPORTED
155+
return nil, nil, nt_status.NT_STATUS_SMB_NO_SUPPORT
156156
}
157157

158158
// handleNtTransactCreate answers NT_TRANSACT_CREATE, the NT_TRANSACT open.

network/smb/smb_v10/server/remaining_subcommands_test.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,12 @@ func TestReservedSubcommandsUseTheirMandatedStatus(t *testing.T) {
210210
_, client := fileServer(t, fs, false)
211211

212212
t.Run("TRANS2_SET_FS_INFORMATION", func(t *testing.T) {
213-
// STATUS_SMB_NO_SUPPORT has no constant in windows/errors/nt_status, so the
214-
// closest available is used; what matters here is that it is not the
215-
// generic STATUS_NOT_IMPLEMENTED.
213+
// [MS-CIFS] 2.2.6.5 mandates STATUS_SMB_NO_SUPPORT for this subcommand,
214+
// not the generic refusal its neighbours receive.
216215
_, _, status := sendTrans2(t, client, subcommands.TRANS2_SET_FS_INFORMATION, make([]byte, 4), nil)
217-
if status != uint32(nt_status.NT_STATUS_NOT_SUPPORTED) {
218-
t.Errorf("it reported 0x%08X, want STATUS_NOT_SUPPORTED (0x%08X)",
219-
status, uint32(nt_status.NT_STATUS_NOT_SUPPORTED))
216+
if status != uint32(nt_status.NT_STATUS_SMB_NO_SUPPORT) {
217+
t.Errorf("it reported 0x%08X, want STATUS_SMB_NO_SUPPORT (0x%08X)",
218+
status, uint32(nt_status.NT_STATUS_SMB_NO_SUPPORT))
220219
}
221220
if status == uint32(nt_status.NT_STATUS_NOT_IMPLEMENTED) {
222221
t.Error("it fell through to the table's generic refusal")

0 commit comments

Comments
 (0)