[Rt-commit] rt branch, 3.8-trunk, updated. rt-3.8.7-150-gd5488e7

sartak at bestpractical.com sartak at bestpractical.com
Tue Feb 9 16:47:05 EST 2010


The branch, 3.8-trunk has been updated
       via  d5488e7f2d7de7e27eb5be9f5b78323adbdcc07d (commit)
      from  14b2119fe023c4174c4ad6a6dfe13300a9184607 (commit)

Summary of changes:
 lib/RT/Interface/Web.pm              |   53 +++++++++++++++++++++++++---------
 share/html/NoAuth/images/autohandler |    3 +-
 2 files changed, 41 insertions(+), 15 deletions(-)

- Log -----------------------------------------------------------------
commit d5488e7f2d7de7e27eb5be9f5b78323adbdcc07d
Author: Shawn M Moore <sartak at bestpractical.com>
Date:   Tue Feb 9 16:46:11 2010 -0500

    Analyze the path logically without consulting the filesystem

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index b38faa1..2fb9701 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -554,27 +554,51 @@ sub StaticFileHeaders {
     # $HTML::Mason::Commands::r->headers_out->{'Last-Modified'} = $date->RFC2616;
 }
 
-=head2 FileExistsInCompRoots
+=head2 PathIsSafe
 
-Takes a C<< File => path >> and returns the path of first Mason comp root
-that the file lives under, or C<undef> if none exist.
+Takes a C<< Path => path >> and returns a boolean indicating that
+the path is safely within RT's control or not. The path I<must> be
+relative.
+
+This function does not consult the filesystem at all; it is merely
+a logical sanity checking of the path. This explicitly does not handle
+symlinks; if you have symlinks in RT's webroot pointing outside of it,
+then we assume you know what you are doing.
 
 =cut
 
-sub FileExistsInCompRoots {
+sub PathIsSafe {
     my $self = shift;
     my %args = @_;
-    my $file = $args{File};
-
-    require Cwd;
-    my $realpath = Cwd::realpath($file);
-
-    for my $comp_root ($HTML::Mason::Commands::m->interp->comp_root_array) {
-        my ($name, $rootdir) = @$comp_root;
-        return $rootdir if $realpath =~ /^\Q$rootdir\E(?=\/|$)/;
+    my $path = $args{Path};
+
+    # Get File::Spec to clean up extra /s, ./, etc
+    my $cleaned_up = File::Spec->canonpath($path);
+
+    # Forbid too many ..s. We can't just sum then check because
+    # "../foo/bar/baz" should be illegal even though it has more
+    # downdirs than updirs. So as soon as we get a negative score
+    # (which means "breaking out" of the top level) we reject the path.
+
+    my @components = split '/', $cleaned_up;
+    my $score = 0;
+    for my $component (@components) {
+        if ($component eq '..') {
+            $score--;
+            if ($score < 0) {
+                $RT::Logger->info("Rejecting unsafe path: $file");
+                return 0;
+            }
+        }
+        elsif ($component eq '.' || $component eq '') {
+            # these two have no effect on $score
+        }
+        else {
+            $score++;
+        }
     }
 
-    return undef;
+    return 1;
 }
 
 =head2 SendStaticFile 
@@ -594,8 +618,9 @@ sub SendStaticFile {
     my %args = @_;
     my $file = $args{File};
     my $type = $args{Type};
+    my $relfile = $args{RelativeFile};
 
-    if (!$self->FileExistsInCompRoots(File => $file)) {
+    if (defined($relfile) && !$self->PathIsSafe(Path => $relfile)) {
         $HTML::Mason::Commands::r->status(400);
         $HTML::Mason::Commands::m->abort;
     }
diff --git a/share/html/NoAuth/images/autohandler b/share/html/NoAuth/images/autohandler
index 431a44f..7abf8b8 100644
--- a/share/html/NoAuth/images/autohandler
+++ b/share/html/NoAuth/images/autohandler
@@ -3,5 +3,6 @@
 # properly configured their webserver to stop RT from passing 
 # images through the mason handler.
 my $file = $m->base_comp->source_file;
-RT::Interface::Web->SendStaticFile( File => $file );
+my $relfile = $m->base_comp->path;
+RT::Interface::Web->SendStaticFile( File => $file, RelativeFile => $relfile );
 </%INIT>

-----------------------------------------------------------------------


More information about the Rt-commit mailing list