[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[CVE-2018-11782, CVE-2019-0203] Apache Subversion svnserve vulnerabilities

From: Julian Foad <julianfoad_at_apache.org>
Date: Wed, 31 Jul 2019 17:19:58 +0100

The recent releases of Apache Subversion 1.12.2, 1.10.6, 1.9.12, contain fixes for two security issues, CVE-2018-11782 and CVE-2019-0203. These issues affect Subversion 'svnserve' servers. We encourage server operators to upgrade to the latest appropriate version as soon as reasonable. Please see the [release announcements] for more information about the releases.

To get the latest release from the nearest mirror, please visit our [download page].

[CVE-2018-11782]
http://subversion.apache.org/security/CVE-2018-11782-advisory.txt

[CVE-2019-0203]
http://subversion.apache.org/security/CVE-2019-0203-advisory.txt

[release announcements]
https://lists.apache.org/list.html?announce@subversion.apache.org

[download page]
http://subversion.apache.org/download.cgi#recommended-release

Below are the advisories, with patches to fix the problems. The patches
apply to Subversion 1.12.0, 1.10.4, 1.9.10. Subversion 1.12.2, 1.10.6,
1.9.12 will include the patches below, as well as other stability and bug
fixes. You can get an advance copy of the source distribution here:

  https://dist.apache.org/repos/dist/release/subversion/?p=34990

Here are the full advisories:

Advisory for CVE-2019-0203:
{{{
  Remote unauthenticated denial-of-service in Subversion svnserve.

Summary:
========

  Subversion's svnserve server process may exit when a client sends certain
  sequences of protocol commands.

  This can lead to disruption for users of the server.

Known vulnerable:
=================

  Subversion svnserve servers through 1.9.10 (inclusive).
  Subversion svnserve servers 1.10.0 through 1.10.4 (inclusive).
  Subversion svnserve servers 1.11.0 through 1.11.1 (inclusive).
  Subversion svnserve servers 1.12.0 through 1.12.0 (inclusive).

  mod_dav_svn (any version) is not affected.

Known fixed:
============

  Subversion svnserve servers 1.9.11
  Subversion svnserve servers 1.10.5
  Subversion svnserve servers 1.12.1

  (Subversion 1.11.x is not a supported release line.)

Details:
========

  A null-pointer-dereference has been found in svnserve that results in a
  remote unauthenticated Denial-of-Service in some server configurations.

  The vulnerability can be triggered by an unauthenticated user if the
  server is configured with anonymous access enabled.

  The problem originates in opening a new connection to svnserve. On failure
  to find the specified repository or to be authorized to access it,
  svnserve logs and reports the error, but also keeps the connection open
  despite its incomplete initialization. If the client sends any further
  command on the same connection, then a null-pointer-dereference occurs in
  svnserve.

Severity:
=========

  CVSSv3 Base Score: 7.5 (High)
  CVSSv3 Base Vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

  Exploitation results in denial of service by crashing an svnserve
  process. The impact of this differs depending on how svnserve is
  launched, including the different run modes selected by options such
  as "svnserve -d", "svnserve -T -d", "svnserve -t", and "svnserve -i".

Recommendations:
================

  We recommend all users to upgrade to a known fixed release of the
  Subversion svnserve server.

  Users who are unable to upgrade may apply the included patches.

References:
===========

  CVE-2019-0203 (Subversion)

Reported by:
============

  Tomas Bortoli <tomasbortoli_at_gmail.com>

Patches:
========

  Patch for Subversion 1.12, 1.10, 1.9:
[[[
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c
+++ subversion/svnserve/serve.c
@@ -4125,7 +4125,7 @@ construct_server_baton
                        serve_params_t *params,
                        apr_pool_t *scratch_pool)
 {
- svn_error_t *err, *io_err;
+ svn_error_t *err;
   apr_uint64_t ver;
   const char *client_url, *ra_client_string, *client_string;
   svn_ra_svn__list_t *caplist;
@@ -4267,11 +4267,12 @@
     }
   if (err)
     {
- log_error(err, b);
- io_err = svn_ra_svn__write_cmd_failure(conn, scratch_pool, err);
- svn_error_clear(err);
- SVN_ERR(io_err);
- return svn_ra_svn__flush(conn, scratch_pool);
+ /* Report these errors to the client before closing the connection. */
+ err = svn_error_compose_create(err,
+ svn_ra_svn__write_cmd_failure(conn, scratch_pool, err));
+ err = svn_error_compose_create(err,
+ svn_ra_svn__flush(conn, scratch_pool));
+ return err;
     }

   SVN_ERR(svn_fs_get_uuid(b->repository->fs, &b->repository->uuid,

]]]

}}}

Advisory for CVE-2018-11782:
{{{
  Remotely triggerable DoS vulnerability in svnserve 'get-deleted-rev'.

Summary:
========

  Subversion's svnserve server process may exit when a well-formed
  read-only request produces a particular answer.

  This can lead to disruption for users of the server.

Known vulnerable:
=================

  Subversion svnserve servers through 1.9.10 (inclusive).
  Subversion svnserve servers 1.10.0 through 1.10.4 (inclusive).
  Subversion svnserve servers 1.11.0 through 1.11.1 (inclusive).
  Subversion svnserve servers 1.12.0 through 1.12.0 (inclusive).

  mod_dav_svn (any version) is not affected.

Known fixed:
============

  Subversion svnserve servers 1.9.11
  Subversion svnserve servers 1.10.5
  Subversion svnserve servers 1.12.1

  (Subversion 1.11.x is not a supported release line.)

Details:
========

  Subversion svn:// connections, including svn+ssh:// and svn+<custom>://, use
  a custom network protocol [1] with Lisp-like syntax. The code implementing
  the protocol has dedicated codepaths for serialization of revision numbers
  into protocol integers. A particular client query could cause the server to
  attempt to reply with a revision number whose value is the invalid revision
  number constant `SVN_INVALID_REVNUM`, thereby triggering an assertion failure
  in the the serialization layer.

  [1] https://svn.apache.org/repos/asf/subversion/tags/1.10.0/subversion/libsvn_ra_svn/protocol

Severity:
=========

  CVSSv3 Base Score: 6.5 (Medium)
  CVSSv3 Base Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

  Exploitation results in denial of service by crashing an svnserve
  process. The impact of this differs depending on how svnserve is
  launched, including the different run modes selected by options such
  as "svnserve -d", "svnserve -T -d", "svnserve -t", and "svnserve -i".

Recommendations:
================

  We recommend all users to upgrade to a known fixed release of the
  Subversion svnserve server.

  The same releases also include changes in the client side. These
  client-side changes are not needed to fix the server vulnerability.
  Upgrading the clients to one of these releases provides an ordinary bug
  fix that make the case in question work correctly when operating against
  an upgraded server.

  - With a new client against a new server, such queries are now handled
    correctly.

  - With an old client against a new server, the client will report a more
    informative error message, and the server will not crash.

  - With a new client against an old server, the behaviour is the same as
    with an old client against an old server.

  Users who are unable to upgrade may apply the included patches.

References:
===========

  CVE-2018-11782 (Subversion)

Reported by:
============

  Ace Olszowka, Build Master, Computers Unlimited

Patches:
========

  Patch against Subversion 1.12.0, 1.10.4:
[[[
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c
+++ subversion/libsvn_ra_svn/client.c
@@ -3102,25 +3102,38 @@ ra_svn_get_deleted_rev(svn_ra_session_t
                        svn_revnum_t *revision_deleted,
                        apr_pool_t *pool)
 
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
+ svn_error_t *err;
 
   path = reparent_path(session, path, pool);
 
   /* Transmit the parameters. */
   SVN_ERR(svn_ra_svn__write_cmd_get_deleted_rev(conn, pool, path,
                                                peg_revision, end_revision));
 
   /* Servers before 1.6 don't support this command. Check for this here. */
   SVN_ERR(handle_unsupported_cmd(handle_auth_request(sess_baton, pool),
                                  N_("'get-deleted-rev' not implemented")));
 
- return svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, "r",
- revision_deleted));
+ err = svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, "r",
+ revision_deleted));
+ /* The protocol does not allow for a reply of SVN_INVALID_REVNUM directly.
+ Instead, a new enough server returns SVN_ERR_ENTRY_MISSING_REVISION to
+ indicate the answer to the query is SVN_INVALID_REVNUM. (An older server
+ closes the connection and returns SVN_ERR_RA_SVN_CONNECTION_CLOSED.) */
+ if (err && err->apr_err == SVN_ERR_ENTRY_MISSING_REVISION)
+ {
+ *revision_deleted = SVN_INVALID_REVNUM;
+ svn_error_clear(err);
+ }
+ else
+ SVN_ERR(err);
+ return SVN_NO_ERROR;
 }
 
 static svn_error_t *
 ra_svn_register_editor_shim_callbacks(svn_ra_session_t *session,
                                       svn_delta_shim_callbacks_t *callbacks)
 {
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c
+++ subversion/svnserve/serve.c
@@ -3513,14 +3513,27 @@ get_deleted_rev(svn_ra_svn_conn_t *conn,
   SVN_ERR(svn_ra_svn__parse_tuple(params, "crr",
                                  &path, &peg_revision, &end_revision));
   full_path = svn_fspath__join(b->repository->fs_path->data,
                                svn_relpath_canonicalize(path, pool), pool);
   SVN_ERR(log_command(b, conn, pool, "get-deleted-rev"));
   SVN_ERR(trivial_auth_request(conn, pool, b));
- SVN_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision,
- end_revision, &revision_deleted, pool));
+ SVN_CMD_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision,
+ end_revision, &revision_deleted, pool));
+
+ /* The protocol does not allow for a reply of SVN_INVALID_REVNUM directly.
+ Instead, return SVN_ERR_ENTRY_MISSING_REVISION. A new enough client
+ knows that this means the answer to the query is SVN_INVALID_REVNUM.
+ (An older client reports this as an error.) */
+ if (revision_deleted == SVN_INVALID_REVNUM)
+ SVN_CMD_ERR(svn_error_createf(SVN_ERR_ENTRY_MISSING_REVISION, NULL,
+ "svn protocol command 'get-deleted-rev': "
+ "path '%s' was not deleted in r%ld-%ld; "
+ "NOTE: newer clients handle this case "
+ "and do not report it as an error",
+ full_path, peg_revision, end_revision));
+
   SVN_ERR(svn_ra_svn__write_cmd_response(conn, pool, "r", revision_deleted));
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
 get_inherited_props(svn_ra_svn_conn_t *conn,
Index: subversion/tests/libsvn_ra/ra-test.c
===================================================================
--- subversion/tests/libsvn_ra/ra-test.c
+++ subversion/tests/libsvn_ra/ra-test.c
@@ -91,12 +91,47 @@ commit_changes(svn_ra_session_t *session
   SVN_ERR(editor->close_directory(dir_baton, pool));
   SVN_ERR(editor->close_directory(root_baton, pool));
   SVN_ERR(editor->close_edit(edit_baton, pool));
   return SVN_NO_ERROR;
 }
 
+/* Commit two revisions: add 'B', then delete 'A' */
+static svn_error_t *
+commit_two_changes(svn_ra_session_t *session,
+ apr_pool_t *pool)
+{
+ apr_hash_t *revprop_table = apr_hash_make(pool);
+ const svn_delta_editor_t *editor;
+ void *edit_baton;
+ void *root_baton, *dir_baton;
+
+ /* mkdir B */
+ SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+ revprop_table,
+ NULL, NULL, NULL, TRUE, pool));
+ SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
+ pool, &root_baton));
+ SVN_ERR(editor->add_directory("B", root_baton, NULL, SVN_INVALID_REVNUM,
+ pool, &dir_baton));
+ SVN_ERR(editor->close_directory(dir_baton, pool));
+ SVN_ERR(editor->close_directory(root_baton, pool));
+ SVN_ERR(editor->close_edit(edit_baton, pool));
+
+ /* delete A */
+ SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+ revprop_table,
+ NULL, NULL, NULL, TRUE, pool));
+ SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
+ pool, &root_baton));
+ SVN_ERR(editor->delete_entry("A", SVN_INVALID_REVNUM, root_baton, pool));
+ SVN_ERR(editor->close_directory(root_baton, pool));
+ SVN_ERR(editor->close_edit(edit_baton, pool));
+
+ return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 commit_tree(svn_ra_session_t *session,
             apr_pool_t *pool)
 {
   apr_hash_t *revprop_table = apr_hash_make(pool);
   const svn_delta_editor_t *editor;
@@ -1781,12 +1816,62 @@ commit_locked_file(const svn_test_opts_t
   SVN_TEST_ASSERT(propval);
   SVN_TEST_STRING_ASSERT(propval->data, "propval");
 
   return SVN_NO_ERROR;
 }
 
+/* Cases of 'get-deleted-rev' that should return SVN_INVALID_REVNUM. */
+static svn_error_t *
+test_get_deleted_rev_no_delete(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_ra_session_t *ra_session;
+ svn_revnum_t revision_deleted;
+
+ SVN_ERR(make_and_open_repos(&ra_session,
+ "test-repo-get-deleted-rev-no-delete", opts,
+ pool));
+ SVN_ERR(commit_changes(ra_session, pool));
+ SVN_ERR(commit_two_changes(ra_session, pool));
+
+ /* expect 'no deletion' in the range up to r2, when it is deleted in r3 */
+ /* This was failing over RA-SVN where the 'get-deleted-rev' wire command's
+ prototype cannot directly represent that result. A new enough client and
+ server collaborate on a work-around implemented using an error code. */
+ SVN_ERR(svn_ra_get_deleted_rev(ra_session, "A", 1, 2,
+ &revision_deleted, pool));
+ SVN_TEST_INT_ASSERT(revision_deleted, SVN_INVALID_REVNUM);
+
+ /* this connection should still be open: a simple case should still work */
+ SVN_ERR(svn_ra_get_deleted_rev(ra_session, "A", 1, 3,
+ &revision_deleted, pool));
+ SVN_TEST_INT_ASSERT(revision_deleted, 3);
+
+ return SVN_NO_ERROR;
+}
+
+/* Cases of 'get-deleted-rev' that should return an error. */
+static svn_error_t *
+test_get_deleted_rev_errors(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_ra_session_t *ra_session;
+ svn_revnum_t revision_deleted;
+
+ SVN_ERR(make_and_open_repos(&ra_session,
+ "test-repo-get-deleted-rev-errors", opts, pool));
+ SVN_ERR(commit_changes(ra_session, pool));
+
+ /* expect an error when searching up to r3, when repository head is r1 */
+ SVN_TEST_ASSERT_ERROR(svn_ra_get_deleted_rev(ra_session, "A", 1, 3,
+ &revision_deleted, pool),
+ SVN_ERR_FS_NO_SUCH_REVISION);
+
+ return SVN_NO_ERROR;
+}
+
 
 /* The test table. */
 
 static int max_threads = 4;
 
 static struct svn_test_descriptor_t test_funcs[] =
@@ -1817,10 +1902,14 @@ static struct svn_test_descriptor_t test
     SVN_TEST_OPTS_PASS(tunnel_run_checkout,
                        "verify checkout over a tunnel"),
     SVN_TEST_OPTS_PASS(commit_empty_last_change,
                        "check how last change applies to empty commit"),
     SVN_TEST_OPTS_PASS(commit_locked_file,
                        "check commit editor for a locked file"),
+ SVN_TEST_OPTS_PASS(test_get_deleted_rev_no_delete,
+ "test get-deleted-rev no delete"),
+ SVN_TEST_OPTS_PASS(test_get_deleted_rev_errors,
+ "test get-deleted-rev errors"),
     SVN_TEST_NULL
   };
 
 SVN_TEST_MAIN
]]]

  Patch against Subversion 1.9.10
