File Coverage

checks/binaries.pm
Criterion Covered Total %
statement 317 331 95.7
branch 203 248 81.8
condition 96 148 64.8
subroutine 18 18 100.0
total 634 745 85.1


line stmt bran cond sub time code
1           # binaries -- lintian check script -*- perl -*-
2            
3           # Copyright (C) 1998 Christian Schwarz and Richard Braakman
4           # Copyright (C) 2012 Kees Cook
5           #
6           # This program is free software; you can redistribute it and/or modify
7           # it under the terms of the GNU General Public License as published by
8           # the Free Software Foundation; either version 2 of the License, or
9           # (at your option) any later version.
10           #
11           # This program is distributed in the hope that it will be useful,
12           # but WITHOUT ANY WARRANTY; without even the implied warranty of
13           # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14           # GNU General Public License for more details.
15           #
16           # You should have received a copy of the GNU General Public License
17           # along with this program. If not, you can find it on the World Wide
18           # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
19           # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20           # MA 02110-1301, USA.
21            
22           package Lintian::binaries;
23 2968     2968 26534 use strict;
  2968       8753  
  2968       125154  
24 2968     2968 23327 use warnings;
  2968       8296  
  2968       144804  
25 2968     2968 37207 use autodie;
  2968       8197  
  2968       27026  
26            
27 2968       351934 use constant NUMPY_REGEX => qr/
28           \Qmodule compiled against ABI version \E (?:0x)?%x
29           \Q but this version of numpy is \E (?:0x)?%x
30 2968     2968 29144901 /xo;
  2968       10166  
31            
32           # These are the ones file(1) looks for. The ".zdebug_info" being the
33           # compressed version of .debug_info.
34           # - Technically, file(1) also looks for .symtab, but that is apparently
35           # not strippable for static libs. Accordingly, it is omitted below.
36 2968     2968 26910 use constant DEBUG_SECTIONS => qw(.debug_info .zdebug_info);
  2968       9704  
  2968       320011  
37            
38 2968     2968 26861 use File::Spec;
  2968       11071  
  2968       67878  
39 2968     2968 146782 use List::MoreUtils qw(any);
  2968       9245  
  2968       136748  
40            
41 2968     2968 4638645 use Lintian::Check qw(check_spelling spelling_tag_emitter);
  2968       12963  
  2968       343217  
42 2968     2968 31146 use Lintian::Data;
  2968       8910  
  2968       20753  
43 2968     2968 128357 use Lintian::Relation qw(:constants);
  2968       9139  
  2968       658713  
44 2968     2968 26987 use Lintian::Tags qw(tag);
  2968       8688  
  2968       192013  
45 2968     2968 24984 use Lintian::Util qw(fail slurp_entire_file strip);
  2968       8465  
  2968       25289786  
