Description: Fix a symlink directory traversal vulnerability.
 Backported from version 5.2.7.
Bug-Debian: https://bugs.debian.org/774171

--- unrar-nonfree-4.1.4.orig/cmddata.cpp
+++ unrar-nonfree-4.1.4/cmddata.cpp
@@ -538,6 +538,8 @@ void CommandData::ProcessSwitch(const ch
 #ifdef SAVE_LINKS
         case 'L':
           SaveLinks=true;
+          if (etoupper(Switch[2])=='A')
+            AbsoluteLinks=true;
           break;
 #endif
 #ifdef _WIN_ALL
--- unrar-nonfree-4.1.4.orig/extract.cpp
+++ unrar-nonfree-4.1.4/extract.cpp
@@ -856,7 +856,7 @@ bool CmdExtract::ExtractCurrentFile(Comm
       CurFile.SetAllowDelete(!Cmd->KeepBroken);
 
       bool LinkCreateMode=!Cmd->Test && !SkipSolid;
-      if (ExtractLink(DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
+      if (ExtractLink(Cmd,DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
         PrevExtracted=LinkCreateMode;
       else
         if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0)
--- unrar-nonfree-4.1.4.orig/loclang.hpp
+++ unrar-nonfree-4.1.4/loclang.hpp
@@ -99,7 +99,7 @@
 #define   MCHelpSwNal        "\n  n@<list>      Include files listed in specified list file"
 #define   MCHelpSwO          "\n  o[+|-]        Set the overwrite mode"
 #define   MCHelpSwOC         "\n  oc            Set NTFS Compressed attribute"
-#define   MCHelpSwOL         "\n  ol            Save symbolic links as the link instead of the file"
+#define   MCHelpSwOL         "\n  ol[a]         Process symbolic links as the link [absolute paths]"
 #define   MCHelpSwOR         "\n  or            Rename files automatically"
 #define   MCHelpSwOS         "\n  os            Save NTFS streams"
 #define   MCHelpSwOW         "\n  ow            Save or restore file owner and group"
--- unrar-nonfree-4.1.4.orig/options.hpp
+++ unrar-nonfree-4.1.4/options.hpp
@@ -116,6 +116,7 @@ class RAROptions
     int ConvertNames;
     bool ProcessOwners;
     bool SaveLinks;
+    bool AbsoluteLinks;
     int Priority;
     int SleepTime;
     bool KeepBroken;
--- unrar-nonfree-4.1.4.orig/ulinks.cpp
+++ unrar-nonfree-4.1.4/ulinks.cpp
@@ -2,7 +2,44 @@
 
 
 
-bool ExtractLink(ComprDataIO &DataIO,Archive &Arc,const char *LinkName,uint &LinkCRC,bool Create)
+static bool IsFullRootPath(const char *PathA) // Unix ASCII version.
+{
+  return *PathA==CPATHDIVIDER;
+}
+
+
+static bool IsRelativeSymlinkSafe(const char *SrcName,const char *TargetName)
+{
+  if (IsFullRootPath(SrcName))
+    return false;
+  int AllowedDepth=0;
+  while (*SrcName!=0)
+  {
+    if (IsPathDiv(SrcName[0]) && SrcName[1]!=0 && !IsPathDiv(SrcName[1]))
+    {
+      bool Dot=SrcName[1]=='.' && (IsPathDiv(SrcName[2]) || SrcName[2]==0);
+      bool Dot2=SrcName[1]=='.' && SrcName[2]=='.' && (IsPathDiv(SrcName[3]) || SrcName[3]==0);
+      if (!Dot && !Dot2)
+        AllowedDepth++;
+    }
+    SrcName++;
+  }
+  if (IsFullRootPath(TargetName)) // Catch root dir based /path/file paths.
+    return false;
+  for (int Pos=0;*TargetName!=0;Pos++)
+  {
+    bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' && 
+              (IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
+              (Pos==0 || IsPathDiv(*(TargetName-1)));
+    if (Dot2)
+      AllowedDepth--;
+    TargetName++;
+  }
+  return AllowedDepth>=0;
+}
+
+
+bool ExtractLink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const char *LinkName,uint &LinkCRC,bool Create)
 {
 #if defined(SAVE_LINKS) && defined(_UNIX)
   char LinkTarget[NM];
@@ -13,6 +50,13 @@ bool ExtractLink(ComprDataIO &DataIO,Arc
     LinkTarget[DataSize]=0;
     if (Create)
     {
+      if (!Cmd->AbsoluteLinks && (IsFullRootPath(LinkTarget) ||
+          !IsRelativeSymlinkSafe(Arc.FileName,LinkTarget))) {
+        int NameSize=Min(DataSize,strlen(LinkTarget));
+        LinkCRC=CRC(0xffffffff,LinkTarget,NameSize);
+        return(false);
+      }
+
       CreatePath(LinkName,NULL,true);
       if (symlink(LinkTarget,LinkName)==-1) // Error.
         if (errno==EEXIST)
--- unrar-nonfree-4.1.4.orig/ulinks.hpp
+++ unrar-nonfree-4.1.4/ulinks.hpp
@@ -3,7 +3,7 @@
 
 void SaveLinkData(ComprDataIO &DataIO,Archive &TempArc,FileHeader &hd,
                   const char *Name);
-bool ExtractLink(ComprDataIO &DataIO,Archive &Arc,const char *LinkName,
+bool ExtractLink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const char *LinkName,
                  uint &LinkCRC,bool Create);
 
 #endif