[[[
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c
+++ subversion/libsvn_ra_svn/client.c
@@ -2837,6 +2837,7 @@
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
+ svn_error_t *err;
 
   /* Transmit the parameters. */
   SVN_ERR(svn_ra_svn__write_cmd_get_deleted_rev(conn, pool, path,
@@ -2846,8 +2847,20 @@
   SVN_ERR(handle_unsupported_cmd(handle_auth_request(sess_baton, pool),
                                  N_("'get-deleted-rev' not implemented")));
 
- return svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, "r",
- revision_deleted));
+ err = svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, "r",
+ revision_deleted));
+ /* The protocol does not allow for a reply of SVN_INVALID_REVNUM directly.
+ Instead, a new enough server returns SVN_ERR_ENTRY_MISSING_REVISION to
+ indicate the answer to the query is SVN_INVALID_REVNUM. (An older server
+ closes the connection and returns SVN_ERR_RA_SVN_CONNECTION_CLOSED.) */
+ if (err && err->apr_err == SVN_ERR_ENTRY_MISSING_REVISION)
+ {
+ *revision_deleted = SVN_INVALID_REVNUM;
+ svn_error_clear(err);
+ }
+ else
+ SVN_ERR(err);
+ return SVN_NO_ERROR;
 }
 
 static svn_error_t *
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c
+++ subversion/svnserve/serve.c
@@ -3296,8 +3296,21 @@
                                svn_relpath_canonicalize(path, pool), pool);
   SVN_ERR(log_command(b, conn, pool, "get-deleted-rev"));
   SVN_ERR(trivial_auth_request(conn, pool, b));
