[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#650536: first pass



Hi!

Attached is a first-pass at the lintian support for "hardening-check".

There are two more things to do, which I'd like some direction on:

1) With these build tests added, all the other internal lintian tests
   need to either:
        a) add the new warnings to their "tags" file, or
        b) have all their builds adjusted to bring in the dpkg-buildflag
           defaults.
   It looks like a pretty large change, but it should be relatively
   mechanical to accomplish. I would think that "b" above is the better
   of the two options.

2) In reality, the tests are arch-dependent. For example, "relro" doesn't
   exist at all on ia64 hppa avr32, and "stackprotector" doesn't exist on
   ia64 alpha mips mipsel hppa arm. I think this expectation needs to be
   built into lintian's invocation of "hardening-check", but that means
   that the "tags" file in the internal lintian tests suddenly needs to
   be generated instead of being static. (i.e. on ia64 and hppa, "no-relro"
   shouldn't show up because it can never happen.)

Thoughts?

-Kees

-- 
Kees Cook                                            @debian.org
>From c4709a5f46ecacd9975891332fea7c6e3e6b4d75 Mon Sep 17 00:00:00 2001
From: Kees Cook <kees@outflux.net>
Date: Thu, 1 Dec 2011 16:04:00 -0800
Subject: [PATCH] Add initial lintian checks for ELF hardening

This adds the "hardening-info" collector which depends on the
new "--lintian" mode of the "hardening-check" tool found in the
"hardening-includes" package.

Signed-off-by: Kees Cook <kees@debian.org>
---
 checks/binaries                            |    8 +++
 checks/binaries.desc                       |   34 ++++++++++++++-
 collection/hardening-info                  |   65 ++++++++++++++++++++++++++++
 collection/hardening-info.desc             |    7 +++
 debian/control                             |    2 +
 lib/Lintian/Collect/Binary.pm              |   27 +++++++++++
 t/tests/binaries-hardening/debian/Makefile |   18 ++++++++
 t/tests/binaries-hardening/debian/hello.c  |   17 +++++++
 t/tests/binaries-hardening/desc            |    9 ++++
 t/tests/binaries-hardening/tags            |    5 ++
 10 files changed, 191 insertions(+), 1 deletions(-)
 create mode 100755 collection/hardening-info
 create mode 100644 collection/hardening-info.desc
 create mode 100644 t/tests/binaries-hardening/debian/Makefile
 create mode 100644 t/tests/binaries-hardening/debian/hello.c
 create mode 100644 t/tests/binaries-hardening/desc
 create mode 100644 t/tests/binaries-hardening/tags

diff --git a/checks/binaries b/checks/binaries
index 8eeb543..aee4d55 100644
--- a/checks/binaries
+++ b/checks/binaries
@@ -1,6 +1,7 @@
 # binaries -- lintian check script -*- perl -*-
 
 # Copyright (C) 1998 Christian Schwarz and Richard Braakman
+# Copyright (C) 2011 Kees Cook
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -410,6 +411,13 @@ foreach my $file (@{$info->sorted_file_info}) {
                 tag 'program-not-linked-against-libc', $file;
             }
         }
+
+        # Check for missing hardening characteristics.
+        if (exists($info->hardening_info->{$file})) {
+            foreach my $tag (@{$info->hardening_info->{$file}}) {
+                tag $tag, $file;
+            }
+        }
     }
 }
 
diff --git a/checks/binaries.desc b/checks/binaries.desc
index 9054908..c1653e6 100644
--- a/checks/binaries.desc
+++ b/checks/binaries.desc
@@ -2,7 +2,7 @@ Check-Script: binaries
 Author: Christian Schwarz <schwarz@debian.org>
 Abbrev: bin
 Type: binary, udeb
-Needs-Info: objdump-info, file-info, strings, index
+Needs-Info: hardening-info, objdump-info, file-info, strings, index
 Info: This script checks binaries and object files for bugs.
 
 Tag: arch-independent-package-contains-binary-or-object
@@ -282,3 +282,35 @@ Info: This package provides an OCaml bytecode executable linked with a
  custom runtime. Such executables cannot be stripped and require
  special care. Their usage is deprecated in favour of shared libraries
  for C stubs (dll*.so).
