Subversion HTTP servers 1.6.0 to 1.7.8 (inclusive) are vulnerable to a remotely triggerable segfault DoS vulnerability. Summary: ======== Subversion's mod_dav_svn Apache HTTPD server module will crash in some circumstances when a LOCK request is made against a non-existent URL. This can lead to a DoS. There are no known instances of this problem being observed in the wild. Known vulnerable: ================= Subversion HTTPD servers 1.6.0 through 1.6.20 (inclusive) Subversion HTTPD servers 1.7.0 through 1.7.8 (inclusive) Known fixed: ============ Subversion 1.6.21 Subversion 1.7.9 svnserve (any version) is not vulnerable Details: ======== The vulnerability can be triggered by doing a LOCK request against a URL for a path that does not exist in the repository or an invalid activity URL where authentication is not required for the LOCK method. For example if the repository does not contain a file named foo: curl -X LOCK --data-binary @lock_body 'http://127.0.0.1:8080/repo/foo' Where a file exists named lock_body and has the following contents: http://example.com/ Such a request would normally be rejected since anonymous locks are not supported and in most cases locks against non-existant paths are not supported. However, when auto-versioning is enabled and the client is a non-SVN DAV client, we support locking non-existant files. The code to handle this neglected to check that the username was set before trying to copy it into the revision properties hash. This results in a segfault (NULL dereference) and thus a crash of the httpd child process. Severity: ========= CVSSv2 Base Score: 2.6 CVSSv2 Base Vector: AV:N/AC:H/Au:N/C:N/I:N/A:P We consider this to be a low risk vulnerability. In most configurations authentication will be required for the LOCK method which would prevent this attack entirely. However, sites that are not using locks and that allow anonymous write access may have this configuration. A remote attacker may be able to crash a Subversion server. Many Apache servers will respawn the listener processes, but a determined attacker will be able to crash these processes as they appear, denying service to legitimate users. Servers using threaded MPMs will close the connection on other clients being served by the same process that services the LOCK request from the attacker. Recommendations: ================ We recommend all users to upgrade to Subversion 1.7.9. Users of Subversion 1.6.x or 1.7.x who are unable to upgrade may apply the included patch. New Subversion packages can be found at: http://subversion.apache.org/packages.html Administrators that wish to protect against this without patching should ensure that LOCK requests require authentication against their repositories. Typical configurations either have a 'Require' statement forcing all requests against the repository to be authenticated or use a 'LimitExcept' block to only allow read-only methods without authentication. See this section of the Subversion book for more details: http://svnbook.red-bean.com/en/1.7/svn.serverconfig.httpd.html#svn.serverconfig.httpd.authz.blanket References: =========== CVE-2013-1847 (Subversion) Reported by: ============ Philip Martin & Ben Reser, WANdisco Patches: ======== These patches also fix the flaw in CVE-2013-1846. Patch against 1.7.8: [[[ Index: subversion/mod_dav_svn/lock.c =================================================================== --- subversion/mod_dav_svn/lock.c (revision 1458455) +++ subversion/mod_dav_svn/lock.c (working copy) @@ -640,7 +640,20 @@ append_locks(dav_lockdb *lockdb, svn_lock_t *slock; svn_error_t *serr; dav_error *derr; + dav_svn_repos *repos = resource->info->repos; + + /* We don't allow anonymous locks */ + if (! repos->username) + return dav_svn__new_error(resource->pool, HTTP_UNAUTHORIZED, + DAV_ERR_LOCK_SAVE_LOCK, + "Anonymous lock creation is not allowed."); + /* Not a path in the repository so can't lock it. */ + if (! resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, + DAV_ERR_LOCK_SAVE_LOCK, + "Attempted to lock path not in repository."); + /* If the resource's fs path is unreadable, we don't allow a lock to be created on it. */ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, @@ -663,7 +676,6 @@ append_locks(dav_lockdb *lockdb, svn_fs_txn_t *txn; svn_fs_root_t *txn_root; const char *conflict_msg; - dav_svn_repos *repos = resource->info->repos; apr_hash_t *revprop_table = apr_hash_make(resource->pool); apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING, svn_string_create(repos->username, @@ -741,7 +753,7 @@ append_locks(dav_lockdb *lockdb, /* Convert the dav_lock into an svn_lock_t. */ derr = dav_lock_to_svn_lock(&slock, lock, resource->info->repos_path, - info, resource->info->repos->is_svn_client, + info, repos->is_svn_client, resource->pool); if (derr) return derr; @@ -748,7 +760,7 @@ append_locks(dav_lockdb *lockdb, /* Now use the svn_lock_t to actually perform the lock. */ serr = svn_repos_fs_lock(&slock, - resource->info->repos->repos, + repos->repos, slock->path, slock->token, slock->comment, ]]] Patch against 1.6.20: [[[ Index: subversion/mod_dav_svn/lock.c =================================================================== --- subversion/mod_dav_svn/lock.c (revision 1459696) +++ subversion/mod_dav_svn/lock.c (working copy) @@ -634,7 +634,20 @@ append_locks(dav_lockdb *lockdb, svn_lock_t *slock; svn_error_t *serr; dav_error *derr; + dav_svn_repos *repos = resource->info->repos; + + /* We don't allow anonymous locks */ + if (! repos->username) + return dav_new_error(resource->pool, HTTP_UNAUTHORIZED, + DAV_ERR_LOCK_SAVE_LOCK, + "Anonymous lock creation is not allowed."); + /* Not a path in the repository so can't lock it. */ + if (! resource->info->repos_path) + return dav_new_error(resource->pool, HTTP_BAD_REQUEST, + DAV_ERR_LOCK_SAVE_LOCK, + "Attempted to lock path not in repository."); + /* If the resource's fs path is unreadable, we don't allow a lock to be created on it. */ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, @@ -657,7 +670,6 @@ append_locks(dav_lockdb *lockdb, svn_fs_txn_t *txn; svn_fs_root_t *txn_root; const char *conflict_msg; - dav_svn_repos *repos = resource->info->repos; apr_hash_t *revprop_table = apr_hash_make(resource->pool); apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING, svn_string_create(repos->username, @@ -734,7 +746,7 @@ append_locks(dav_lockdb *lockdb, /* Convert the dav_lock into an svn_lock_t. */ derr = dav_lock_to_svn_lock(&slock, lock, resource->info->repos_path, - info, resource->info->repos->is_svn_client, + info, repos->is_svn_client, resource->pool); if (derr) return derr; @@ -741,7 +753,7 @@ append_locks(dav_lockdb *lockdb, /* Now use the svn_lock_t to actually perform the lock. */ serr = svn_repos_fs_lock(&slock, - resource->info->repos->repos, + repos->repos, slock->path, slock->token, slock->comment, ]]]