- SVN_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision,
- end_revision, &revision_deleted, pool));
+ SVN_CMD_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision,
+ end_revision, &revision_deleted, pool));
+
+ /* The protocol does not allow for a reply of SVN_INVALID_REVNUM directly.
+ Instead, return SVN_ERR_ENTRY_MISSING_REVISION. A new enough client
+ knows that this means the answer to the query is SVN_INVALID_REVNUM.
+ (An older client reports this as an error.) */
+ if (revision_deleted == SVN_INVALID_REVNUM)
+ SVN_CMD_ERR(svn_error_createf(SVN_ERR_ENTRY_MISSING_REVISION, NULL,
+ "svn protocol command 'get-deleted-rev': "
+ "path '%s' was not deleted in r%ld-%ld; "
+ "NOTE: newer clients handle this case "
+ "and do not report it as an error",
+ full_path, peg_revision, end_revision));
+
   SVN_ERR(svn_ra_svn__write_cmd_response(conn, pool, "r", revision_deleted));
   return SVN_NO_ERROR;
 }
@@ -3768,7 +3781,7 @@
                        serve_params_t *params,
                        apr_pool_t *scratch_pool)
 {
- svn_error_t *err, *io_err;
+ svn_error_t *err;
   apr_uint64_t ver;
   const char *client_url, *ra_client_string, *client_string;
   apr_array_header_t *caplist;
@@ -3900,11 +3913,12 @@
     }
   if (err)
     {
- log_error(err, b);
- io_err = svn_ra_svn__write_cmd_failure(conn, scratch_pool, err);
- svn_error_clear(err);
- SVN_ERR(io_err);
- return svn_ra_svn__flush(conn, scratch_pool);
+ /* Report these errors to the client before closing the connection. */
+ err = svn_error_compose_create(err,
+ svn_ra_svn__write_cmd_failure(conn, scratch_pool, err));
+ err = svn_error_compose_create(err,
+ svn_ra_svn__flush(conn, scratch_pool));
+ return err;
     }
 
   SVN_ERR(svn_fs_get_uuid(b->repository->fs, &b->repository->uuid,
Index: subversion/tests/libsvn_ra/ra-test.c
===================================================================
--- subversion/tests/libsvn_ra/ra-test.c
+++ subversion/tests/libsvn_ra/ra-test.c
@@ -93,6 +93,41 @@
   return SVN_NO_ERROR;
 }
 
+/* Commit two revisions: add 'B', then delete 'A' */
+static svn_error_t *
+commit_two_changes(svn_ra_session_t *session,
+ apr_pool_t *pool)
+{
+ apr_hash_t *revprop_table = apr_hash_make(pool);
+ const svn_delta_editor_t *editor;
+ void *edit_baton;
+ void *root_baton, *dir_baton;
+
+ /* mkdir B */
+ SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+ revprop_table,
+ NULL, NULL, NULL, TRUE, pool));
+ SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
+ pool, &root_baton));
+ SVN_ERR(editor->add_directory("B", root_baton, NULL, SVN_INVALID_REVNUM,
+ pool, &dir_baton));
+ SVN_ERR(editor->close_directory(dir_baton, pool));
+ SVN_ERR(editor->close_directory(root_baton, pool));
+ SVN_ERR(editor->close_edit(edit_baton, pool));
+
+ /* delete A */
+ SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+ revprop_table,
+ NULL, NULL, NULL, TRUE, pool));
+ SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
+ pool, &root_baton));
+ SVN_ERR(editor->delete_entry("A", SVN_INVALID_REVNUM, root_baton, pool));
+ SVN_ERR(editor->close_directory(root_baton, pool));
+ SVN_ERR(editor->close_edit(edit_baton, pool));
+
+ return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 commit_tree(svn_ra_session_t *session,
             apr_pool_t *pool)
