summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/Memcached.pm47
-rw-r--r--memtaint.pl14
2 files changed, 60 insertions, 1 deletions
diff --git a/Bugzilla/Memcached.pm b/Bugzilla/Memcached.pm
index cdadf4601..f73623720 100644
--- a/Bugzilla/Memcached.pm
+++ b/Bugzilla/Memcached.pm
@@ -12,6 +12,7 @@ use strict;
use warnings;
use Bugzilla::Error;
+use Bugzilla::Util qw(trick_taint);
use Scalar::Util qw(blessed);
use URI::Escape;
use Encode;
@@ -246,7 +247,51 @@ sub _get {
$key = $self->_encode_key($key)
or return;
- return $self->{memcached}->get($key);
+ my $value = $self->{memcached}->get($key);
+ return unless defined $value;
+
+ # detaint returned values
+ # hashes and arrays are detainted just one level deep
+ if (ref($value) eq 'HASH') {
+ _detaint_hashref($value);
+ }
+ elsif (ref($value) eq 'ARRAY') {
+ foreach my $value (@$value) {
+ next unless defined $value;
+ # arrays of hashes and arrays are common
+ if (ref($value) eq 'HASH') {
+ _detaint_hashref($value);
+ }
+ elsif (ref($value) eq 'ARRAY') {
+ _detaint_arrayref($value);
+ }
+ elsif (!ref($value)) {
+ trick_taint($value);
+ }
+ }
+ }
+ elsif (!ref($value)) {
+ trick_taint($value);
+ }
+ return $value;
+}
+
+sub _detaint_hashref {
+ my ($hashref) = @_;
+ foreach my $value (values %$hashref) {
+ if (defined($value) && !ref($value)) {
+ trick_taint($value);
+ }
+ }
+}
+
+sub _detaint_arrayref {
+ my ($arrayref) = @_;
+ foreach my $value (@$arrayref) {
+ if (defined($value) && !ref($value)) {
+ trick_taint($value);
+ }
+ }
}
sub _delete {
diff --git a/memtaint.pl b/memtaint.pl
new file mode 100644
index 000000000..54072dc49
--- /dev/null
+++ b/memtaint.pl
@@ -0,0 +1,14 @@
+use Cache::Memcached::Fast;
+use Devel::Peek;
+
+my $mc = Cache::Memcached::Fast->new( { servers => ['127.0.0.1:11211'] });
+
+my $v=[$ENV{PATH}];
+
+Dump($v->[0]);
+
+$mc->set("taint", $v);
+
+Dump($v->[0]);
+
+Dump($mc->get("taint")->[0]);