Bug 1097815 (CVE-2014-0244)

Summary: CVE-2014-0244 samba: nmbd denial of service
Product: [Other] Security Response Reporter: Daniel B <dani-rh>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED ERRATA QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: aavati, asn, gdeschner, jkurik, nlevinki, osoukup, pmatouse, rfortier, sbose, scorneli, security-response-team, ssaha, ssorce, vbellur, vkrizan
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
A denial of service flaw was found in the way the sys_recvfile() function of nmbd, the NetBIOS message block daemon, processed non-blocking sockets. An attacker could send a specially crafted packet that, when processed, would cause nmbd to enter an infinite loop and consume an excessive amount of CPU time.
Story Points: ---
Clone Of: Environment:
EL 5.10 i386 samba3x as a domain controler
Last Closed: 2014-08-12 16:49:13 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1105499, 1105500, 1105501, 1105502, 1105504, 1105505, 1112150, 1112151, 1112251    
Bug Blocks: 1098221    
Attachments:
Description Flags
Strace of nmbd when the problem is triggered none

Description Daniel B 2014-05-14 15:09:34 UTC
Created attachment 895515 [details]
Strace of nmbd when the problem is triggered

Description of problem:

I'm running samba3x (samba3x-3.6.6-0.139.el5_10) as an simple NT domain controler on a CentOS 5.10, and found sometime the nmbd process stuck (eating 100% CPU, and not responding anymore to any request, making any domain login impossible). The only solution was to kill -9 this process and restart it. It was occuring randomly, so was quite hard to troubleshoot, but after a few hours, I've finaly identified what's causing it (well at least, I know a simple request from a client is enough to trigger it)

I'll attach:

- a strace of the process at the time the problem occure. In this file the last lines (recvfrom(12, 0xbfcff9c8, 576, 0, 0xbfcffc08, 0xbfcff988) = -1 EAGAIN (Resource temporarily unavailable)) is repeated indefinitly as long as the process isn't killed, producing several GB per hour in the strace file. I've truncated it to the interesting part

- a pcap of the packet crashing nmbd (which you can replay with tcpreplay to reproduce the issue)

Version-Release number of selected component (if applicable):


How reproducible:
100% with the attached pcap


Steps to Reproduce:
1. You need a client with IP 192.168.7.50 and MAC 6c:62:6d:b0:25:42
2. The server running nmbd with IP 192.168.7.1 and MAC 52:54:00:7C:31:C4
(if you have different values you'll have to tweak the pcap with tcprewrite)
3. The netbios name of the samba server should be SAS (it's contained in the pcap and needs to match the netbios name of the server in order to trigger the issue)
4. Run nmbd (I'm running it with daemontools with /usr/sbin/nmbd -F -S but that probably doesn't matter)
5. Replay the attached pcap with tcpreplay -i eth0 nmbd_dos.pcap

Actual results:
nmbd will go in a loop, taking 100% of a core, and won't respond to any further requests, making impossible to login on the domain

Expected results:
nmbd should continue working as normal

Additional info:

Marking this a security issue as it makes it very easy to DOS a domain controler

Comment 2 Stefan Cornelius 2014-05-23 11:49:42 UTC
Thanks for the detailed report and the reproducer, that helped a lot.

I managed to reproduce the issue. When nmbd hangs, it has the following backtrace:

#0  0x00002ba5fb059d53 in __recvfrom_nocancel () from /lib64/libc.so.6
#1  0x00002ba5f85e506d in recvfrom (s=12, buf=0x7fff3cbe5940, len=576, flags=0, from=0x7fff3cbe5b80, fromlen=0x7fff3cbe5914)
    at /usr/include/bits/socket2.h:55
#2  sys_recvfrom (s=12, buf=0x7fff3cbe5940, len=576, flags=0, from=0x7fff3cbe5b80, fromlen=0x7fff3cbe5914) at lib/system.c:288
#3  0x00002ba5f85f6a73 in read_udp_v4_socket (fd=12, buf=0x7fff3cbe5940 "PW\276<\377\177", len=576, psa=0x7fff3cbe5b80) at lib/util_sock.c:259
#4  0x00002ba5f853ddb8 in read_packet (fd=12, packet_type=DGRAM_PACKET) at libsmb/nmblib.c:802
#5  0x00002ba5f84c7601 in listen_for_packets (run_election=<value optimized out>) at nmbd/nmbd_packets.c:1971
#6  0x00002ba5f84bae0b in process (argc=<value optimized out>, argv=<value optimized out>) at nmbd/nmbd.c:493
#7  main (argc=<value optimized out>, argv=<value optimized out>) at nmbd/nmbd.c:1020


read_udp_v4_socket has the following code:
ret = (ssize_t)sys_recvfrom(fd,buf,len,0,
		(struct sockaddr *)psa,&socklen);
if (ret <= 0) {
	/* Don't print a low debug error for a non-blocking socket. */
	if (errno == EAGAIN) {
		DEBUG(10,("read_udp_v4_socket: returned EAGAIN\n"));
	} else {
		DEBUG(2,("read_udp_v4_socket: failed. errno=%s\n",
			strerror(errno)));
	}
	return 0;
}

So, we can see it calls sys_recvfrom() and wants to bail out if it encounters EAGAIN return values.

Now, the interesting part is how sys_recvfrom() is implemented:
ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
{
	ssize_t ret;

	do {
		ret = recvfrom(s, buf, len, flags, from, fromlen);
#if defined(EWOULDBLOCK)
	} while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
#else
	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
#endif
	return ret;
}

We see that it simply loops the recvfrom() and continues doing so if it encounters -1 or EAGAIN, so there's a chance that we end up looping endlessly. Also, it will never propagate -1/EAGAIN errors up to read_udp_v4_socket, so the check in read_udp_v4_socket is essentially useless at this point.

Comment 19 Stefan Cornelius 2014-06-23 12:23:06 UTC
Public now.

External Reference:

http://www.samba.org/samba/security/CVE-2014-0244

Comment 20 Stefan Cornelius 2014-06-23 12:26:05 UTC
Created samba tracking bugs for this issue:

Affects: fedora-all [bug 1112251]

Comment 21 Vincent Danen 2014-07-04 00:36:00 UTC
The upstream patch is here:

http://git.samba.org/?p=samba.git;a=commitdiff;h=d77a74237e660dd2ce9f1e14b02635f8a2569653

Comment 22 Martin Prpič 2014-07-08 12:52:28 UTC
IssueDescription:

A denial of service flaw was found in the way the sys_recvfile() function of nmbd, the NetBIOS message block daemon, processed non-blocking sockets. An attacker could send a specially crafted packet that, when processed, would cause nmbd to enter an infinite loop and consume an excessive amount of CPU time.

Comment 23 errata-xmlrpc 2014-07-09 16:18:36 UTC
This issue has been addressed in following products:

  Red Hat Enterprise Linux 7

Via RHSA-2014:0867 https://rhn.redhat.com/errata/RHSA-2014-0867.html

Comment 24 errata-xmlrpc 2014-07-09 16:29:28 UTC
This issue has been addressed in following products:

  Red Hat Enterprise Linux 6
  Red Hat Enterprise Linux 5

Via RHSA-2014:0866 https://rhn.redhat.com/errata/RHSA-2014-0866.html

Comment 26 Stefan Cornelius 2014-08-12 16:49:13 UTC
This issue has been addressed in following products:

  Red Hat Enterprise Linux 6

Via RHSA-2014:1009 https://rhn.redhat.com/errata/RHSA-2014-1009.html