On 23.03.2015 23:15, Felix Geyer wrote: > It looks like upstream attempted to fix / work around the issue. > > From the WinRAR Version 5.21 changelog: > >> 4. Now by default WinRAR skips symbolic links with absolute paths >> in link target when extracting. You can enable creating such links >> with "Allow absolute paths in symbolic links" option on "Advanced" >> page of extraction dialog or with -ola command line switch. >> >> Such links pointing to folders outside of extraction destination >> folder can present a security risk. Enable their extraction only >> if you are sure that archive contents is safe, such as your own backup. > > The -ola switch and related changes are part of 5.2.5 but I can still > reproduce > the problem with this version.
I've notified upstream about the incomplete fix. Attached are patches for 5.0.10 and 5.2.5. Review would be appreciated. Cheers, Felix
--- unrar-nonfree-5.0.10.orig/extinfo.cpp +++ unrar-nonfree-5.0.10/extinfo.cpp @@ -60,6 +60,37 @@ void SetExtraInfo(CommandData *Cmd,Archi +bool IsRelativeSymlinkSafe(const wchar *SrcName,const wchar *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 ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) { #if defined(SAVE_LINKS) && defined(_UNIX) --- unrar-nonfree-5.0.10.orig/extinfo.hpp +++ unrar-nonfree-5.0.10/extinfo.hpp @@ -1,6 +1,7 @@ #ifndef _RAR_EXTINFO_ #define _RAR_EXTINFO_ +bool IsRelativeSymlinkSafe(const wchar *SrcName,const wchar *TargetName); bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName); #ifdef _UNIX void SetUnixOwner(Archive &Arc,const wchar *FileName); --- unrar-nonfree-5.0.10.orig/pathfn.cpp +++ unrar-nonfree-5.0.10/pathfn.cpp @@ -593,6 +593,12 @@ bool IsFullPath(const wchar *Path) } +bool IsFullRootPath(const wchar *Path) +{ + return IsFullPath(Path) || IsPathDiv(Path[0]); +} + + bool IsDiskLetter(const wchar *Path) { wchar Letter=etoupperw(Path[0]); --- unrar-nonfree-5.0.10.orig/pathfn.hpp +++ unrar-nonfree-5.0.10/pathfn.hpp @@ -31,6 +31,7 @@ wchar* UnixSlashToDos(wchar *SrcName,wch wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName=NULL,size_t MaxLength=NM); void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize); bool IsFullPath(const wchar *Path); +bool IsFullRootPath(const wchar *Path); bool IsDiskLetter(const wchar *Path); void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize); int ParseVersionFileName(wchar *Name,bool Truncate); --- unrar-nonfree-5.0.10.orig/ulinks.cpp +++ unrar-nonfree-5.0.10/ulinks.cpp @@ -24,6 +24,12 @@ static bool UnixSymlink(const char *Targ } +static bool IsFullPath(const char *PathA) // Unix ASCII version. +{ + return *PathA==CPATHDIVIDER; +} + + bool ExtractUnixLink30(ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) { char Target[NM]; @@ -42,6 +48,9 @@ bool ExtractUnixLink30(ComprDataIO &Data if (!DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL)) return true; + if (IsFullPath(Target) || !IsRelativeSymlinkSafe(Arc.FileHead.FileName,Arc.FileHead.RedirName)) + return false; + return UnixSymlink(Target,LinkName); } return false; @@ -55,10 +64,14 @@ bool ExtractUnixLink50(const wchar *Name if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_JUNCTION) { // Cannot create Windows absolute path symlinks in Unix. Only relative path - // Windows symlinks can be created here. - if (strncmp(Target,"\\??\\",4)==0) + // Windows symlinks can be created here. RAR 5.0 used \??\ prefix + // for Windows absolute symlinks, since RAR 5.1 /??/ is used. + // We escape ? as \? to avoid "trigraph" warning + if (strncmp(Target,"\\??\\",4)==0 || strncmp(Target,"/\?\?/",4)==0) return false; DosSlashToUnix(Target,Target,ASIZE(Target)); } + if (IsFullPath(Target) || !IsRelativeSymlinkSafe(hd->FileName,hd->RedirName)) + return false; return UnixSymlink(Target,Name); }
--- unrar-nonfree-5.2.5.orig/ulinks.cpp +++ unrar-nonfree-5.2.5/ulinks.cpp @@ -56,6 +56,7 @@ bool ExtractUnixLink30(CommandData *Cmd, if (!Cmd->AbsoluteLinks && (IsFullPath(Target) || !IsRelativeSymlinkSafe(Arc.FileHead.FileName,Arc.FileHead.RedirName))) + return false; return UnixSymlink(Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime); }