svnserve is vulnerable to a local privilege escalation vulnerability via symlink attack. Summary: ======== svnserve takes a --pid-file option which creates a file containing the process id it is running as. It does not take steps to ensure that the file it has been directed at is not a symlink. If the pid file is in a directory writeable by unprivileged users, the destination could be replaced by a symlink allowing for privilege escalation. svnserve does not create a pid file by default. Known vulnerable: ================= svnserve 1.4.0 through 1.7.12 svnserve 1.8.0 through 1.8.1 svnserve 1.8.2 (not publicly released) All versions are only vulnerable when the --pid-file=ARG option is used. Known fixed: ============ svnserve 1.7.13 svnserve 1.8.3 Workaround: do not pass the --pid-file=ARG option. Details: ======== The pid file is often used by scripts to be able to determine if a specific service is running and to determine which process to kill to stop a service. If the pid file is created in a directory writable by unprivileged directories, they could replace it with a symlink. If that is done while the service is stopped, the service may overwrite the target of the symlink with a one line containing its pid when it starts. This may lead to privilege escalation, depending on the target of the symlink. If that is done while the service is running, the stop script may kill the wrong process. In effect the unprivileged user would be able to kill a process they do not have permissions to kill when a privileged script depends on the pid file. svnserve did not properly ensure that the pid file is being created new every time and as such is vulnerable. Severity: ========= CVSSv2 Base Score: 3.2 CVSSv2 Base Vector: AV:L/AC:L/Au:S/C:N/I:P/A:P We consider this to be a medium risk vulnerability. The pid file is not created by default. Unless the pid file is created in a directory with permissions for unprivileged users the vulnerability cannot be exploited. pid files are typically placed in /var/run or a subdirectory under /var/run, which is not typically writable by unprivileged users. The attacker would need to have local access to the machine that svnserve is running on in order to exploit the vulnerability. However, if the pid file is created in a vulnerable directory, any file writable by svnserve can be truncated. This includes mutable files in the repository data directory ("filesystem directory") so may result in deleting of a portion of history. Note that the user svnserve runs as should not (under good practice) have write access to the hooks and config files (e.g., $REPOSDIR/conf/* and $REPOSDIR/hooks/*). If it does, or if svnserve runs as root, the implications of the vulnerability would be more severe. Recommendations: ================ We recommend that users of svnserve upgrade to Subversion 1.7.13 or 1.8.3. Administrators can mitigate the vulnerability without upgrading by refraining from pointing the pid file at a directory where unprivileged users have write access (e.g. /tmp). Instead the pidfile should be placed in a directory where only the daemon has access to create, modify, and delete files. Alternatively, the pid file may be disabled altogether by removing the --pid-file option from svnserve's invocation. Subversion does not release system startup scripts for svnserve, so check your local installation for details. Alternatively, apply the patch below. References: =========== CVE-2013-4277 (Subversion) Reported by: ============ Daniel Shahaf, elego Software Solutions GmbH Patches: ======== Patch for Subversion 1.7: [[[ Index: subversion/svnserve/main.c =================================================================== --- subversion/svnserve/main.c (revision 1516311) +++ subversion/svnserve/main.c (working copy) @@ -403,8 +403,9 @@ static svn_error_t *write_pid_file(const char *fil const char *contents = apr_psprintf(pool, "%" APR_PID_T_FMT "\n", getpid()); + SVN_ERR(svn_io_remove_file2(filename, TRUE, pool)); SVN_ERR(svn_io_file_open(&file, filename, - APR_WRITE | APR_CREATE | APR_TRUNCATE, + APR_WRITE | APR_CREATE | APR_EXCL, APR_OS_DEFAULT, pool)); SVN_ERR(svn_io_file_write_full(file, contents, strlen(contents), NULL, pool)); ]]] Patch for Subversion 1.8: [[[ Index: subversion/svnserve/svnserve.c =================================================================== --- subversion/svnserve/svnserve.c (revision 1516305) +++ subversion/svnserve/svnserve.c (working copy) @@ -439,8 +439,9 @@ static svn_error_t *write_pid_file(const char *fil const char *contents = apr_psprintf(pool, "%" APR_PID_T_FMT "\n", getpid()); + SVN_ERR(svn_io_remove_file2(filename, TRUE, pool)); SVN_ERR(svn_io_file_open(&file, filename, - APR_WRITE | APR_CREATE | APR_TRUNCATE, + APR_WRITE | APR_CREATE | APR_EXCL, APR_OS_DEFAULT, pool)); SVN_ERR(svn_io_file_write_full(file, contents, strlen(contents), NULL, pool)); ]]]