46            
47           my $ARCH_REGEX = Lintian::Data->new('binaries/arch-regex', qr/\s*\~\~/o,
48           sub { return qr/$_[1]/ });
49           my $ARCH_64BIT_EQUIVS
50           = Lintian::Data->new('binaries/arch-64bit-equivs', qr/\s*\=\>\s*/);
51            
52           sub _embedded_libs {
53 16800     16800 44955 my ($key, $val, undef) = @_;
54 16800       59501 my $result = {'libname' => $key,};
55 16800       82406 my ($opts, $regex) = split m/\|\|/, $val, 2;
56 16800 100     52569 if (!$regex) {
57 10640       21268 $regex = $opts;
58 10640       22423 $opts = '';
59           } else {
60 6160       23587 strip($opts);
61 6160       29977 foreach my $optstr (split m/\s++/, $opts) {
62 6160       24907 my ($opt, $val) = split m/=/, $optstr, 2;
63 6160 100 66   45976 if ($opt eq 'source' or $opt eq 'libname') {
    50        
64 840       3650 $result->{$opt} = $val;
65           } elsif ($opt eq 'source-regex') {
66 5320       135825 $result->{$opt} = qr/$val/;
67           } else {
68 0       0 fail( "Unknown option $opt used for $key"
69           . ' (in binaries/embedded-libs)');
70           }
71           }
72           }
73            
74 16800 50 66   81768 if (defined $result->{'source'} and $result->{'source-regex'}) {
75 0       0 fail( "Both source and source-regex used for $key"
76           . ' (in binaries/embedded-libs)');
77           } else {
78 16800 100     69112 $result->{'source'} = $key unless defined $result->{'source'};
79           }
80            
81 16800       393171 $result->{'match'} = qr/$regex/;
82            
83 16800       108043 return $result;
84           }
85            
86           our $EMBEDDED_LIBRARIES
87           = Lintian::Data->new('binaries/embedded-libs', qr/\s*+\|\|/,
88           \&_embedded_libs);
89            
90           our $MULTIARCH_DIRS = Lintian::Data->new('common/multiarch-dirs', qr/\s++/);
91            
92           sub _split_hash {
93 261250     261250 640694 my (undef, $val) = @_;
94 261250       595095 my $hash = {};
95 261250       2708210 map { $hash->{$_} = 1 } split m/\s*,\s*/o, $val;
  1058200       3012230  
96 261250       1018762 return $hash;
97           }
98            
99           our $HARDENING= Lintian::Data->new('binaries/hardening-tags', qr/\s*\|\|\s*/o,
100           \&_split_hash);
101           our $HARDENED_FUNCTIONS = Lintian::Data->new('binaries/hardened-functions');
102           our $LFS_SYMBOLS = Lintian::Data->new('binaries/lfs-symbols');
103            
104           our $ARCH_32_REGEX;
105            
106           sub run {
107 5591     5591 30459 my ($pkg, $type, $info, $proc, $group) = @_;
108            
109 5591       31886 my ($madir, %directories, $built_with_golang, %SONAME);
110 5591       0 my ($arch_hardening, $gnu_triplet_re, $ruby_triplet_re);
111 5591       26893 my $needs_libc = '';
112 5591       28800 my $needs_libcxx = '';
113 5591       18609 my $needs_libc_file;
114           my $needs_libcxx_file;
115 5591       17531 my $needs_libc_count = 0;
116 5591       16951 my $needs_libcxx_count = 0;
117 5591       17743 my $needs_depends_line = 0;
118 5591       16337 my $has_perl_lib = 0;
119 5591       16622 my $has_php_ext = 0;
120 5591       15930 my $uses_numpy_c_abi = 0;
121            
122 5591       43144 my $arch = $info->field('architecture', '');
123 5591       31299 my $multiarch = $info->field('multi-arch', 'no');
124 5591       40222 my $srcpkg = $proc->pkg_src;
125            
126 5591 100     68301 $arch_hardening = $HARDENING->value($arch)
127           if $arch ne 'all';
128            
129 5591       48403 my $src = $group->get_source_processable;
130 5591 100     31213 if (defined($src)) {
131 5522       33656 $built_with_golang
132           = $src->info->relation('build-depends')
133           ->implies('golang-go | golang-any');
134           }
135            
136 5591       24432 foreach my $file (sort keys %{$info->objdump_info}) {
  5591       51666  
137 1461       8057 my $objdump = $info->objdump_info->{$file};
138 1461       3840 my ($has_lfs, %unharded_functions, @hardened_functions);
139 1461       3531 my $is_profiled = 0;
140           # $file can be an object inside a static lib. These do
141           # not appear in the output of our file_info collection.
142 1461   100   8792 my $file_info = $info->file_info($file) // '';
143            
144           # The LFS check only works reliably for ELF files due to the
145           # architecture regex.
146 1461 100     15353 if ($file_info =~ m/^[^,]*\bELF\b/o) {
147           # Only 32bit ELF binaries can lack LFS.
148 1314 100     7231 $ARCH_32_REGEX = $ARCH_REGEX->value('32')
149           unless defined $ARCH_32_REGEX;
150 1314 100     8394 $has_lfs = 1 unless $file_info =~ m/$ARCH_32_REGEX/o;
151           # We don't care if it is a debug file
152 1314 100     6259 $has_lfs = 1 if $file =~ m,^usr/lib/debug/,;
153           }
154            
155 1461 100     6048 if (defined $objdump->{SONAME}) {
156 383       995 foreach my $soname (@{$objdump->{SONAME}}) {
  383       1833  
157 383   100   5495 $SONAME{$soname} ||= [];
158 383       1007 push @{$SONAME{$soname}}, $file;
  383       2058  
159           }
160           }
161 1461       3246 foreach my $symbol (@{$objdump->{SYMBOLS}}) {
  1461       5440  
162 10721       20355 my ($foo, $sec, $sym) = @{$symbol};
  10721       41549  
163            
164 10721 100     35814 if ($foo eq 'UND') {
165 10135       20368 my $name = $sym;
166 10135       18438 my $hardened;
167 10135 100     38184 $hardened = 1 if $name =~ s/^__(\S+)_chk$/$1/;
168 10135 100     39758 if ($HARDENED_FUNCTIONS->known($name)) {
169 664 100     2078 if ($hardened) {
170 637       2089 push(@hardened_functions, $name);
171           } else {
172 27       108 $unharded_functions{$name} = 1;
173           }
174           }
175            
176           }
177            
178 10721 50     32643 unless (defined $has_lfs) {
179 0 0 0   0 if ($foo eq 'UND' and $LFS_SYMBOLS->known($sym)) {
180           # Using a 32bit only interface call, some parts of the
181           # binary are built without LFS. If the symbol is defined
182           # within the binary then we ignore it
183 0       0 $has_lfs = 0;
184           }
185           }
186 10721 100     28700 next if $is_profiled;
187           # According to the binutils documentation[1], the profiling symbol
188           # can be named "mcount", "_mcount" or even "__mcount".
189           # [1] http://sourceware.org/binutils/docs/gprof/Implementation.html
190 10696 100 100   83903 if ($sec =~ /^GLIBC_.*/ and $sym =~ m{\A _?+ _?+ mcount \Z}xsm){
    50        
191 5       20 $is_profiled = 1;
192           } elsif ($arch ne 'hppa') {
193           # This code was used to detect profiled code in Wheezy
194           # (and earlier)
195 10691 50 100   42803 if ( $foo eq '.text'
      66      
196           and $sec eq 'Base'
197           and$sym eq '__gmon_start__') {
198 0       0 $is_profiled = 1;
199           }
200           }
201 10696 100     57169 tag 'binary-compiled-with-profiling-enabled', $file
202           if $is_profiled;
203           }
204 1461 50 100   7137 if ( %unharded_functions
      66      
      66      
205           and not @hardened_functions
206           and not $built_with_golang
207           and $arch_hardening->{'hardening-no-fortify-functions'}) {
208 9       81 tag 'hardening-no-fortify-functions', $file;
209           }
210            
211           tag 'apparently-corrupted-elf-binary', $file
212 1461 100     5584 if $objdump->{'ERRORS'};
213 1461 50 66   11165 tag 'binary-file-built-without-LFS-support', $file
214           if defined $has_lfs and not $has_lfs;
215 1461 100     7855 if ($objdump->{'BAD-DYNAMIC-TABLE'}) {
216 70 100     523 tag 'binary-with-bad-dynamic-table', $file
217           unless $file =~ m%^usr/lib/debug/%;
218           }
219           }
220            
221           # For the package naming check, filter out SONAMEs where all the
222           # files are at paths other than /lib, /usr/lib, or /usr/X11R6/lib.
223           # This avoids false positives with plugins like Apache modules,
224           # which may have their own SONAMEs but which don't matter for the
225           # purposes of this check. Also filter out nsswitch modules
226 5591       62615 $madir = $MULTIARCH_DIRS->value($arch);
227 5591 100     43062 if (not defined($madir)) {
228           # In the case that the architecture is "all" or unknown (or we do
229           # not know the multi-arch path for a known architecture) , we assume
230           # it the multi-arch path to be this (hopefully!) non-existent path to
231           # avoid warnings about uninitialized variables.
232 4433       28196 $madir = './!non-existent-path!/./';
233           }
234            
235 5591       32124 $gnu_triplet_re = quotemeta $madir;
236 5591       38290 $gnu_triplet_re =~ s,^i386,i[3-6]86,;
237 5591       19557 $ruby_triplet_re = $gnu_triplet_re;
238 5591       27906 $ruby_triplet_re =~ s,linux\\-gnu$,linux,;
239 5591       24232 $ruby_triplet_re =~ s,linux\\-gnu,linux\\-,;
240            
241           sub lib_soname_path {
242 345     345 1696 my ($dir, @paths) = @_;
243 345       1531 foreach my $path (@paths) {
244           next
245 360 50     2015 if $path
246           =~ m%^(?:usr/)?lib(?:32|64)?/libnss_[^.]+\.so(?:\.[0-9]+)$%;
247 360 100     2056 return 1 if $path =~ m%^lib/[^/]+$%;
248 349 100     4229 return 1 if $path =~ m%^usr/lib/[^/]+$%;
249 57 100 66   1897 return 1 if defined $dir && $path =~ m%lib/$dir/[^/]++$%;
250 46 50 33   961 return 1 if defined $dir && $path =~ m%usr/lib/$dir/[^/]++$%;
251           }
252 31       192 return 0;
253           }
254           my @sonames
255 5591       37183 = sort grep { lib_soname_path($madir, @{$SONAME{$_}}) } keys %SONAME;
  345       1182  
  345       2258  
256            
257           # try to identify transition strings
258 5591       24658 my $base_pkg = $pkg;
259 5591       26379 $base_pkg =~ s/c102\b//o;
260 5591       23423 $base_pkg =~ s/c2a?\b//o;
261 5591       21530 $base_pkg =~ s/\dg$//o;
262 5591       22059 $base_pkg =~ s/gf$//o;
263 5591       23753 $base_pkg =~ s/v[5-6]$//o; # GCC-5 / libstdc++6 C11 ABI breakage
264 5591       20825 $base_pkg =~ s/-udeb$//o;
265 5591       20676 $base_pkg =~ s/^lib64/lib/o;
266            
267 5591       22553 my $match_found = 0;
268 5591       27737 foreach my $expected_name (@sonames) {
269 314       1590 $expected_name =~ s/([0-9])\.so\./$1-/;
270 314       2362 $expected_name =~ s/\.so(?:\.|\z)//;
271 314       1217 $expected_name =~ s/_/-/g;
272            
273 314 100 100   2902 if ( (lc($expected_name) eq $pkg)
274           || (lc($expected_name) eq $base_pkg)) {
275 238       933 $match_found = 1;
276 238       883 last;
277           }
278           }
279            
280 5591 100 100   45023 tag 'package-name-doesnt-match-sonames', "@sonames"
281           if @sonames && !$match_found;
282            
283           # process all files in package
284 5591       77210 foreach my $file ($info->sorted_index) {
285 53062       307013 my ($fileinfo, $objdump, $fname);
286            
287 53062 100     189665 next if not $file->is_file;
288            
289 21470       492443 $fileinfo = $file->file_info;
290            
291           # binary or object file?
292           next
293 21470 100 100   355942 unless ($fileinfo =~ m/^[^,]*\bELF\b/)
294           or ($fileinfo =~ m/\bcurrent ar archive\b/);
295            
296           # Warn about Architecture: all packages that contain shared libraries.
297 1365 100     6521 if ($arch eq 'all') {
298 5       55 tag 'arch-independent-package-contains-binary-or-object',$file;
299           }
300            
301 1365       5971 $fname = $file->name;
302 1365 100     11995 if ($fname =~ m,^etc/,) {
303 5       35 tag 'binary-in-etc', $file;
304           }
305            
306 1365 100     6313 if ($fname =~ m,^usr/share/,) {
307 10       60 tag 'arch-dependent-file-in-usr-share', $file;
308           }
309            
310 1365 100     6749 if ($multiarch eq 'same') {
311 11 100     724 unless ($fname
312           =~ m,\b$gnu_triplet_re(?:\b|_)|/(?:$ruby_triplet_re|java-\d+-openjdk-\Q$arch\E|\.build-id)/,
313           ) {
314 5       45 tag 'arch-dependent-file-not-in-arch-specific-directory',$file;
315           }
316           }
317 1365 100     6568 if ($fileinfo =~ m/\bcurrent ar archive\b/) {
318            
319           # "libfoo_g.a" is usually a "debug" library, so ignore
320           # unneeded sections in those.
321 51 50     186 next if $file =~ m/_g\.a$/;
322            
323 51       579 $objdump = $info->objdump_info->{$file};
324            
325 51       299 foreach my $obj (@{ $objdump->{'objects'} }) {
  51       241  
326 96       354 my $libobj = $info->objdump_info->{"${file}(${obj})"};
327           # Shouldn't happen, but...
328 96 50     787 fail("object ($file $obj) in static lib is missing!?")
329           unless defined $libobj;
330            
331 96 100   182 918 if (any { exists($libobj->{'SH'}{$_}) } DEBUG_SECTIONS) {
  182       468  
332 10       40 tag 'unstripped-static-library', "${file}(${obj})";
333           } else {
334 86       218 tag_unneeded_sections(
335           'static-library-has-unneeded-section',
336           "${file}(${obj})", $libobj);
337           }
338           }
339           }
340            
341           # ELF?
342 1365 100     11020 next unless $fileinfo =~ m/^[^,]*\bELF\b/o;
343            
344 1314       8723 $objdump = $info->objdump_info->{$fname};
345            
346 1314 100 66   13529 if ($arch eq 'all' or not $ARCH_REGEX->known($arch)) {
347           # arch:all or unknown architecture - not much we can say here
348 5       35 1;
349           } else {
350 1309       6543 my $archre = $ARCH_REGEX->value($arch);
351 1309       3952 my $bad = 1;
352 1309 100 33   18431 if ($fileinfo =~ m/$archre/) {
    50 33      
    50        
    50        
    50        
353           # If it matches the architecture regex, it is good
354 1304       4670 $bad = 0;
355           } elsif ($fname =~ m,(?:^|/)lib(x?\d{2})/,
356           or $fname =~ m,^emul/ia(\d{2}),) {
357 0       0 my $bitre = $ARCH_REGEX->value($1);
358           # Special case - "old" multi-arch dirs
359 0 0 0   0 $bad = 0 if $bitre and $fileinfo =~ m/$bitre/;
360           } elsif ($fname =~ m,^usr/lib/debug/\.build-id/,) {
361           # Detached debug symbols could be for a biarch library.
362 0       0 $bad = 0;
363           } elsif ($ARCH_64BIT_EQUIVS->known($arch)
364           && $fname =~ m,^lib/modules/,) {
365 0       0 my $arch64re
366           = $ARCH_REGEX->value($ARCH_64BIT_EQUIVS->value($arch));
367           # Allow amd64 kernel modules to be installed on i386.
368 0 0     0 $bad = 0 if $fileinfo =~ m/$arch64re/;
369           } elsif ($arch eq 'amd64') {
370 5       45 my $arch32re = $ARCH_REGEX->value('i386');
371           # Ignore i386 binaries in amd64 packages for right now.
372 5 50     60 $bad = 0 if $fileinfo =~ m/$arch32re/;
373           }
374 1309 100     5333 tag 'binary-from-other-architecture', $file if $bad;
375           }
376            
377 1314       7939 my $strings = slurp_entire_file($info->strings($file));
378           my $exceptions = {
379 1314       7147 %{ $group->info->spelling_exceptions },
  1314       9273  
380           'teH' => 1, # From #711207
381           'tEH' => 1, # From #782902
382           'tEh' => 1, # From #782902, too
383           'ang' => 1, # The Go stdlib html/ package contains "ang;"
384           'writeN' => 1, # The Go stdlib text/tabwriter pkg contains "writeN"
385           'writeN' => 1, # The Go stdlib text/tabwriter pkg contains "writeN"
386           'ot' => 1, # The Go stdlib runtime/ package contains "ot"
387           };
388 1314       9630 my $tag_emitter
389           = spelling_tag_emitter('spelling-error-in-binary', $file);
390 1314       7469 check_spelling($strings, $exceptions, $tag_emitter, 0);
391            
392           # stripped?
393 1314 100     10576 if ($fileinfo =~ m,\bnot stripped\b,o) {
394           # Is it an object file (which generally cannot be
395           # stripped), a kernel module, debugging symbols, or
396           # perhaps a debugging package?
397 151 100 66   2902 unless ($fname =~ m,\.k?o$,
      66      
      100      
      66      
398           or $pkg =~ m/-dbg$/
399           or $pkg =~ m/debug/
400           or $fname =~ m,/lib/debug/,
401           or $fname =~ m,\.gox$,o) {
402 66 100 100   590 if ( $fileinfo =~ m/executable/
403           and $strings =~ m/^Caml1999X0[0-9][0-9]$/m) {
404           # Check for OCaml custom executables (#498138)
405 5       35 tag 'ocaml-custom-executable', $file;
406           } else {
407 61       342 tag 'unstripped-binary-or-object', $file;
408           }
409           }
410           } else {
411           # stripped but a debug or profiling library?
412 1163 100 66   37874 if (($fname =~ m,/lib/debug/,o) or ($fname =~ m,/lib/profile/,o)){
413 5       15 tag 'library-in-debug-or-profile-should-not-be-stripped',$file;
414           } else {
415           # appropriately stripped, but is it stripped enough?
416 1158       6607 tag_unneeded_sections('binary-has-unneeded-section', $file,
417           $objdump);
418           }
419           }
420            
421           # rpath is disallowed, except in private directories
422 1314 100 66   13803 if (exists($objdump->{RPATH}) or exists($objdump->{RUNPATH})) {
423 20 100     115 if (not %directories) {
424 5       30 for my $file ($info->sorted_index) {
425 150       190 my $name;
426 150 100 66   270 next unless $file->is_dir || $file->is_symlink;
427 75       150 $name = $file->name;
428 75       405 $name =~ s,/\z,,;
429 75       200 $directories{"/$name"}++;
430           }
431           }
432           my @rpaths
433 20       50 = (keys(%{$objdump->{RPATH}}),keys(%{$objdump->{RUNPATH}}),);
  20       90  
  20       100  
434            
435 20       70 foreach my $rpath (map {File::Spec->canonpath($_)}@rpaths) {
  25       290  
436           next
437 25 100     355 if $rpath
438           =~ m,^/usr/lib/(?:$madir/)?(?:games/)?(?:\Q$pkg\E|\Q$srcpkg\E)(?:/|\z),;
439 15 50     75 next if $rpath =~ m,^\$\{?ORIGIN\}?,;
440           next
441 15 100 100   195 if $directories{$rpath}
442           and $rpath !~ m,^(?:/usr)?/lib(?:/$madir)?/?\z,;
443 10       70 tag 'binary-or-shlib-defines-rpath', $file, $rpath;
444           }
445           }
446            
447 1314       8952 foreach my $emlib ($EMBEDDED_LIBRARIES->all) {
448 78840       460702 my $ldata = $EMBEDDED_LIBRARIES->value($emlib);
449 78840 100     932494 if ($ldata->{'source-regex'}) {
450 24966 50     84401 next if $proc->pkg_src =~ m/^$ldata->{'source-regex'}$/;
451           } else {
452 53874 50     175341 next if $proc->pkg_src eq $ldata->{'source'};
453           }
454 78840 100     2281750 if ($strings =~ $ldata->{'match'}) {
455 663       5265 tag 'embedded-library', "$fname: $ldata->{'libname'}";
456           }
457           }
458            
459           # binary or shared object?
460           next
461 1314 50 66   23592 unless ($fileinfo =~ m/executable/)
462           or ($fileinfo =~ m/shared object/);
463 1314 50     6184 next if $type eq 'udeb';
464            
465           # Perl library?
466 1314 100     7854 if ($fname =~ m,^usr/lib/(?:[^/]+/)?perl5/.*\.so$,) {
467 29       92 $has_perl_lib = 1;
468           }
469            
470           # PHP extension?
471 1314 100     5670 if ($fname =~ m,^usr/lib/php\d/.*\.so(?:\.\d+)*$,) {
472 5       25 $has_php_ext = 1;
473           }
474            
475           # Python extension using Numpy C ABI?
476 1314 100 33   12594 if (
      66      
477           $fname =~ m,usr/lib/(?:pyshared/)?python2\.\d+/.*(?
478           or( $fname =~ m,usr/lib/python3/.+\.cpython-\d+([a-z]+)\.so$,
479           and $1 !~ /d/)
480           ) {
481 12 50 33   132 if (index($strings, 'numpy') > -1 and $strings =~ NUMPY_REGEX) {
482 0       0 $uses_numpy_c_abi = 1;
483           }
484           }
485            
486           # Something other than detached debugging symbols in
487           # /usr/lib/debug paths.
488 1314 100     6245 if ($fname
489           =~ m,^usr/lib/debug/(?:lib\d*|s?bin|usr|opt|dev|emul|\.build-id)/,)
490           {
491 60 100     280 if (exists($objdump->{NEEDED})) {
492 15       105 tag 'debug-file-should-use-detached-symbols', $file;
493           }
494           tag 'debug-file-with-no-debug-symbols', $file
495           unless (exists $objdump->{'SH'}{'.debug_line'}
496           or exists $objdump->{'SH'}{'.zdebug_line'}
497           or exists $objdump->{'SH'}{'.debug_str'}
498 60 50 66   826 or exists $objdump->{'SH'}{'.zdebug_str'});
      33      
      33      
499           }
500            
501           # Detached debugging symbols directly in /usr/lib/debug.
502 1314 100     5610 if ($fname =~ m,^usr/lib/debug/[^/]+$,) {
503 20 100 100   145 unless (exists($objdump->{NEEDED})
504           || $fileinfo =~ m/statically linked/) {
505 5       20 tag 'debug-symbols-directly-in-usr-lib-debug', $file;
506           }
507           }
508            
509           # statically linked?
510 1314 100     8325 if (!exists($objdump->{NEEDED})) {
511 125 100     799 if ($fileinfo =~ m/shared object/o) {
512           # Some exceptions: kernel modules, syslinux modules, detached
513           # debugging information and the dynamic loader (which itself
514           # has no dependencies).
515 47 50     262 next if ($fname =~ m%^boot/modules/%);
516 47 50     235 next if ($fname =~ m%^lib/modules/%);
517 47 100     529 next if ($fname =~ m%^usr/lib/debug/%);
518 17 50     175 next if ($fname =~ m%\.(?:[ce]32|e64)$%);
519           next
520           if (
521 17 50     78 $fname =~ m{
522           ^lib(?:|32|x32|64)/
523           (?:[-\w/]+/)?
524           ld-[\d.]+\.so$
525           }xsm
526           );
527 17       95 tag 'shared-lib-without-dependency-information', $file;
528           } else {
529           # Some exceptions: files in /boot, /usr/lib/debug/*,
530           # named *-static or *.static, or *-static as
531           # package-name.
532 78 100     485 next if ($fname =~ m%^boot/%);
533 71 100     660 next if ($fname =~ /[\.-]static$/);
534 52 50     244 next if ($pkg =~ /-static$/);
535           # Binaries built by the Go compiler are statically
536           # linked by default.
537 52 100     275 next if ($built_with_golang);
538           # klibc binaries appear to be static.
539           next
540           if (exists $objdump->{INTERP}
541 47 50 33   247 && $objdump->{INTERP} =~ m,/lib/klibc-\S+\.so,);
542           # Location of debugging symbols.
543 47 100     412 next if ($fname =~ m%^usr/lib/debug/%);
544           # ldconfig must be static.
545 27 50     170 next if ($fname eq 'sbin/ldconfig');
546 27       255 tag 'statically-linked-binary', $file;
547           }
548           } else {
549 1189       3666 my $no_libc = 1;
550 1189       4085 my $is_shared = 0;
551 1189       2735 my @needed;
552 1189       3174 $needs_depends_line = 1;
553 1189 100     7325 $is_shared = 1 if index($fileinfo, 'shared object') != -1;
554 1189 50     5140 @needed = @{$objdump->{NEEDED}} if exists($objdump->{NEEDED});
  1189       6049  
555 1189       4773 for my $lib (@needed) {
556 1251 100     9100 if ($lib =~ /^libc\.so\.(\d+.*)/) {
557 1175       6006 $needs_libc = "libc$1";
558 1175 100     4826 $needs_libc_file = $fname unless $needs_libc_file;
559 1175       3117 $needs_libc_count++;
560 1175       3255 $no_libc = 0;
561           }
562 1251 100     5472 if ($lib =~ m{\A libstdc\+\+\.so\.(\d+) \Z}xsm) {
563 5       35 $needs_libcxx = "libstdc++$1";
564 5 50     30 $needs_libcxx_file = $fname
565           unless $needs_libcxx_file;
566 5       20 $needs_libcxx_count++;
567           }
568           }
569 1189 100 66   6581 if ($no_libc and not $fname =~ m,/libc\b,) {
570           # If there is no libc dependency, then it is most likely a
571           # bug. The major exception is that some C++ libraries,
572           # but these tend to link against libstdc++ instead. (see
573           # #719806)
574 14 100     49 if ($is_shared) {
575 7 50     63 tag 'library-not-linked-against-libc', $file
576           unless $needs_libcxx ne '';
577           } else {
578 7       63 tag 'program-not-linked-against-libc', $file;
579           }
580           }
581            
582 1189 100 66   19219 if ( $arch_hardening->{'hardening-no-relro'}
      100      
583           and not $built_with_golang
584           and not $objdump->{'PH'}{'RELRO'}) {
585 9       81 tag 'hardening-no-relro', $file;
586           }
587            
588 1189 100 66   15437 if ( $arch_hardening->{'hardening-no-bindnow'}
      100      
589           and not $built_with_golang
590           and not exists($objdump->{'FLAGS_1'}{'NOW'})) {
591 159       739 tag 'hardening-no-bindnow', $file;
592           }
593            
594 1189 100 66   28834 if ( $arch_hardening->{'hardening-no-pie'}
      100      
595           and not $built_with_golang
596           and $objdump->{'ELF-TYPE'} eq 'EXEC') {
597 43       307 tag 'hardening-no-pie', $file;
598           }
599           }
600           }
601            
602           # Find the package dependencies, which is used by various checks.
603 5591       70256 my $depends = $info->relation('strong');
604            
605           # Check for a libc dependency.
606 5591 100     32419 if ($needs_depends_line) {
607 411 100     3365 if ($depends->empty) {
608 18       105 tag 'missing-depends-line';
609           } else {
610 393 100 66   6237 if ($needs_libc && $pkg !~ /^libc[\d.]+(?:-|\z)/) {
611           # Match libcXX or libcXX-*, but not libc3p0.
612 386       7507 my $re = qr/^\Q$needs_libc\E\b/;
613 386 100     3378 if (!$depends->matches($re)) {
614 26       115 my $others = '';
615 26       62 $needs_libc_count--;
616 26 100     129 if ($needs_libc_count > 0) {
617 15       80 $others = " and $needs_libc_count others";
618           }
619 26       172 tag 'missing-dependency-on-libc',
620           "needed by $needs_libc_file$others";
621           }
622           }
623 393 100     5285 if ($needs_libcxx ne '') {
624           # Match libstdc++XX or libcstdc++XX-*
625 5       90 my $re = qr/^\Q$needs_libcxx\E\b/;
626 5 50     35 if (!$depends->matches($re)) {
627 5       25 my $others = '';
628 5       15 $needs_libcxx_count--;
629 5 50     30 if ($needs_libcxx_count > 0) {
630 0       0 $others = " and $needs_libcxx_count others";
631           }
632 5       40 tag 'missing-dependency-on-libstdc++',
633           "needed by $needs_libcxx_file$others";
634           }
635           }
636           }
637           }
638            
639           # Check for a Perl dependency.
640 5591 100     29056 if ($has_perl_lib) {
641           # It is a virtual package, so no version is allowed and
642           # alternatives probably does not make sense here either.
643 29       173 my $re = qr/^perlapi-[-\w.]+(?:\s*\[[^\]]+\])?$/;
644 29 100     248 unless ($depends->matches($re, VISIT_OR_CLAUSE_FULL)) {
645 18       105 tag 'missing-dependency-on-perlapi';
646           }
647           }
648            
649           # Check for a phpapi- dependency.
650 5591 100     27084 if ($has_php_ext) {
651           # It is a virtual package, so no version is allowed and
652           # alternatives probably does not make sense here either.
653 5 50     40 unless ($depends->matches(qr/^phpapi-[\d\w+]+$/, VISIT_OR_CLAUSE_FULL))
654           {
655 5       30 tag 'missing-dependency-on-phpapi';
656           }
657           }
658            
659           # Check for dependency on python-numpy-abiN dependency (or strict versioned
660           # dependency on python-numpy)
661 5591 50 33   34120 if ($uses_numpy_c_abi and $pkg !~ m{\A python3?-numpy \Z}xsm) {
662           # We do not allow alternatives as it would mostly likely
663           # defeat the purpose of this relation. Also, we do not allow
664           # versions for -abi as it is a virtual package.
665 0       0 my $vflags = VISIT_OR_CLAUSE_FULL;
666 0 0 0   0 tag 'missing-dependency-on-numpy-abi'
      0      
667           unless $depends->matches(qr/^python3?-numpy-abi\d+$/, $vflags)
668           or ( $depends->matches(qr/^python-numpy \(>[>=][^\|]+$/, $vflags)
669           and $depends->matches(qr/^python-numpy \(<[<=][^\|]+$/, $vflags));
670           }
671            
672 5591       48305 return;
673           }
674            
675           sub tag_unneeded_sections {
676 1244     1244 6107 my ($tag, $file, $objdump) = @_;
677 1244       4632 foreach my $sect ('.note', '.comment') {
678 2488 100     12543 if (exists $objdump->{'SH'}{$sect}) {
679 36       245 tag $tag, "$file $sect";
680           }
681           }
682 1244       4247 return;
683           }
684            
685           1;
686            
687           # Local Variables:
688           # indent-tabs-mode: nil
689           # cperl-indent-level: 4
690           # End:
691           # vim: syntax=perl sw=4 sts=4 sr et