+
+Tag: no-stackprotector
+Severity: normal
+Certainty: possible
+Info: This package provides an ELF binary that lacks the stack protector
+ function <tt>__stack_chk_fail</tt>. Either there are no character arrays used
+ on the stack of any routines, or the package was not built with the
+ default Debian compiler flags defined by <tt>dpkg-buildflags</tt>. If built
+ using <tt>dpkg-buildflags</tt> directly, be sure to import <tt>CFLAGS</tt>
+ and/or <tt>CXXFLAGS</tt>.
+Ref: http://wiki.debian.org/Hardening
+
+Tag: no-fortify-functions
+Severity: normal
+Certainty: possible
+Info: This package provides an ELF binary that lacks the use of fortified
+ libc functions. Either there are no potentially unfortified functions
+ called by any routines, all unfortified calls have already been fully
+ validated at compile-time, or the package was not built with the default
+ Debian compiler flags defined by <tt>dpkg-buildflags</tt>. If built using
+ <tt>dpkg-buildflags</tt> directly, be sure to import <tt>CPPFLAGS</tt>.
+Ref: http://wiki.debian.org/Hardening
+
+Tag: no-relro
+Severity: normal
+Certainty: certain
+Info: This package provides an ELF binary that lacks the "read-only
+ relocation" link flag. This package was likely not built with the
+ default Debian compiler flags defined by <tt>dpkg-buildflags</tt>.
+ If built using <tt>dpkg-buildflags</tt> directly, be sure to import
+ <tt>LDFLAGS</tt>.
+Ref: http://wiki.debian.org/Hardening
diff --git a/collection/hardening-info b/collection/hardening-info
new file mode 100755
index 0000000..0072d93
--- /dev/null
+++ b/collection/hardening-info
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+# hardening-info -- lintian collection script
+
+# The original shell script version of this script is
+# Copyright (C) 1998 Christian Schwarz
+# 
+# The objdump version, including support for etch's binutils, is
+# Copyright (C) 2008 Adam D. Barratt
+# 
+# This version, a trimmed-down wrapper for hardening-check, is
+# Copyright (C) 2011 Kees Cook <kees@debian.org>
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, you can find it on the World Wide
+# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+use strict;
+use warnings;
+
+my $failed = 0;
+
+open (FILES, '<', 'file-info')
+    or fail("cannot open file-info: $!");
+
+open (OUT, '>', 'hardening-info')
+    or fail("cannot open hardening-info: $!");
+
+chdir ('unpacked')
+    or fail ("unable to chdir to unpacked: $!\n");
+
+while (<FILES>) {
+    if (m/^(.+?)\x00\s.*ELF/) {
+        my $bin = $1;
+
+        if (open(PIPE, '-|', "hardening-check -pb --lintian \Q$bin\E 2>&1")) {
+            local $/;
+            local $_ = <PIPE>;
+            print OUT $_;
+            close PIPE;
+        }
+    }
+}
+
+close FILES;
+close OUT or fail("cannot write objdump-info: $!");
+
+exit $failed;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/collection/hardening-info.desc b/collection/hardening-info.desc
new file mode 100644
index 0000000..47a3c43
--- /dev/null
+++ b/collection/hardening-info.desc
@@ -0,0 +1,7 @@
+Collector-Script: hardening-info
+Author: Kees Cook <kees@debian.org>
+Info: This script runs hardening-check(1) over all ELF binaries of a binary
+ package.
+Type: binary, udeb
+Version: 1
+Needs-Info: file-info, unpacked
diff --git a/debian/control b/debian/control
index 5d9bb66..f1a902b 100644
--- a/debian/control
+++ b/debian/control
@@ -19,6 +19,7 @@ Build-Depends: binutils,
                fakeroot,
                file,
                gettext,
+               hardening-includes (=> 1.35),
                intltool-debian,
                javahelper (>= 0.32~),
                libapt-pkg-perl,
@@ -60,6 +61,7 @@ Depends: binutils,
          diffstat,
          file,
          gettext,
+         hardening-includes (>= 1.35),
          intltool-debian,
          libapt-pkg-perl,
          libclass-accessor-perl,
