Bug#781718: unblock: subversion/1.8.10-6
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package subversion
This uploaded backports fixes for 3 recent CVEs.
$ debdiff subversion_1.8.10-5.dsc subversion_1.8.10-6.dsc
diffstat for subversion_1.8.10-5 subversion_1.8.10-6
debian/patches/CVE-2015-0202 | 474 ++++++++++++++++++++++++++++++++
debian/patches/CVE-2015-0248 | 105 +++++++
debian/patches/CVE-2015-0251 | 62 ++++
subversion-1.8.10/debian/changelog | 11
subversion-1.8.10/debian/patches/series | 3
5 files changed, 655 insertions(+)
diff -u subversion-1.8.10/debian/changelog subversion-1.8.10/debian/changelog
--- subversion-1.8.10/debian/changelog
+++ subversion-1.8.10/debian/changelog
@@ -1,3 +1,14 @@
+subversion (1.8.10-6) unstable; urgency=high
+
+ * patches/CVE-2015-0202: Excessive memory use with certain REPORT requests
+ against mod_dav_svn with FSFS repositories
+ * patches/CVE-2015-0248: Assertion DoS vulnerability for certain mod_dav_svn
+ and svnserve requests with dynamically evaluated revision numbers
+ * patches/CVE-2015-0251: mod_dav_svn allows spoofing svn:author property
+ values for new revisions
+
+ -- James McCoy <jamessan@debian.org> Tue, 31 Mar 2015 22:51:18 -0400
+
subversion (1.8.10-5) unstable; urgency=medium
* patches/CVE-2014-8108: mod_dav_svn DoS vulnerability with invalid virtual
diff -u subversion-1.8.10/debian/patches/series subversion-1.8.10/debian/patches/series
--- subversion-1.8.10/debian/patches/series
+++ subversion-1.8.10/debian/patches/series
@@ -21,0 +22,3 @@
+CVE-2015-0251
+CVE-2015-0248
+CVE-2015-0202
only in patch2:
unchanged:
--- subversion-1.8.10.orig/debian/patches/CVE-2015-0202
+++ subversion-1.8.10/debian/patches/CVE-2015-0202
@@ -0,0 +1,474 @@
+Index: subversion/libsvn_fs_fs/tree.c
+===================================================================
+--- a/subversion/libsvn_fs_fs/tree.c (revision 1655679)
++++ b/subversion/libsvn_fs_fs/tree.c (working copy)
+@@ -127,7 +127,6 @@ typedef struct fs_txn_root_data_t
+ static svn_error_t * get_dag(dag_node_t **dag_node_p,
+ svn_fs_root_t *root,
+ const char *path,
+- svn_boolean_t needs_lock_cache,
+ apr_pool_t *pool);
+
+ static svn_fs_root_t *make_revision_root(svn_fs_t *fs, svn_revnum_t rev,
+@@ -178,34 +177,10 @@ typedef struct cache_entry_t
+ */
+ enum { BUCKET_COUNT = 256 };
+
+-/* Each pool that has received a DAG node, will hold at least on lock on
+- our cache to ensure that the node remains valid despite being allocated
+- in the cache's pool. This is the structure to represent the lock.
+- */
+-typedef struct cache_lock_t
+-{
+- /* pool holding the lock */
+- apr_pool_t *pool;
+-
+- /* cache being locked */
+- fs_fs_dag_cache_t *cache;
+-
+- /* next lock. NULL at EOL */
+- struct cache_lock_t *next;
+-
+- /* previous lock. NULL at list head. Only then this==cache->first_lock */
+- struct cache_lock_t *prev;
+-} cache_lock_t;
+-
+ /* The actual cache structure. All nodes will be allocated in POOL.
+ When the number of INSERTIONS (i.e. objects created form that pool)
+ exceeds a certain threshold, the pool will be cleared and the cache
+ with it.
+-
+- To ensure that nodes returned from this structure remain valid, the
+- cache will get locked for the lifetime of the _receiving_ pools (i.e.
+- those in which we would allocate the node if there was no cache.).
+- The cache will only be cleared FIRST_LOCK is 0.
+ */
+ struct fs_fs_dag_cache_t
+ {
+@@ -221,47 +196,8 @@ struct fs_fs_dag_cache_t
+ /* Property lookups etc. have a very high locality (75% re-hit).
+ Thus, remember the last hit location for optimistic lookup. */
+ apr_size_t last_hit;
+-
+- /* List of receiving pools that are still alive. */
+- cache_lock_t *first_lock;
+ };
+
+-/* Cleanup function to be called when a receiving pool gets cleared.
+- Unlocks the cache once.
+- */
+-static apr_status_t
+-unlock_cache(void *baton_void)
+-{
+- cache_lock_t *lock = baton_void;
+-
+- /* remove lock from chain. Update the head */
+- if (lock->next)
+- lock->next->prev = lock->prev;
+- if (lock->prev)
+- lock->prev->next = lock->next;
+- else
+- lock->cache->first_lock = lock->next;
+-
+- return APR_SUCCESS;
+-}
+-
+-/* Cleanup function to be called when the cache itself gets destroyed.
+- In that case, we must unregister all unlock requests.
+- */
+-static apr_status_t
+-unregister_locks(void *baton_void)
+-{
+- fs_fs_dag_cache_t *cache = baton_void;
+- cache_lock_t *lock;
+-
+- for (lock = cache->first_lock; lock; lock = lock->next)
+- apr_pool_cleanup_kill(lock->pool,
+- lock,
+- unlock_cache);
+-
+- return APR_SUCCESS;
+-}
+-
+ fs_fs_dag_cache_t*
+ svn_fs_fs__create_dag_cache(apr_pool_t *pool)
+ {
+@@ -268,59 +204,15 @@ svn_fs_fs__create_dag_cache(apr_pool_t *pool)
+ fs_fs_dag_cache_t *result = apr_pcalloc(pool, sizeof(*result));
+ result->pool = svn_pool_create(pool);
+
+- apr_pool_cleanup_register(pool,
+- result,
+- unregister_locks,
+- apr_pool_cleanup_null);
+-
+ return result;
+ }
+
+-/* Prevent the entries in CACHE from being destroyed, for as long as the
+- POOL lives.
+- */
+-static void
+-lock_cache(fs_fs_dag_cache_t* cache, apr_pool_t *pool)
+-{
+- /* we only need to lock / unlock once per pool. Since we will often ask
+- for multiple nodes with the same pool, we can reduce the overhead.
+- However, if e.g. pools are being used in an alternating pattern,
+- we may lock the cache more than once for the same pool (and register
+- just as many cleanup actions).
+- */
+- cache_lock_t *lock = cache->first_lock;
+-
+- /* try to find an existing lock for POOL.
+- But limit the time spent on chasing pointers. */
+- int limiter = 8;
+- while (lock && --limiter)
+- if (lock->pool == pool)
+- return;
+-
+- /* create a new lock and put it at the beginning of the lock chain */
+- lock = apr_palloc(pool, sizeof(*lock));
+- lock->cache = cache;
+- lock->pool = pool;
+- lock->next = cache->first_lock;
+- lock->prev = NULL;
+-
+- if (cache->first_lock)
+- cache->first_lock->prev = lock;
+- cache->first_lock = lock;
+-
+- /* instruct POOL to remove the look upon cleanup */
+- apr_pool_cleanup_register(pool,
+- lock,
+- unlock_cache,
+- apr_pool_cleanup_null);
+-}
+-
+ /* Clears the CACHE at regular intervals (destroying all cached nodes)
+ */
+ static void
+ auto_clear_dag_cache(fs_fs_dag_cache_t* cache)
+ {
+- if (cache->first_lock == NULL && cache->insertions > BUCKET_COUNT)
++ if (cache->insertions > BUCKET_COUNT)
+ {
+ svn_pool_clear(cache->pool);
+
+@@ -433,18 +325,12 @@ locate_cache(svn_cache__t **cache,
+ }
+ }
+
+-/* Return NODE for PATH from ROOT's node cache, or NULL if the node
+- isn't cached; read it from the FS. *NODE remains valid until either
+- POOL or the FS gets cleared or destroyed (whichever comes first).
+-
+- Since locking can be expensive and POOL may be long-living, for
+- nodes that will not need to survive the next call to this function,
+- set NEEDS_LOCK_CACHE to FALSE. */
++/* Return NODE_P for PATH from ROOT's node cache, or NULL if the node
++ isn't cached; read it from the FS. *NODE_P is allocated in POOL. */
+ static svn_error_t *
+ dag_node_cache_get(dag_node_t **node_p,
+ svn_fs_root_t *root,
+ const char *path,
+- svn_boolean_t needs_lock_cache,
+ apr_pool_t *pool)
+ {
+ svn_boolean_t found;
+@@ -466,25 +352,23 @@ dag_node_cache_get(dag_node_t **node_p,
+ if (bucket->node == NULL)
+ {
+ locate_cache(&cache, &key, root, path, pool);
+- SVN_ERR(svn_cache__get((void **)&node, &found, cache, key,
+- ffd->dag_node_cache->pool));
++ SVN_ERR(svn_cache__get((void **)&node, &found, cache, key, pool));
+ if (found && node)
+ {
+ /* Patch up the FS, since this might have come from an old FS
+ * object. */
+ svn_fs_fs__dag_set_fs(node, root->fs);
+- bucket->node = node;
++
++ /* Retain the DAG node in L1 cache. */
++ bucket->node = svn_fs_fs__dag_dup(node,
++ ffd->dag_node_cache->pool);
+ }
+ }
+ else
+ {
+- node = bucket->node;
++ /* Copy the node from L1 cache into the passed-in POOL. */
++ node = svn_fs_fs__dag_dup(bucket->node, pool);
+ }
+-
+- /* if we found a node, make sure it remains valid at least as long
+- as it would when allocated in POOL. */
+- if (node && needs_lock_cache)
+- lock_cache(ffd->dag_node_cache, pool);
+ }
+ else
+ {
+@@ -822,7 +706,7 @@ get_copy_inheritance(copy_id_inherit_t *inherit_p,
+ SVN_ERR(svn_fs_fs__dag_get_copyroot(©root_rev, ©root_path,
+ child->node));
+ SVN_ERR(svn_fs_fs__revision_root(©root_root, fs, copyroot_rev, pool));
+- SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, FALSE, pool));
++ SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, pool));
+ copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
+
+ if (svn_fs_fs__id_compare(copyroot_id, child_id) == -1)
+@@ -938,7 +822,7 @@ open_path(parent_path_t **parent_path_p,
+ {
+ directory = svn_dirent_dirname(path, pool);
+ if (directory[1] != 0) /* root nodes are covered anyway */
+- SVN_ERR(dag_node_cache_get(&here, root, directory, TRUE, pool));
++ SVN_ERR(dag_node_cache_get(&here, root, directory, pool));
+ }
+
+ /* did the shortcut work? */
+@@ -998,8 +882,8 @@ open_path(parent_path_t **parent_path_p,
+ element if we already know the lookup to fail for the
+ complete path. */
+ if (next || !(flags & open_path_uncached))
+- SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far,
+- TRUE, pool));
++ SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far, pool));
++
+ if (cached_node)
+ child = cached_node;
+ else
+@@ -1136,8 +1020,7 @@ make_path_mutable(svn_fs_root_t *root,
+ parent_path->node));
+ SVN_ERR(svn_fs_fs__revision_root(©root_root, root->fs,
+ copyroot_rev, pool));
+- SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path,
+- FALSE, pool));
++ SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, pool));
+
+ child_id = svn_fs_fs__dag_get_id(parent_path->node);
+ copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
+@@ -1174,16 +1057,11 @@ make_path_mutable(svn_fs_root_t *root,
+
+ /* Open the node identified by PATH in ROOT. Set DAG_NODE_P to the
+ node we find, allocated in POOL. Return the error
+- SVN_ERR_FS_NOT_FOUND if this node doesn't exist.
+-
+- Since locking can be expensive and POOL may be long-living, for
+- nodes that will not need to survive the next call to this function,
+- set NEEDS_LOCK_CACHE to FALSE. */
++ SVN_ERR_FS_NOT_FOUND if this node doesn't exist. */
+ static svn_error_t *
+ get_dag(dag_node_t **dag_node_p,
+ svn_fs_root_t *root,
+ const char *path,
+- svn_boolean_t needs_lock_cache,
+ apr_pool_t *pool)
+ {
+ parent_path_t *parent_path;
+@@ -1192,7 +1070,7 @@ get_dag(dag_node_t **dag_node_p,
+ /* First we look for the DAG in our cache
+ (if the path may be canonical). */
+ if (*path == '/')
+- SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache, pool));
++ SVN_ERR(dag_node_cache_get(&node, root, path, pool));
+
+ if (! node)
+ {
+@@ -1202,8 +1080,7 @@ get_dag(dag_node_t **dag_node_p,
+ path = svn_fs__canonicalize_abspath(path, pool);
+
+ /* Try again with the corrected path. */
+- SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache,
+- pool));
++ SVN_ERR(dag_node_cache_get(&node, root, path, pool));
+ }
+
+ if (! node)
+@@ -1281,7 +1158,7 @@ svn_fs_fs__node_id(const svn_fs_id_t **id_p,
+ {
+ dag_node_t *node;
+
+- SVN_ERR(get_dag(&node, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+ *id_p = svn_fs_fs__id_copy(svn_fs_fs__dag_get_id(node), pool);
+ }
+ return SVN_NO_ERROR;
+@@ -1296,7 +1173,7 @@ svn_fs_fs__node_created_rev(svn_revnum_t *revision
+ {
+ dag_node_t *node;
+
+- SVN_ERR(get_dag(&node, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+ return svn_fs_fs__dag_get_revision(revision, node, pool);
+ }
+
+@@ -1311,7 +1188,7 @@ fs_node_created_path(const char **created_path,
+ {
+ dag_node_t *node;
+
+- SVN_ERR(get_dag(&node, root, path, TRUE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+ *created_path = svn_fs_fs__dag_get_created_path(node);
+
+ return SVN_NO_ERROR;
+@@ -1375,7 +1252,7 @@ fs_node_prop(svn_string_t **value_p,
+ dag_node_t *node;
+ apr_hash_t *proplist;
+
+- SVN_ERR(get_dag(&node, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+ SVN_ERR(svn_fs_fs__dag_get_proplist(&proplist, node, pool));
+ *value_p = NULL;
+ if (proplist)
+@@ -1398,7 +1275,7 @@ fs_node_proplist(apr_hash_t **table_p,
+ apr_hash_t *table;
+ dag_node_t *node;
+
+- SVN_ERR(get_dag(&node, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+ SVN_ERR(svn_fs_fs__dag_get_proplist(&table, node, pool));
+ *table_p = table ? table : apr_hash_make(pool);
+
+@@ -1515,8 +1392,8 @@ fs_props_changed(svn_boolean_t *changed_p,
+ (SVN_ERR_FS_GENERAL, NULL,
+ _("Cannot compare property value between two different filesystems"));
+
+- SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
+- SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
++ SVN_ERR(get_dag(&node1, root1, path1, pool));
++ SVN_ERR(get_dag(&node2, root2, path2, pool));
+ return svn_fs_fs__dag_things_different(changed_p, NULL,
+ node1, node2);
+ }
+@@ -1529,7 +1406,7 @@ fs_props_changed(svn_boolean_t *changed_p,
+ static svn_error_t *
+ get_root(dag_node_t **node, svn_fs_root_t *root, apr_pool_t *pool)
+ {
+- return get_dag(node, root, "/", TRUE, pool);
++ return get_dag(node, root, "/", pool);
+ }
+
+
+@@ -2193,7 +2070,7 @@ fs_dir_entries(apr_hash_t **table_p,
+ dag_node_t *node;
+
+ /* Get the entries for this path in the caller's pool. */
+- SVN_ERR(get_dag(&node, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+ return svn_fs_fs__dag_dir_entries(table_p, node, pool);
+ }
+
+@@ -2365,7 +2242,7 @@ copy_helper(svn_fs_root_t *from_root,
+ _("Copy from mutable tree not currently supported"));
+
+ /* Get the NODE for FROM_PATH in FROM_ROOT.*/
+- SVN_ERR(get_dag(&from_node, from_root, from_path, TRUE, pool));
++ SVN_ERR(get_dag(&from_node, from_root, from_path, pool));
+
+ /* Build up the parent path from TO_PATH in TO_ROOT. If the last
+ component does not exist, it's not that big a deal. We'll just
+@@ -2442,7 +2319,7 @@ copy_helper(svn_fs_root_t *from_root,
+ pool));
+
+ /* Make a record of this modification in the changes table. */
+- SVN_ERR(get_dag(&new_node, to_root, to_path, TRUE, pool));
++ SVN_ERR(get_dag(&new_node, to_root, to_path, pool));
+ SVN_ERR(add_change(to_root->fs, txn_id, to_path,
+ svn_fs_fs__dag_get_id(new_node), kind, FALSE, FALSE,
+ svn_fs_fs__dag_node_kind(from_node),
+@@ -2553,7 +2430,7 @@ fs_copied_from(svn_revnum_t *rev_p,
+ {
+ /* There is no cached entry, look it up the old-fashioned
+ way. */
+- SVN_ERR(get_dag(&node, root, path, TRUE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+ SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(©from_rev, node));
+ SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(©from_path, node));
+ }
+@@ -2628,7 +2505,7 @@ fs_file_length(svn_filesize_t *length_p,
+ dag_node_t *file;
+
+ /* First create a dag_node_t from the root/path pair. */
+- SVN_ERR(get_dag(&file, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&file, root, path, pool));
+
+ /* Now fetch its length */
+ return svn_fs_fs__dag_file_length(length_p, file, pool);
+@@ -2647,7 +2524,7 @@ fs_file_checksum(svn_checksum_t **checksum,
+ {
+ dag_node_t *file;
+
+- SVN_ERR(get_dag(&file, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&file, root, path, pool));
+ return svn_fs_fs__dag_file_checksum(checksum, file, kind, pool);
+ }
+
+@@ -2666,7 +2543,7 @@ fs_file_contents(svn_stream_t **contents,
+ svn_stream_t *file_stream;
+
+ /* First create a dag_node_t from the root/path pair. */
+- SVN_ERR(get_dag(&node, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+
+ /* Then create a readable stream from the dag_node_t. */
+ SVN_ERR(svn_fs_fs__dag_get_contents(&file_stream, node, pool));
+@@ -2689,7 +2566,7 @@ fs_try_process_file_contents(svn_boolean_t *succes
+ apr_pool_t *pool)
+ {
+ dag_node_t *node;
+- SVN_ERR(get_dag(&node, root, path, FALSE, pool));
++ SVN_ERR(get_dag(&node, root, path, pool));
+
+ return svn_fs_fs__dag_try_process_file_contents(success, node,
+ processor, baton, pool);
+@@ -3071,8 +2948,8 @@ fs_contents_changed(svn_boolean_t *changed_p,
+ (SVN_ERR_FS_GENERAL, NULL, _("'%s' is not a file"), path2);
+ }
+
+- SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
+- SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
++ SVN_ERR(get_dag(&node1, root1, path1, pool));
++ SVN_ERR(get_dag(&node2, root2, path2, pool));
+ return svn_fs_fs__dag_things_different(NULL, changed_p,
+ node1, node2);
+ }
+@@ -3092,10 +2969,10 @@ fs_get_file_delta_stream(svn_txdelta_stream_t **st
+ dag_node_t *source_node, *target_node;
+
+ if (source_root && source_path)
+- SVN_ERR(get_dag(&source_node, source_root, source_path, TRUE, pool));
++ SVN_ERR(get_dag(&source_node, source_root, source_path, pool));
+ else
+ source_node = NULL;
+- SVN_ERR(get_dag(&target_node, target_root, target_path, TRUE, pool));
++ SVN_ERR(get_dag(&target_node, target_root, target_path, pool));
+
+ /* Create a delta stream that turns the source into the target. */
+ return svn_fs_fs__dag_get_file_delta_stream(stream_p, source_node,
+@@ -3588,7 +3465,7 @@ history_prev(void *baton, apr_pool_t *pool)
+
+ SVN_ERR(svn_fs_fs__revision_root(©root_root, fs, copyroot_rev,
+ pool));
+- SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, FALSE, pool));
++ SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, pool));
+ copy_dst = svn_fs_fs__dag_get_created_path(node);
+
+ /* If our current path was the very destination of the copy,
+@@ -3785,7 +3662,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs_root_t *r
+ svn_pool_clear(iterpool);
+
+ kid_path = svn_fspath__join(this_path, dirent->name, iterpool);
+- SVN_ERR(get_dag(&kid_dag, root, kid_path, TRUE, iterpool));
++ SVN_ERR(get_dag(&kid_dag, root, kid_path, iterpool));
+
+ SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, kid_dag));
+ SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down, kid_dag));
+@@ -4031,7 +3908,7 @@ add_descendant_mergeinfo(svn_mergeinfo_catalog_t r
+ dag_node_t *this_dag;
+ svn_boolean_t go_down;
+
+- SVN_ERR(get_dag(&this_dag, root, path, TRUE, scratch_pool));
++ SVN_ERR(get_dag(&this_dag, root, path, scratch_pool));
+ SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down,
+ this_dag));
+ if (go_down)
only in patch2:
unchanged:
--- subversion-1.8.10.orig/debian/patches/CVE-2015-0248
+++ subversion-1.8.10/debian/patches/CVE-2015-0248
@@ -0,0 +1,105 @@
+--- a/subversion/mod_dav_svn/reports/get-location-segments.c
++++ b/subversion/mod_dav_svn/reports/get-location-segments.c
+@@ -181,17 +181,36 @@
+ "Not all parameters passed.",
+ SVN_DAV_ERROR_NAMESPACE,
+ SVN_DAV_ERROR_TAG);
+- if (SVN_IS_VALID_REVNUM(start_rev)
+- && SVN_IS_VALID_REVNUM(end_rev)
+- && (end_rev > start_rev))
++
++ /* No START_REV or PEG_REVISION? We'll use HEAD. */
++ if (!SVN_IS_VALID_REVNUM(start_rev) || !SVN_IS_VALID_REVNUM(peg_revision))
++ {
++ svn_revnum_t youngest;
++
++ serr = svn_fs_youngest_rev(&youngest, resource->info->repos->fs,
++ resource->pool);
++ if (serr != NULL)
++ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
++ "Could not determine youngest revision",
++ resource->pool);
++
++ if (!SVN_IS_VALID_REVNUM(start_rev))
++ start_rev = youngest;
++ if (!SVN_IS_VALID_REVNUM(peg_revision))
++ peg_revision = youngest;
++ }
++
++ /* No END_REV? We'll use 0. */
++ if (!SVN_IS_VALID_REVNUM(end_rev))
++ end_rev = 0;
++
++ if (end_rev > start_rev)
+ return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ "End revision must not be younger than "
+ "start revision",
+ SVN_DAV_ERROR_NAMESPACE,
+ SVN_DAV_ERROR_TAG);
+- if (SVN_IS_VALID_REVNUM(peg_revision)
+- && SVN_IS_VALID_REVNUM(start_rev)
+- && (start_rev > peg_revision))
++ if (start_rev > peg_revision)
+ return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ "Start revision must not be younger than "
+ "peg revision",
+--- a/subversion/svnserve/serve.c
++++ b/subversion/svnserve/serve.c
+@@ -2465,9 +2465,30 @@
+
+ abs_path = svn_fspath__join(b->fs_path->data, relative_path, pool);
+
+- if (SVN_IS_VALID_REVNUM(start_rev)
+- && SVN_IS_VALID_REVNUM(end_rev)
+- && (end_rev > start_rev))
++ SVN_ERR(trivial_auth_request(conn, pool, b));
++ SVN_ERR(log_command(baton, conn, pool, "%s",
++ svn_log__get_location_segments(abs_path, peg_revision,
++ start_rev, end_rev,
++ pool)));
++
++ /* No START_REV or PEG_REVISION? We'll use HEAD. */
++ if (!SVN_IS_VALID_REVNUM(start_rev) || !SVN_IS_VALID_REVNUM(peg_revision))
++ {
++ svn_revnum_t youngest;
++
++ SVN_CMD_ERR(svn_fs_youngest_rev(&youngest, b->fs, pool));
++
++ if (!SVN_IS_VALID_REVNUM(start_rev))
++ start_rev = youngest;
++ if (!SVN_IS_VALID_REVNUM(peg_revision))
++ peg_revision = youngest;
++ }
++
++ /* No END_REV? We'll use 0. */
++ if (!SVN_IS_VALID_REVNUM(end_rev))
++ end_rev = 0;
++
++ if (end_rev > start_rev)
+ {
+ err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+ "Get-location-segments end revision must not be "
+@@ -2475,9 +2496,7 @@
+ return log_fail_and_flush(err, b, conn, pool);
+ }
+
+- if (SVN_IS_VALID_REVNUM(peg_revision)
+- && SVN_IS_VALID_REVNUM(start_rev)
+- && (start_rev > peg_revision))
++ if (start_rev > peg_revision)
+ {
+ err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+ "Get-location-segments start revision must not "
+@@ -2485,12 +2504,6 @@
+ return log_fail_and_flush(err, b, conn, pool);
+ }
+
+- SVN_ERR(trivial_auth_request(conn, pool, b));
+- SVN_ERR(log_command(baton, conn, pool, "%s",
+- svn_log__get_location_segments(abs_path, peg_revision,
+- start_rev, end_rev,
+- pool)));
+-
+ /* All the parameters are fine - let's perform the query against the
+ * repository. */
+
only in patch2:
unchanged:
--- subversion-1.8.10.orig/debian/patches/CVE-2015-0251
+++ subversion-1.8.10/debian/patches/CVE-2015-0251
@@ -0,0 +1,62 @@
+Index: subversion/mod_dav_svn/deadprops.c
+===================================================================
+--- a/subversion/mod_dav_svn/deadprops.c (revision 1660122)
++++ b/subversion/mod_dav_svn/deadprops.c (working copy)
+@@ -163,6 +163,23 @@ get_value(dav_db *db, const dav_prop_name *name, s
+ }
+
+
++static svn_error_t *
++change_txn_prop(svn_fs_txn_t *txn,
++ const char *propname,
++ const svn_string_t *value,
++ apr_pool_t *scratch_pool)
++{
++ if (strcmp(propname, SVN_PROP_REVISION_AUTHOR) == 0)
++ return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
++ "Attempted to modify 'svn:author' property "
++ "on a transaction");
++
++ SVN_ERR(svn_repos_fs_change_txn_prop(txn, propname, value, scratch_pool));
++
++ return SVN_NO_ERROR;
++}
++
++
+ static dav_error *
+ save_value(dav_db *db, const dav_prop_name *name,
+ const svn_string_t *const *old_value_p,
+@@ -213,9 +230,8 @@ save_value(dav_db *db, const dav_prop_name *name,
+ {
+ if (resource->working)
+ {
+- serr = svn_repos_fs_change_txn_prop(resource->info->root.txn,
+- propname, value,
+- subpool);
++ serr = change_txn_prop(resource->info->root.txn, propname,
++ value, subpool);
+ }
+ else
+ {
+@@ -254,8 +270,8 @@ save_value(dav_db *db, const dav_prop_name *name,
+ }
+ else if (resource->info->restype == DAV_SVN_RESTYPE_TXN_COLLECTION)
+ {
+- serr = svn_repos_fs_change_txn_prop(resource->info->root.txn,
+- propname, value, subpool);
++ serr = change_txn_prop(resource->info->root.txn, propname,
++ value, subpool);
+ }
+ else
+ {
+@@ -560,8 +576,8 @@ db_remove(dav_db *db, const dav_prop_name *name)
+ /* Working Baseline or Working (Version) Resource */
+ if (db->resource->baselined)
+ if (db->resource->working)
+- serr = svn_repos_fs_change_txn_prop(db->resource->info->root.txn,
+- propname, NULL, subpool);
++ serr = change_txn_prop(db->resource->info->root.txn, propname,
++ NULL, subpool);
+ else
+ /* ### VIOLATING deltaV: you can't proppatch a baseline, it's
+ not a working resource! But this is how we currently
unblock subversion/1.8.10-6
-- System Information:
Debian Release: 8.0
APT prefers unstable
APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 3.16.0-4-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
Reply to: