Commit message: security fix: imudp emitted a message when a non-permitted sender...

...tried to send a message to it. This behaviour is operator-configurable.
If enabled, a message was emitted each time. That way an attacker could
effectively fill the disk via this facility. The message is now
emitted only once in a minute (this currently is a hard-coded limit,
if someone comes up with a good reason to make it configurable, we
will probably do that).
CVE: CVE-2008-5618
CWE: NVD-CWE-Other
Vulnerability description: imudp in rsyslog 4.x before 4.1.2, 3.21 before 3.21.9 beta, and 3.20 before 3.20.2 generates a message even when it is sent by an unauthorized sender, which allows remote attackers to cause a denial of service (disk consumption) via a large number of spurious messages.

Project: rsyslog
File: imudp.c

	if((pRcvBuf = malloc(MAXLINE * sizeof(char))) == NULL) {
		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
	}

Project: rsyslog
File: imudp.c

	if(udpLstnSocks != NULL) {
		net.closeUDPListenSockets(udpLstnSocks);
		udpLstnSocks = NULL;
	}

Project: rsyslog
File: imudp.c

	if(pRcvBuf != NULL) {
		free(pRcvBuf);
		pRcvBuf = NULL;
	}

Project: rsyslog
File: imudp.c

static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal)
{
	DEFiRet;
	uchar *bindAddr;
	int *newSocks;
	int *tmpSocks;
	int iSrc, iDst;

	/* check which address to bind to. We could do this more compact, but have not
	 * done so in order to make the code more readable. -- rgerhards, 2007-12-27
	 */
	if(pszBindAddr == NULL)
		bindAddr = NULL;
	else if(pszBindAddr[0] == '*' && pszBindAddr[1] == '\0')
		bindAddr = NULL;
	else
		bindAddr = pszBindAddr;

	dbgprintf("Trying to open syslog UDP ports at %s:%s.\n",
		  (bindAddr == NULL) ? (uchar*)"*" : bindAddr, pNewVal);

	newSocks = net.create_udp_socket(bindAddr, (pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal, 1);
	if(newSocks != NULL) {
		/* we now need to add the new sockets to the existing set */
		if(udpLstnSocks == NULL) {
			/* esay, we can just replace it */
			udpLstnSocks = newSocks;
		} else {
			/* we need to add them */
			if((tmpSocks = malloc(sizeof(int) * 1 + newSocks[0] + udpLstnSocks[0])) == NULL) {
				dbgprintf("out of memory trying to allocate udp listen socket array\n");
				/* in this case, we discard the new sockets but continue with what we
				 * already have
				 */
				free(newSocks);
				ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
			} else {
				/* ready to copy */
				iDst = 1;
				for(iSrc = 1 ; iSrc <= udpLstnSocks[0] ; ++iSrc)
					tmpSocks[iDst++] = udpLstnSocks[iSrc];
				for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc)
					tmpSocks[iDst++] = newSocks[iSrc];
				tmpSocks[0] = udpLstnSocks[0] + newSocks[0];
				free(newSocks);
				free(udpLstnSocks);
				udpLstnSocks = tmpSocks;
			}
		}
	}

finalize_it:
	free(pNewVal); /* in any case, this is no longer needed */

	RETiRet;
}

Project: rsyslog
File: imudp.c

static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
	if(pszBindAddr != NULL) {
		free(pszBindAddr);
		pszBindAddr = NULL;
	}
	if(udpLstnSocks != NULL) {
		net.closeUDPListenSockets(udpLstnSocks);
		udpLstnSocks = NULL;
	}
	return RS_RET_OK;
}

Project: rsyslog
File: imudp.c

	while(1) {
		/* Add the Unix Domain Sockets to the list of read
		 * descriptors.
		 * rgerhards 2005-08-01: we must now check if there are
		 * any local sockets to listen to at all. If the -o option
		 * is given without -a, we do not need to listen at all..
		 */
	        maxfds = 0;
	        FD_ZERO (&readfds);

		/* Add the UDP listen sockets to the list of read descriptors.
		 */
		if(udpLstnSocks != NULL) {
                        for (i = 0; i < *udpLstnSocks; i++) {
                                if (udpLstnSocks[i+1] != -1) {
					if(Debug)
						net.debugListenInfo(udpLstnSocks[i+1], "UDP");
                                        FD_SET(udpLstnSocks[i+1], &readfds);
					if(udpLstnSocks[i+1]>maxfds) maxfds=udpLstnSocks[i+1];
				}
                        }
		}
		if(Debug) {
			dbgprintf("--------imUDP calling select, active file descriptors (max %d): ", maxfds);
			for (nfds = 0; nfds <= maxfds; ++nfds)
				if ( FD_ISSET(nfds, &readfds) )
					dbgprintf("%d ", nfds);
			dbgprintf("\n");
		}

		/* wait for io to become ready */
		nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL);

		if(udpLstnSocks != NULL) {
		       for (i = 0; nfds && i < *udpLstnSocks; i++) {
			       if (FD_ISSET(udpLstnSocks[i+1], &readfds)) {
				       socklen = sizeof(frominet);
				       l = recvfrom(udpLstnSocks[i+1], (char*) pRcvBuf, MAXLINE - 1, 0,
						    (struct sockaddr *)&frominet, &socklen);
				       if (l > 0) {
					       if(net.cvthname(&frominet, fromHost, fromHostFQDN, fromHostIP) == RS_RET_OK) {
						       dbgprintf("Message from inetd socket: #%d, host: %s\n",
							       udpLstnSocks[i+1], fromHost);
						       /* Here we check if a host is permitted to send us
							* syslog messages. If it isn't, we do not further
							* process the message but log a warning (if we are
							* configured to do this).
							* rgerhards, 2005-09-26
							*/
						       if(net.isAllowedSender((uchar*) "UDP",
							  (struct sockaddr *)&frominet, (char*)fromHostFQDN)) {
							       parseAndSubmitMessage(fromHost, fromHostIP, pRcvBuf, l,
							       MSG_PARSE_HOSTNAME, NOFLAG, eFLOWCTL_NO_DELAY);
						       } else {
							       dbgprintf("%s is not an allowed sender\n", (char*)fromHostFQDN);
							       if(glbl.GetOption_DisallowWarning) {
							       		time_t tt;

									time(&tt);
									if(tt > ttLastDiscard + 60) {
										ttLastDiscard = tt;
										errmsg.LogError(0, NO_ERRCODE,
										"UDP message from disallowed sender %s discarded",
										(char*)fromHost);
									}
							       }	
						       }
					       }
				       } else if (l < 0 && errno != EINTR && errno != EAGAIN) {
						char errStr[1024];
						rs_strerror_r(errno, errStr, sizeof(errStr));
						dbgprintf("INET socket error: %d = %s.\n", errno, errStr);
						       errmsg.LogError(errno, NO_ERRCODE, "recvfrom inet");
						       /* should be harmless */
						       sleep(1);
					       }
					--nfds; /* indicate we have processed one */
				}
		       }
		}
	}