[SCM] Debian package checker branch, squeeze, updated. 2.4.3-16-gddd5248
The following commit has been merged in the squeeze branch:
commit f8789fa30740be704d5d04d69d8a38e259e4525d
Author: Niels Thykier <niels@thykier.net>
Date: Fri Apr 5 16:20:14 2013 +0200
checks/*: Check for symlinks before opening files
Signed-off-by: Niels Thykier <niels@thykier.net>
diff --git a/checks/cruft b/checks/cruft
index 34ab8d9..05e2ad2 100644
--- a/checks/cruft
+++ b/checks/cruft
@@ -313,6 +313,10 @@ sub find_cruft {
}
}
-f or return; # we just need normal files for the rest
+ if (-l && !is_ancestor_of($info->unpacked, $_)) {
+ # skip unsafe symlinks too
+ return;
+ }
unless ($warned->{$name}) {
for my $rule (@file_checks) {
diff --git a/checks/debhelper b/checks/debhelper
index 56bbc00..54c9a2d 100644
--- a/checks/debhelper
+++ b/checks/debhelper
@@ -70,10 +70,16 @@ my $seendhcleank = '';
my $overridetargets = 0;
my %missingbdeps;
+if ( ! -f "debfiles/rules" or !is_ancestor_of("debfiles", "debfiles/rules")) {
+ # unsafe symlink
+ return;
+}
+
open(RULES, '<', "debfiles/rules") or fail("cannot read debian/rules: $!");
my $maybe_skipping;
my $dhcompatvalue;
my @versioncheck;
+
while (<RULES>) {
if (/^ifn?(eq|def)\s/) {
$maybe_skipping++;
@@ -244,6 +250,7 @@ opendir(DEBIAN, 'debfiles')
while (defined(my $file=readdir(DEBIAN))) {
if ($file =~ m/^(?:(.*)\.)?(?:post|pre)(?:inst|rm)$/) {
next unless $needtomodifyscripts;
+ next unless is_ancestor_of("debfiles", "debfiles/$file");
# They need to have #DEBHELPER# in their scripts. Search for scripts
# that look like maintainer scripts and make sure the token is there.
@@ -310,6 +317,8 @@ while (defined(my $file=readdir(DEBIAN))) {
# supported.
if ($filename_configs->known($base)) {
next if $level < 3;
+ next unless is_ancestor_of("debfiles", "debfiles/$file");
+
open (IN, '<', "debfiles/$file")
or fail("Can't open debfiles/$file: $!");
local $_;
diff --git a/checks/infofiles b/checks/infofiles
index 2c5b994..1bb8061 100644
--- a/checks/infofiles
+++ b/checks/infofiles
@@ -87,6 +87,10 @@ foreach my $file (sort keys %{$info->index}) {
# If this is the main info file (no numeric extension). make sure it has
# appropriate dir entry information.
if ($fname !~ /-\d+\.gz/ && $file_info =~ /gzip compressed data/) {
+ if ($index_info->{type} eq 'l' && !is_ancestor_of("unpacked", $file)) {
+ # unsafe symlink, skip
+ next;
+ }
my $pid = open INFO, '-|';
if (not defined $pid) {
fail("cannot fork: $!");
diff --git a/checks/init.d b/checks/init.d
index 5454286..fb8e33d 100644
--- a/checks/init.d
+++ b/checks/init.d
@@ -21,6 +21,9 @@
package Lintian::init_d;
use strict;
use Util;
+
+use File::Basename qw(dirname);
+use Lintian::Check qw($PKGNAME_REGEX);
use Lintian::Tags qw(tag);
# A list of valid LSB keywords. The value is 0 if optional and 1 if required.
@@ -220,6 +223,11 @@ sub check_init {
if ($target =~ m,(?:\A|/)lib/init/upstart-job\z,) {
return;
}
+ if (!is_ancestor_of(dirname($initd_file), $initd_file)) {
+ # unsafe symlink, skip. NB: dirname($initd_file) is safe
+ # because coll/init.d does sanity checking for us.
+ return;
+ }
}
open(IN, '<', $initd_file)
or fail("cannot open init.d file $initd_file: $!");
diff --git a/checks/menu-format b/checks/menu-format
index bbb4bc8..eaa1a4f 100644
--- a/checks/menu-format
+++ b/checks/menu-format
@@ -428,6 +428,7 @@ foreach my $menufile (@menufiles) {
$fullname = "/usr/lib/menu/$basename" if $menufile =~ m,^menu/lib/,o;
next if $basename eq "README"; # README is a special case
+ next if !is_ancestor_of('menu', $menufile);
my $menufile_line ="";
open (IN, '<', $menufile) or
@@ -704,12 +705,19 @@ sub VerifyIcon {
$iconfile = "unpacked/usr/share/pixmaps/$icon";
}
- if (! open (IN, '<', $iconfile)) {
- tag "menu-icon-missing", "$icon";
- return;
+ if (-e $iconfile) {
+ if (!is_ancestor_of("unpacked", $iconfile)) {
+ # unsafe symlink
+ return;
+ }
+ } else {
+ tag 'menu-icon-missing', $icon;
+ return;
}
- my $parse = "XPM header";
+ open (IN, '<', $iconfile) or fail "open $iconfile: $!";
+
+ my $parse = 'XPM header';
my $line;
do { defined ($line = <IN>) or goto parse_error; }
until ($line =~ /\/\*\s*XPM\s*\*\//);
diff --git a/checks/menus b/checks/menus
index 08622ac..b915c8e 100644
--- a/checks/menus
+++ b/checks/menus
@@ -190,7 +190,8 @@ if ($docbase_file) {
my $dbfile;
while (defined ($dbfile = readdir DOCBASEDIR)) {
# don't try to parse executables, plus we already warned about it
- next if -x "doc-base/$dbfile";
+ # - skip symlinks as well, unlikely to be used for real doc-base files.
+ next if -x "doc-base/$dbfile" or -l "doc-base/$dbfile";
check_doc_base_file($dbfile, $pkg, $type, \%all_files, \%all_links);
}
closedir DOCBASEDIR;
diff --git a/checks/patch-systems b/checks/patch-systems
index 9934d46..ae521fe 100644
--- a/checks/patch-systems
+++ b/checks/patch-systems
@@ -47,16 +47,25 @@ sub run {
my $quilt_format = ($format =~ /3\.\d+ \(quilt\)/) ? 1 : 0;
my $cwd = realpath('.');
+ if (!is_ancestor_of("debfiles", "debfiles/patches")) {
+ # skip, bad symlink
+ return;
+ }
#----- dpatch
if ($build_deps->implies("dpatch")) {
$uses_patch_system++;
#check for a debian/patches file:
- if (! -r "debfiles/patches/00list") {
+ if (-l "debfiles/patches/00list"
+ and not is_ancestor_of("debfiles", "debfiles/patches/00list")) {
+ # skip
+ } elsif (! -r "debfiles/patches/00list") {
tag "dpatch-build-dep-but-no-patch-list";
} else {
my $list_uses_cpp = 0;
- if (open(OPTS, '<', "debfiles/patches/00options")) {
+ if (-f "debian/patches/00options"
+ && is_ancestor_of("debfiles", "debfiles/patches/00options")) {
+ open(OPTS, '<', "debfiles/patches/00options") or fail "open 00options: $!";
while(<OPTS>) {
if (/DPATCH_OPTION_CPP=1/) {
$list_uses_cpp = 1;
@@ -67,7 +76,8 @@ sub run {
}
foreach my $listfile (glob("debfiles/patches/00list*")) {
my @patches;
- if (open(IN, '<', "$listfile")) {
+ if ( -f $listfile && is_ancestor_of("debfiles", $listfile)) {
+ open(IN, '<', "$listfile") or fail "open $listfile: $!";
while(<IN>) {
chomp;
next if (/^\#/); #ignore comments or CPP directive
@@ -119,7 +129,10 @@ sub run {
if ($build_deps->implies("quilt") or $quilt_format) {
$uses_patch_system++;
#check for a debian/patches file:
- if (! -r "debfiles/patches/series") {
+ if (-l "debfiles/patches/series" and
+ not is_ancestor_of("debfiles", "debfiles/patches/series")) {
+ # skip
+ } elsif (! -r "debfiles/patches/series") {
tag "quilt-build-dep-but-no-series-file" unless $quilt_format;
} else {
if (open(IN, '<', "debfiles/patches/series")) {
@@ -174,13 +187,18 @@ sub run {
if (-r "debfiles/patches/series" and
-f "debfiles/patches/series") {
# 3.0 (quilt) sources don't need quilt as dpkg-source will do the work
- tag "quilt-series-but-no-build-dep" unless $quilt_format;
+ if (! -l "debfiles/patches/series"
+ or is_ancestor_of("defiles", "debfiles/patches/series")) {
+ tag "quilt-series-but-no-build-dep" unless $quilt_format;
+ }
}
}
#----- look for README.source
if ($uses_patch_system && ! $quilt_format && ! -f 'debfiles/README.source') {
- tag "patch-system-but-no-source-readme";
+ if (! -l "debfiles/README.source") {
+ tag "patch-system-but-no-source-readme";
+ }
}
#----- general cruft checking:
diff --git a/checks/po-debconf b/checks/po-debconf
index 902c4ee..8c878d6 100644
--- a/checks/po-debconf
+++ b/checks/po-debconf
@@ -39,6 +39,7 @@ my $has_template = my $has_depends = my $has_config = 0;
my @lang_templates;
for my $file (readdir(DEB)) {
next if -d "debfiles/$file";
+ next if !is_ancestor_of("debfiles", "debfiles/$file");
if ($file =~ m/^(.+\.)?templates(\..+)?$/) {
if ($file =~ m/templates\.\w\w(_\w\w)?$/) {
push (@lang_templates, $file);
@@ -70,6 +71,10 @@ closedir(DEB);
#TODO: check whether all templates are named in TEMPLATES.pot
if ( $has_template ) {
+ if ( -l "debfiles/po" and !is_ancestor_of("debfiles", "debfiles/po")) {
+ # debian/po is an unsafe symlink - lets stop here.
+ return;
+ }
if ( ! -d "debfiles/po" ) {
tag "not-using-po-debconf", "";
return 0;
@@ -89,7 +94,7 @@ for (@lang_templates) {
# check).
my $missing_files = 0;
my $yada = 0;
-if (open (RULES, '<', 'debfiles/rules')) {
+if ( ! -l "debfiles/rules" and open (RULES, '<', 'debfiles/rules')) {
local $_;
while (<RULES>) {
if (m%^\t\s*(?:perl debian/)?yada\s%) {
@@ -99,7 +104,7 @@ if (open (RULES, '<', 'debfiles/rules')) {
}
}
-if (!$yada && -f "debfiles/po/POTFILES.in") {
+if (!$yada && -f "debfiles/po/POTFILES.in" and ! -l "debfiles/po/POTFILES.in") {
open(POTFILES, '<', "debfiles/po/POTFILES.in")
or fail("Can't open debfiles/po/POTFILES.in.");
while (<POTFILES>) {
@@ -118,7 +123,7 @@ if (!$yada && -f "debfiles/po/POTFILES.in") {
tag "missing-potfiles-in", "";
$missing_files = 1;
}
-if (! -f "debfiles/po/templates.pot") {
+if (! -f "debfiles/po/templates.pot" and ! -l "debfiles/po/templates.pot") {
tag "missing-templates-pot", "";
$missing_files = 1;
}
@@ -146,6 +151,8 @@ while (defined(my $file=readdir(DEBIAN))) {
unless ($file =~ /^[a-z]{2,3}(_[A-Z]{2})?\.po$/);
local ($/) = "\n\n";
$_ = '';
+ next if -l "debfiles/po/$file" or ! -f "debfiles/po/$file";
+
open(PO, '<', "debfiles/po/$file")
or fail("Can't open debfiles/po/$file file.");
while (<PO>) {
diff --git a/checks/rules b/checks/rules
index 358db41..91b9209 100644
--- a/checks/rules
+++ b/checks/rules
@@ -110,7 +110,7 @@ my $info = shift;
# all the tests if we then can't read it.
if (-l "debfiles/rules") {
tag "debian-rules-is-symlink", "";
- return 0 unless -f "debfiles/rules";
+ return 0 unless -f "debfiles/rules" and is_ancestor_of("debfiles", "debfiles/rules");
}
#get architecture field:
diff --git a/checks/shared-libs b/checks/shared-libs
index dbe78a2..e374239 100644
--- a/checks/shared-libs
+++ b/checks/shared-libs
@@ -279,7 +279,9 @@ for (keys %SONAME) {
}
@shlibs = grep { !$unversioned_shlibs{$_} } keys %SONAME;
-if ($#shlibs == -1) {
+if (-l 'control/shlibs') {
+ # control files are not symlinks, skip this part.
+} elsif ($#shlibs == -1) {
# no shared libraries included in package, thus shlibs control file should
# not be present
if (-f 'control/shlibs') {
@@ -357,7 +359,9 @@ if ($#shlibs == -1) {
# 5th step: check symbols control file. Add back in the unversioned shared
# libraries, since they can still have symbols files.
-if ($#shlibs == -1 and not %unversioned_shlibs) {
+if (-l 'control/symbols') {
+ # control files are not symlinks, skip this part.
+} elsif ($#shlibs == -1 and not %unversioned_shlibs) {
# no shared libraries included in package, thus symbols control file should
# not be present
if (-f 'control/symbols') {
diff --git a/checks/watch-file b/checks/watch-file
index aa11b7a..0e8f453 100644
--- a/checks/watch-file
+++ b/checks/watch-file
@@ -25,6 +25,7 @@ use strict;
use Lintian::Collect;
use Lintian::Tags qw(tag);
+use Util;
sub run {
@@ -32,6 +33,9 @@ my $pkg = shift;
my $type = shift;
my $info = shift;
+if (-l "debfiles/watch") {
+ return unless is_ancestor_of("debfiles", "debfiles/watch");
+}
if (! -f "debfiles/watch") {
tag 'debian-watch-file-is-missing' unless ($info->native);
return;
diff --git a/debian/changelog b/debian/changelog
index 42eaa23..962f449 100755
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,7 @@
lintian (2.4.3+squeeze2) stable; urgency=low
+ * checks/*:
+ + [NT] Avoid following unsafe symlinks.
* checks/debconf:
+ [NT] Fix several path traversal issues that could leak
information about the host system.
--
Debian package checker
Reply to: