Talos Vulnerability Report

TALOS-2021-1263

Apple macOS SMB server lock request infinite loop

June 2, 2021
CVE Number

CVE-2021-30716

Summary

A resource exhaustion vulnerability exists in the SMB Server on Apple macOS 11.2. A specially crafted SMB packet can trigger an infinite loop which leads to maximum CPU utilization and denial of service. This vulnerability can be triggered by sending a malicious packet to the vulnerable server.

Tested Versions

Apple macOS 11.2

Product URLs

https://apple.com

CVSSv3 Score

6.5 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

CWE

CWE-835 - Loop with Unreachable Exit Condition (‘Infinite Loop’)

Details

macOS is a series of proprietary operating systems developed by Apple with macOS 11.2, with Big Sur being the latest.

Server Message Block (SMB) is a network file sharing protocol widely used in Windows network environments and macOS contains a proprietary implementation of both server and client components. SMB is often used in office and enterprise environments for file and printer sharing.

Three distinct versions and multiple dialects of SMB protocol are supported by macOS’ SMB server. This vulnerability is present in SMB2 and newer versions of the protocol, more specifically in the LOCK request processing.

Lock requests are meant to be used to prevent changes to file contents pending other operations. As specified by SMB protocol , lock request structure contains a file ID which points to a file to be locked, as well as one or more LOCK_ELEMENT structures which contain file offset at which a lock should be made, lock size and flags. File locking is handled by smb2_dispatch_lock function which extracts the packet contents, partially validates the locks and proceeds to call ntvfs::lock_range function in a loop to lock all file ranges specified by LOCK_ELEMENT entries in the packet. There exists a bug in the way error conditions are handled. Namely , when two LOCK_ELEMENT structures in a single lock request have an overlapping range , a second lock call can fail , depending on the flags. When lock_range fails, an error code is returned and looping over LOCK_ELEMENT structures is halted. Following code is being executed:

100029665                  rax_9 = ntvfs::lock_range(r12_1, &var_38, &var_70)                         [1]
10002966d                  if (rax_9 u>= 0x40000000)
100029681                      if ((platform::log::global_level() & 0x1f) == 0x1f)
1000296ac                          int64_t* rax_13 = platform::log::logger_for_level(0x1f)
1000296c0                          (*(*rax_13 + 0x10))(rax_13, 0x1f, "/AppleInternal/BuildRoot/Library…", 0x56, "smb2_dispatch_lock", "%s: lock_range error, lock_fid: …", "smb2_dispatch_lock", var_70, zmm0.q, zmm0:8.q, rax_9) [2]
100029688                      if ((rbx_1 & 4) == 0)
100029688                          break                                                                                               [3]
10002968e                  i = i + 1
100029698                  r13_1 = r13_1 + 0x18
100029698              while (i u< zx.q(smb_lock_request.lock_count))                                 [4]
100029709              if (not(rax_9 u>= 0x40000000 && (rbx_1 & 4) == 0))
100029709                  goto label_100029709
10002980b              if (i.d == 0)
100029836                  rax_5 = smb2_schedule_error(arg1, rax_9)
100029818              else
100029818                  while (true)                                                                                          [5]
100029818                      int32_t var_68_2 = 2
100029828                      ntvfs::lock_range(r12_1, &var_38, &var_70)
10002980b              goto label_1000297da

In the above code, when a call to lock_range at [1] fails, a debug message stating the reason is printed at [2] and break from the loop at [4] is made at [3]. Then, after a few condition checks execution ends up at [5] which causes ntvfs::lock_range to be called in a loop without any possible exit condition. This constitutes an infinite loop which will keep the client handling thread busy forever. The thread isn’t affected by timeouts and will use all available CPU resources. If a second lock request with the same contents is made , another client handling thread will follow the same path and end up in an infinite loop, too. Depending on number of cores available to the SMB server, additional client handling threads can be allocated, but no matter how many are available, they can be exhausted by running the supplied proof of concept code multiple times. Once all available threads end up stuck in infinite loops, the SMB server becomes unavailable which constitutes a denial of service state. Moreover, the whole operating system is affected as SMB threads use up all available CPU.

Timeline

2021-03-04 - Vendor Disclosure
2021-05-25 - Vendor Patched

2021-06-02 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.