@@ -842,6 +877,63 @@
 }
 
 

+/* Cases of 'get-deleted-rev' that should return SVN_INVALID_REVNUM. */
+static svn_error_t *
+test_get_deleted_rev_no_delete(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_ra_session_t *ra_session;
+ svn_revnum_t revision_deleted;
+
+ SVN_ERR(make_and_open_repos(&ra_session,
+ "test-repo-get-deleted-rev-no-delete", opts,
+ pool));
+ SVN_ERR(commit_changes(ra_session, pool));
+ SVN_ERR(commit_two_changes(ra_session, pool));
+
+ /* expect 'no deletion' in the range up to r2, when it is deleted in r3 */
+ /* This was failing over RA-SVN where the 'get-deleted-rev' wire command's
+ prototype cannot directly represent that result. A new enough client and
+ server collaborate on a work-around implemented using an error code. */
+ SVN_ERR(svn_ra_get_deleted_rev(ra_session, "A", 1, 2,
+ &revision_deleted, pool));
+ SVN_TEST_INT_ASSERT(revision_deleted, SVN_INVALID_REVNUM);
+
+ /* this connection should still be open: a simple case should still work */
+ SVN_ERR(svn_ra_get_deleted_rev(ra_session, "A", 1, 3,
+ &revision_deleted, pool));
+ SVN_TEST_INT_ASSERT(revision_deleted, 3);
+
+ return SVN_NO_ERROR;
+}
+
+/* Cases of 'get-deleted-rev' that should return an error. */
+static svn_error_t *
+test_get_deleted_rev_errors(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_ra_session_t *ra_session;
+ svn_revnum_t revision_deleted;
+ svn_error_t *err;
+
+ SVN_ERR(make_and_open_repos(&ra_session,
+ "test-repo-get-deleted-rev-errors", opts, pool));
+ SVN_ERR(commit_changes(ra_session, pool));
+
+ /* expect an error when searching up to r3, when repository head is r1 */
+ err = svn_ra_get_deleted_rev(ra_session, "A", 1, 3, &revision_deleted, pool);
+
+ /* mod_dav_svn returns a generic error code for "500 Internal Server Error";
+ * the other RA layers return the specific error code for "no such revision".
+ * We should make these consistent, but for now that's how it is. */
+ if (opts->repos_url && strncmp(opts->repos_url, "http", 4) == 0)
+ SVN_TEST_ASSERT_ERROR(err, SVN_ERR_RA_DAV_REQUEST_FAILED);
+ else
+ SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_NO_SUCH_REVISION);
+
+ return SVN_NO_ERROR;
+}
+
 /* The test table. */
 
 static int max_threads = 2;
@@ -867,6 +959,10 @@
                        "check list has_props performance"),
     SVN_TEST_OPTS_PASS(tunnel_run_checkout,
                        "verify checkout over a tunnel"),
+ SVN_TEST_OPTS_PASS(test_get_deleted_rev_no_delete,
+ "test get-deleted-rev no delete"),
+ SVN_TEST_OPTS_PASS(test_get_deleted_rev_errors,
+ "test get-deleted-rev errors"),
     SVN_TEST_NULL
   };
 
]]]

}}}
Received on 2019-07-31 18:20:10 CEST

This is an archived mail posted to the Subversion Dev mailing list.