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
 


Reply via email to