Origin: https://github.com/drupal/drupal/commit/92f679b84a7878ce99b3f24ada7ff08520a0de2e
Forwarded: not-needed
From: Drew Webber, micieltcs, Heine, Jess, Lee Rowlands
Date: Mon 26 Jul 2021 11:17:11 PM CST
Subject: Fixes for SA-CORE-2021-004
 Backported the diff between 7.81 and 7.82, applying it to the version in the
 old-stable Debian release (7.52)
 .
 SA-CORE-2021-004 includes a fix to the pear Archive_Tar library that could
 allow an attacker to extract parts of tar archives outside its directory via
 symlinks.
Index: drupal7/modules/system/system.tar.inc
===================================================================
--- drupal7.orig/modules/system/system.tar.inc
+++ drupal7/modules/system/system.tar.inc
@@ -2148,14 +2148,6 @@ class Archive_Tar
                             }
                         }
                     } elseif ($v_header['typeflag'] == "2") {
-                        if (strpos(realpath(dirname($v_header['link'])), realpath($p_path)) !== 0) {
-                            $this->_error(
-                                'Out-of-path file extraction {'
-                                . $v_header['filename'] . ' --> ' .
-                                $v_header['link'] . '}'
-                            );
-                            return false;
-                        }
                         if (!$p_symlinks) {
                             $this->_warning('Symbolic links are not allowed. '
                                 . 'Unable to extract {'
@@ -2163,6 +2155,40 @@ class Archive_Tar
                             );
                             return false;
                         }
+			$absolute_link = FALSE;
+                        $link_depth = 0;
+                        if (strpos($v_header['link'], "/") === 0 || strpos($v_header['link'], ':') !== FALSE) {
+                          $absolute_link = TRUE;
+                        }
+                        else {
+                            $s_filename = preg_replace('@^' . preg_quote($p_path) . '@', "", $v_header['filename']);
+                            $s_linkname = str_replace('\\', '/', $v_header['link']);
+                            foreach (explode("/", $s_filename) as $dir) {
+                                if ($dir === "..") {
+                                    $link_depth--;
+                                } elseif ($dir !== "" && $dir !== "." ) {
+                                    $link_depth++;
+                                }
+                            }
+                            foreach (explode("/", $s_linkname) as $dir){
+                                if ($link_depth <= 0) {
+                                    break;
+                                }
+                                if ($dir === "..") {
+                                    $link_depth--;
+                                } elseif ($dir !== "" && $dir !== ".") {
+                                    $link_depth++;
+                                }
+                            }
+                        }
+                        if ($absolute_link || $link_depth <= 0) {
+                            $this->_error(
+                                 'Out-of-path file extraction {'
+                                 . $v_header['filename'] . ' --> ' .
+                                 $v_header['link'] . '}'
+                            );
+                            return false;
+                        }
                         if (@file_exists($v_header['filename'])) {
                             @drupal_unlink($v_header['filename']);
                         }
