Author: dsahlberg
Date: Sun Dec 8 23:54:07 2024
New Revision: 1922384
URL: http://svn.apache.org/viewvc?rev=1922384&view=rev
Log:
Merge r1922383 from trunk, fixing CVE-2024-46901
* CVE-2024-46901
Votes:
+1: kotkov, stsp, astieger
Modified:
subversion/branches/1.14.x/ (props changed)
subversion/branches/1.14.x/subversion/include/private/svn_repos_private.h
subversion/branches/1.14.x/subversion/libsvn_repos/commit.c
subversion/branches/1.14.x/subversion/libsvn_repos/repos.c
subversion/branches/1.14.x/subversion/mod_dav_svn/lock.c
subversion/branches/1.14.x/subversion/mod_dav_svn/repos.c
subversion/branches/1.14.x/subversion/tests/cmdline/mod_dav_svn_tests.py
Propchange: subversion/branches/1.14.x/
------------------------------------------------------------------------------
Merged /subversion/trunk:r1922383
Modified:
subversion/branches/1.14.x/subversion/include/private/svn_repos_private.h
URL:
http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/include/private/svn_repos_private.h?rev=1922384&r1=1922383&r2=1922384&view=diff
==============================================================================
--- subversion/branches/1.14.x/subversion/include/private/svn_repos_private.h
(original)
+++ subversion/branches/1.14.x/subversion/include/private/svn_repos_private.h
Sun Dec 8 23:54:07 2024
@@ -390,6 +390,14 @@ svn_repos__get_dump_editor(const svn_del
const char *update_anchor_relpath,
apr_pool_t *pool);
+/* Validate that the given PATH is a valid pathname that can be stored in
+ * a Subversion repository, according to the name constraints used by the
+ * svn_repos_* layer.
+ */
+svn_error_t *
+svn_repos__validate_new_path(const char *path,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/branches/1.14.x/subversion/libsvn_repos/commit.c
URL:
http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/libsvn_repos/commit.c?rev=1922384&r1=1922383&r2=1922384&view=diff
==============================================================================
--- subversion/branches/1.14.x/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/1.14.x/subversion/libsvn_repos/commit.c Sun Dec 8
23:54:07 2024
@@ -308,8 +308,7 @@ add_file_or_directory(const char *path,
svn_boolean_t was_copied = FALSE;
const char *full_path, *canonicalized_path;
- /* Reject paths which contain control characters (related to issue #4340). */
- SVN_ERR(svn_path_check_valid(path, pool));
+ SVN_ERR(svn_repos__validate_new_path(path, pool));
SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL, path,
pool, pool));
Modified: subversion/branches/1.14.x/subversion/libsvn_repos/repos.c
URL:
http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/libsvn_repos/repos.c?rev=1922384&r1=1922383&r2=1922384&view=diff
==============================================================================
--- subversion/branches/1.14.x/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/1.14.x/subversion/libsvn_repos/repos.c Sun Dec 8
23:54:07 2024
@@ -2092,3 +2092,13 @@ svn_repos__fs_type(const char **fs_type,
svn_dirent_join(repos_path, SVN_REPOS__DB_DIR, pool),
pool);
}
+
+svn_error_t *
+svn_repos__validate_new_path(const char *path,
+ apr_pool_t *scratch_pool)
+{
+ /* Reject paths which contain control characters (related to issue #4340). */
+ SVN_ERR(svn_path_check_valid(path, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/branches/1.14.x/subversion/mod_dav_svn/lock.c
URL:
http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/mod_dav_svn/lock.c?rev=1922384&r1=1922383&r2=1922384&view=diff
==============================================================================
--- subversion/branches/1.14.x/subversion/mod_dav_svn/lock.c (original)
+++ subversion/branches/1.14.x/subversion/mod_dav_svn/lock.c Sun Dec 8
23:54:07 2024
@@ -36,6 +36,7 @@
#include "svn_pools.h"
#include "svn_props.h"
#include "private/svn_log.h"
+#include "private/svn_repos_private.h"
#include "dav_svn.h"
@@ -717,6 +718,12 @@ append_locks(dav_lockdb *lockdb,
/* Commit a 0-byte file: */
+ if ((serr = svn_repos__validate_new_path(resource->info->repos_path,
+ resource->pool)))
+ return dav_svn__convert_err(serr, HTTP_BAD_REQUEST,
+ "Request specifies an invalid path.",
+ resource->pool);
+
if ((serr = dav_svn__get_youngest_rev(&rev, repos, resource->pool)))
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Could not determine youngest revision",
Modified: subversion/branches/1.14.x/subversion/mod_dav_svn/repos.c
URL:
http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/mod_dav_svn/repos.c?rev=1922384&r1=1922383&r2=1922384&view=diff
==============================================================================
--- subversion/branches/1.14.x/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/1.14.x/subversion/mod_dav_svn/repos.c Sun Dec 8
23:54:07 2024
@@ -2928,6 +2928,16 @@ open_stream(const dav_resource *resource
if (kind == svn_node_none) /* No existing file. */
{
+ serr = svn_repos__validate_new_path(resource->info->repos_path,
+ resource->pool);
+
+ if (serr != NULL)
+ {
+ return dav_svn__convert_err(serr, HTTP_BAD_REQUEST,
+ "Request specifies an invalid path.",
+ resource->pool);
+ }
+
serr = svn_fs_make_file(resource->info->root.root,
resource->info->repos_path,
resource->pool);
@@ -4120,6 +4130,14 @@ create_collection(dav_resource *resource
return err;
}
+ if ((serr = svn_repos__validate_new_path(resource->info->repos_path,
+ resource->pool)) != NULL)
+ {
+ return dav_svn__convert_err(serr, HTTP_BAD_REQUEST,
+ "Request specifies an invalid path.",
+ resource->pool);
+ }
+
if ((serr = svn_fs_make_dir(resource->info->root.root,
resource->info->repos_path,
resource->pool)) != NULL)
@@ -4194,6 +4212,12 @@ copy_resource(const dav_resource *src,
return err;
}
+ serr = svn_repos__validate_new_path(dst->info->repos_path, dst->pool);
+ if (serr)
+ return dav_svn__convert_err(serr, HTTP_BAD_REQUEST,
+ "Request specifies an invalid path.",
+ dst->pool);
+
src_repos_path = svn_repos_path(src->info->repos->repos, src->pool);
dst_repos_path = svn_repos_path(dst->info->repos->repos, dst->pool);
@@ -4430,6 +4454,12 @@ move_resource(dav_resource *src,
if (err)
return err;
+ serr = svn_repos__validate_new_path(dst->info->repos_path, dst->pool);
+ if (serr)
+ return dav_svn__convert_err(serr, HTTP_BAD_REQUEST,
+ "Request specifies an invalid path.",
+ dst->pool);
+
/* Copy the src to the dst. */
serr = svn_fs_copy(src->info->root.root, /* the root object of src rev*/
src->info->repos_path, /* the relative path of src */
Modified:
subversion/branches/1.14.x/subversion/tests/cmdline/mod_dav_svn_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/1.14.x/subversion/tests/cmdline/mod_dav_svn_tests.py?rev=1922384&r1=1922383&r2=1922384&view=diff
==============================================================================
--- subversion/branches/1.14.x/subversion/tests/cmdline/mod_dav_svn_tests.py
(original)
+++ subversion/branches/1.14.x/subversion/tests/cmdline/mod_dav_svn_tests.py
Sun Dec 8 23:54:07 2024
@@ -686,6 +686,67 @@ def last_modified_header(sbox):
raise svntest.Failure('Unexpected Last-Modified header: %s' %
last_modified)
r.read()
+@SkipUnless(svntest.main.is_ra_type_dav)
+def create_name_with_control_chars(sbox):
+ "test creating items with control chars in names"
+
+ sbox.build(create_wc=False)
+
+ h = svntest.main.create_http_connection(sbox.repo_url)
+
+ # POST /repos/!svn/me
+ # Create a new transaction.
+ req_body = (
+ '(create-txn-with-props '
+ '(svn:txn-client-compat-version 6 1.14.4 '
+ 'svn:txn-user-agent 45 SVN/1.14.4 (x86-microsoft-windows) serf/1.3.9 '
+ 'svn:log 0 ))'
+ )
+ headers = {
+ 'Authorization': 'Basic ' +
base64.b64encode(b'jconstant:rayjandom').decode(),
+ 'Content-Type': 'application/vnd.svn-skel',
+ }
+ h.request('POST', sbox.repo_url + '/!svn/me', req_body, headers)
+ r = h.getresponse()
+ if r.status != httplib.CREATED:
+ raise svntest.Failure('Unexpected status: %d %s' % (r.status, r.reason))
+ txn_name = r.getheader('SVN-Txn-Name')
+ r.read()
+
+ # MKCOL /repos/!svn/txn/TXN_NAME/tab%09name
+ # Must fail with a 400 Bad Request.
+ headers = {
+ 'Authorization': 'Basic ' +
base64.b64encode(b'jconstant:rayjandom').decode(),
+ }
+ h.request('MKCOL', sbox.repo_url + '/!svn/txr/' + txn_name + '/tab%09name',
None, headers)
+ r = h.getresponse()
+ if r.status != httplib.BAD_REQUEST:
+ raise svntest.Failure('Unexpected status: %d %s' % (r.status, r.reason))
+ r.read()
+
+ # PUT /repos/!svn/txn/TXN_NAME/tab%09name
+ # Must fail with a 400 Bad Request.
+ headers = {
+ 'Authorization': 'Basic ' +
base64.b64encode(b'jconstant:rayjandom').decode(),
+ }
+ h.request('PUT', sbox.repo_url + '/!svn/txr/' + txn_name + '/tab%09name',
None, headers)
+ r = h.getresponse()
+ if r.status != httplib.BAD_REQUEST:
+ raise svntest.Failure('Unexpected status: %d %s' % (r.status, r.reason))
+ r.read()
+
+ # COPY /repos/!svn/rvr/1/iota -> /repos/!svn/txn/TXN_NAME/tab%09name
+ # Must fail with a 400 Bad Request.
+ headers = {
+ 'Authorization': 'Basic ' +
base64.b64encode(b'jconstant:rayjandom').decode(),
+ 'Destination': sbox.repo_url + '/!svn/txr/' + txn_name + '/tab%09name'
+ }
+ h.request('COPY', sbox.repo_url + '/!svn/rvr/1/iota', None, headers)
+ r = h.getresponse()
+ if r.status != httplib.BAD_REQUEST:
+ raise svntest.Failure('Unexpected status: %d %s' % (r.status, r.reason))
+ r.read()
+
########################################################################
# Run the tests
@@ -700,6 +761,7 @@ test_list = [ None,
propfind_allprop,
propfind_propname,
last_modified_header,
+ create_name_with_control_chars,
]
serial_only = True