improve fix for symlink attacks to check subdirectories for symlinks too
authorjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Wed, 29 Mar 2006 18:50:36 +0000 (18:50 +0000)
committerjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Wed, 29 Mar 2006 18:50:36 +0000 (18:50 +0000)
before writing

IkiWiki/CGI.pm
IkiWiki/Render.pm
doc/security.mdwn
ikiwiki

index b47c8e8038d1c1d00a4d70b3c7349610e8702b19..f360b6778d9c78c1a227d755aa6b4f03e0d76018 100644 (file)
@@ -425,7 +425,7 @@ sub cgi_editpage ($$) { #{{{
                my $content=$form->field('content');
                $content=~s/\r\n/\n/g;
                $content=~s/\r/\n/g;
-               writefile("$config{srcdir}/$file", $content);
+               writefile($file, $config{srcdir}, $content);
                
                my $message="web commit ";
                if (length $session->param("name")) {
index 3d827d341e45f0c654d4c12aaf0d546ebdb6b8b3..9e340c26e162abe5623524d4b4ced32942e6c834 100644 (file)
@@ -349,7 +349,7 @@ sub render ($) { #{{{
                $content=htmlize($type, $content);
                
                check_overwrite("$config{destdir}/".htmlpage($page), $page);
-               writefile("$config{destdir}/".htmlpage($page),
+               writefile(htmlpage($page), $config{destdir},
                        genpage($content, $page, mtime($srcfile)));
                $oldpagemtime{$page}=time;
                $renderedfiles{$page}=htmlpage($page);
@@ -358,14 +358,14 @@ sub render ($) { #{{{
                # check_overwrite, as above, but currently renderedfiles
                # only supports listing one file per page.
                if ($config{rss} && exists $inlinepages{$page}) {
-                       writefile("$config{destdir}/".rsspage($page),
+                       writefile(rsspage($page), $config{destdir},
                                genrss($content, $page, mtime($srcfile)));
                }
        }
        else {
                $links{$file}=[];
                check_overwrite("$config{destdir}/$file", $file);
-               writefile("$config{destdir}/$file", $content);
+               writefile($file, $config{destdir}, $content);
                $oldpagemtime{$file}=time;
                $renderedfiles{$file}=$file;
        }
index 0f8861d0dbb6f99f5857828f5bd71f7453048d66..3743adea1e61b5225520d4f889b80d0208ad0ca3 100644 (file)
@@ -161,7 +161,8 @@ page from the web, which follows the symlink when reading the page, and
 again when saving the changed page.
 
 This was fixed by making ikiwiki refuse to read or write to files that are
-symlinks, combined with the above locking.
+symlinks, or that are in subdirectories that are symlinks, combined with
+the above locking.
 
 ## underlaydir override attacks
 
diff --git a/ikiwiki b/ikiwiki
index 4ef6ceba39d3e7cb07dd32ea27dc27bade27bdf4..b1bc9984f2bd9475787808d65f886424c250e7cc 100755 (executable)
--- a/ikiwiki
+++ b/ikiwiki
@@ -202,15 +202,20 @@ sub readfile ($) { #{{{
        return $ret;
 } #}}}
 
-sub writefile ($$) { #{{{
-       my $file=shift;
+sub writefile ($$$) { #{{{
+       my $file=shift; # can include subdirs
+       my $destdir=shift; # directory to put file in
        my $content=shift;
        
-       if (-l $file) {
-               error("cannot write to a symlink ($file)");
+       my $test=$file;
+       while (length $test) {
+               if (-l "$destdir/$test") {
+                       error("cannot write to a symlink ($test)");
+               }
+               $test=dirname($test);
        }
 
-       my $dir=dirname($file);
+       my $dir=dirname("$destdir/$file");
        if (! -d $dir) {
                my $d="";
                foreach my $s (split(m!/+!, $dir)) {
@@ -221,7 +226,7 @@ sub writefile ($$) { #{{{
                }
        }
        
-       open (OUT, ">$file") || error("failed to write $file: $!");
+       open (OUT, ">$destdir/$file") || error("failed to write $destdir/$file: $!");
        print OUT $content;
        close OUT;
 } #}}}