diff --git a/lib/Lintian/Collect/Binary.pm b/lib/Lintian/Collect/Binary.pm
index b0d81de..493904b 100644
--- a/lib/Lintian/Collect/Binary.pm
+++ b/lib/Lintian/Collect/Binary.pm
@@ -3,6 +3,7 @@
 
 # Copyright (C) 2008, 2009 Russ Allbery
 # Copyright (C) 2008 Frank Lichtenheld
+# Copyright (C) 2011 Kees Cook
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by the Free
@@ -240,6 +241,32 @@ sub objdump_info {
 }
 
 
+# Returns the information from collect/hardening-info
+# sub hardening_info Needs-Info hardening-info
+sub hardening_info {
+    my ($self) = @_;
+    return $self->{hardening_info} if exists $self->{hardening_info};
+    my $base_dir = $self->base_dir();
+    my %hardening_info;
+    my ($file);
+    open(my $idx, '<', "$base_dir/hardening-info")
+        or fail("cannot open $base_dir/hardening-info: $!");
+    while (<$idx>) {
+        chomp;
+
+        if (m,^([^:]+):\./(.*)$,) {
+            my ($tag, $file) = ($1, $2);
+
+            push(@{$hardening_info{$file}}, $tag);
+        }
+    }
+
+    $self->{hardening_info} = \%hardening_info;
+
+    return $self->{hardening_info};
+}
+
+
 # Returns the information from collect/objdump-info
 # sub java_info Needs-Info java-info
 sub java_info {
diff --git a/t/tests/binaries-hardening/debian/Makefile b/t/tests/binaries-hardening/debian/Makefile
new file mode 100644
index 0000000..5f75208
--- /dev/null
+++ b/t/tests/binaries-hardening/debian/Makefile
@@ -0,0 +1,18 @@
+all:
+	# Build without dpkg-buildflags.
+	gcc -o weak hello.c
+	gcc -o strong \
+		$(shell dpkg-buildflags --get CPPFLAGS) \
+		$(shell dpkg-buildflags --get CFLAGS) \
+		$(shell dpkg-buildflags --get LDFLAGS) \
+		hello.c
+
+install:
+	install -d $(DESTDIR)/usr/bin/
+	install -m 755 -c weak $(DESTDIR)/usr/bin/weak
+	install -m 755 -c strong $(DESTDIR)/usr/bin/strong
+
+clean distclean:
+	rm -f weak strong
+
+check test:
diff --git a/t/tests/binaries-hardening/debian/hello.c b/t/tests/binaries-hardening/debian/hello.c
new file mode 100644
index 0000000..7b87bd7
--- /dev/null
+++ b/t/tests/binaries-hardening/debian/hello.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+void
+report(char *string)
+{
+    char buf[80];
+    int len;
+
+    strcpy(buf, string);
+    fprintf(stdout, "Hello world from %s!\n%n", buf, &len);
+}
+
+int
+main(int argc, char *argv[])
+{
+    report(argv[0]);
+}
diff --git a/t/tests/binaries-hardening/desc b/t/tests/binaries-hardening/desc
new file mode 100644
index 0000000..d66f8da
--- /dev/null
+++ b/t/tests/binaries-hardening/desc
@@ -0,0 +1,9 @@
+Testname: binaries-hardening
+Sequence: 6000
+Version: 1.0
+Description: Check for missing hardening features
+Architecture: any
+Test-For:
+ no-relro
+ no-stackprotector
+ no-fortify-functions
diff --git a/t/tests/binaries-hardening/tags b/t/tests/binaries-hardening/tags
new file mode 100644
index 0000000..1f64a2a
--- /dev/null
+++ b/t/tests/binaries-hardening/tags
@@ -0,0 +1,5 @@
+W: binaries-hardening: binary-without-manpage usr/bin/strong
+W: binaries-hardening: binary-without-manpage usr/bin/weak
+W: binaries-hardening: no-fortify-functions usr/bin/weak
+W: binaries-hardening: no-relro usr/bin/weak
+W: binaries-hardening: no-stackprotector usr/bin/weak
-- 
1.7.5.4


Reply to: