commit:     fc3cb03273c38d997e22d294a76647c82303797f
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Thu Jun 19 23:48:22 2025 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Fri Jun 20 05:45:35 2025 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=fc3cb032

emerge-webrsync: validate repo and snapshot timestamps

As concerns the get_repository_timestamp() function, check not only that
the "timestamp.x" file can be opened but that it also contains at least
one complete line whose first field is a valid timestamp (in unix time).
Otherwise, have both of its calling functions raise an error and exit.

As concerns the get_snapshot_timestamp() function, check that the output
of tar(1) constitutes at least one complete line whose first field is a
valid timestamp (in unix time). Otherwise, have its calling function
raise an error and exit.

To validate inputs is a matter of common sense. However, one must also
be mindful that the arithmetic context permits arbitrary code execution.

$ f() { echo 'a[$(echo hi >&2)0]'; }
$ (( 0 < $(f) ))
hi
$ [[ 0 -lt $(f) ]]
hi

Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>
Signed-off-by: Sam James <sam <AT> gentoo.org>

 bin/emerge-webrsync | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/bin/emerge-webrsync b/bin/emerge-webrsync
index ffe8096906..6358ec7f51 100755
--- a/bin/emerge-webrsync
+++ b/bin/emerge-webrsync
@@ -194,13 +194,20 @@ get_unixtime_by_date() {
 }
 
 get_repository_timestamp() {
-       local portage_current_timestamp=0
+       local unixtime path
 
-       if [[ -f "${repo_location}/metadata/timestamp.x" ]]; then
-               portage_current_timestamp=$(cut -f 1 -d " " 
"${repo_location}/metadata/timestamp.x" )
+       path=${repo_location}/metadata/timestamp.x
+       if [[ ! -f ${path} ]]; then
+               unixtime=0
+       elif ! read -r unixtime _ < "${path}" || ! is_uint "${unixtime}"; then
+               return 1
        fi
 
-       echo "${portage_current_timestamp}"
+       printf '%s\n' "${unixtime}"
+}
+
+is_uint() {
+       [[ $1 == @(0|[1-9]*([0-9])) ]]
 }
 
 fetch_file() {
@@ -373,8 +380,14 @@ check_file_signature() {
 
 get_snapshot_timestamp() {
        local file=$1
+       local unixtime
 
-       do_tar "${file}" --to-stdout -f - --wildcards -x 
'*/metadata/timestamp.x' | cut -f 1 -d " "
+       do_tar "${file}" --to-stdout -f - --wildcards -x 
'*/metadata/timestamp.x' |
+       {
+               read -r unixtime _ \
+               && is_uint "${unixtime}" \
+               && printf '%s\n' "${unixtime}"
+       }
 }
 
 sync_local() {
@@ -448,7 +461,7 @@ sync_local() {
 
 do_snapshot() {
        local ignore_timestamp=$1 date=$2
-       local snapshot_timestamp have_files signature unixtime digest mirror 
file
+       local {repo,snapshot}_timestamp have_files signature unixtime digest 
mirror file
        local -A suffix_by
        local -a tarballs
 
@@ -494,10 +507,14 @@ do_snapshot() {
                        if (( have_files )); then
                                einfo "Getting snapshot timestamp ..."
 
-                               snapshot_timestamp=$(get_snapshot_timestamp 
"${DISTDIR}/${file}")
-
+                               if ! 
snapshot_timestamp=$(get_snapshot_timestamp "${DISTDIR}/${file}"); then
+                                       die "couldn't determine the timestamp 
of snapshot ${file@Q}"
+                               fi
                                if [[ ${ignore_timestamp} == 0 ]]; then
-                                       if (( snapshot_timestamp < 
$(get_repository_timestamp) )); then
+                                       if ! 
repo_timestamp=$(get_repository_timestamp); then
+                                               die "couldn't determine the 
timestamp of repo ${repo_location@Q}"
+                                       fi
+                                       if (( snapshot_timestamp < 
repo_timestamp )); then
                                                ewarn "Repository (age) is 
newer than fetched snapshot"
                                                have_files=0
                                        fi
@@ -547,7 +564,9 @@ do_latest_snapshot() {
        # are considered to be approximately equal.
        min_time_diff=$(( 2 * 60 * 60 ))
 
-       existing_timestamp=$(get_repository_timestamp)
+       if ! existing_timestamp=$(get_repository_timestamp); then
+               die "couldn't determine the timestamp of repo 
${repo_location@Q}"
+       fi
        printf -v start_time '%(%s)T'
        printf -v start_hour '%(%H)T' "${start_time}"
 

Reply via email to