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

Bug#650536: update!



Okay, here's the latest version. Some notes:

- It requires the lastest dpkg-dev (still in experimental) to get
  the dpkg-buildflags that supports --query-features.

- The hardening checker only expects the hardened features that are
  defaulted on for the architecture of the package it is examining.

- The hardening checker checks if it is running as part of the
  internal test suite, so that it is disabled for all tests except
  its own, since the bulk of the internal tests do not build with
  hardening flags, and only for i386 and amd64 since there isn't
  a sane way to generate the "tags" file on the fly for a test.

Doing manual testing shows that building, for example, the "hello"
package as-is triggers appropriate warnings, and when I fix the "hello"
package to import the dpkg-buildflags correctly, the lintian warnings
go away. :)

-Kees

-- 
Kees Cook                                            @debian.org
>From 550f6f0ef62a965118dc510f59329e66d73668d7 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                            |   10 +++
 checks/binaries.desc                       |   53 +++++++++++++++-
 collection/hardening-info                  |   98 ++++++++++++++++++++++++++++
 collection/hardening-info.desc             |    7 ++
 debian/changelog                           |    5 +-
 debian/control                             |    5 +-
 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 ++
 11 files changed, 251 insertions(+), 3 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 0e3c956..f3d01fd 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) 2012 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
@@ -437,6 +438,15 @@ foreach my $file (@{$info->sorted_file_info}) {
                 tag 'program-not-linked-against-libc', $file;
             }
         }
+
+        # Check for missing hardening characteristics. This currently
+        # handles the following checks:
+        # no-relro no-fortify-functions no-stackprotector no-bindnow no-pie
+        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 4e0ad1e..f269c70 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
@@ -299,3 +299,54 @@ 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
+
+Tag: no-pie
+Severity: normal
+Certainty: certain
+Info: This package provides an ELF binary that was not built as a Position
+ Independent Executable. 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
+
+Tag: no-bindnow
+Severity: normal
+Certainty: certain
+Info: This package provides an ELF binary that lacks the "bind now"
+ linker 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..c8e49d0
--- /dev/null
+++ b/collection/hardening-info
@@ -0,0 +1,98 @@
+#!/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) 2012 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;
+
+use lib "$ENV{'LINTIAN_ROOT'}/lib";
+use Util;
+use Cwd;
+
+open (OUT, '>', 'hardening-info')
+    or fail("cannot open hardening-info: $!");
+
+# If we're running inside the Lintian test suite itself, we need to avoid
+# all the tests except the "binaries-hardening" test.
+my $base = Cwd::realpath('.');
+exit 0
+    if (defined $ENV{'LINTIAN_INTERNAL_TESTSUITE'} and
+        $ENV{'LINTIAN_INTERNAL_TESTSUITE'} eq "1" and
+        $base !~ m|/binaries-hardening/binaries-hardening_1.0_.*_binary$|);
+
+open (FILES, '<', 'file-info')
+    or fail("cannot open file-info: $!");
+
+# Override the arch seen by dpkg-buildflags for the arch of this package.
+my @fields = read_dpkg_control ('control/control');
+defined ($fields[0]{'architecture'})
+    or fail ("cannot determine architecture of package!");
+$ENV{'DEB_HOST_ARCH'} = $fields[0]{'architecture'}
+    if ($fields[0]{'architecture'} ne "all");
+
+# Prepare to examine the file tree.
+chdir ('unpacked')
+    or fail("unable to chdir to unpacked: $!");
+
+# We must figure out what hardening features are expected by default for a
+# given architecture. Extract this from "dpkg-buildflags", and set up the
+# needed arguments for calling "hardening-check".
+open (my $FLAGS, '-|', "dpkg-buildflags --query-features hardening")
+    or fail ("could not launch dpkg-buildflags: $!");
+my $args = "--lintian";
+my $feature = "";
+@fields = parse_dpkg_control ($FLAGS);
+foreach my $flag (@fields) {
+    if ($flag->{enabled} eq "no") {
+        $args .= " --no" . $flag->{feature};
+    }
+}
+close $FLAGS;
+
+while (<FILES>) {
+    if (m/^(.+?)\x00\s.*ELF/) {
+        my $bin = $1;
+
+        if (open (PIPE, '-|', "hardening-check $args -- \Q$bin\E 2>&1")) {
+            local $/;
+            local $_ = <PIPE>;
+            print OUT $_;
+            close PIPE;
+        }
+    }
+}
+
+close FILES;
+close OUT or fail("cannot write objdump-info: $!");
+
+exit 0;
+
+# 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..ee051fe
--- /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: bin-pkg-control, file-info, unpacked
diff --git a/debian/changelog b/debian/changelog
index 9fe866f..f7c8e10 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -15,7 +15,10 @@ lintian (2.5.6) UNRELEASED; urgency=low
     + [NT] Fixed issue where "Experimental: no" was handled as a
       "yes" when generating a tag description.
 
- -- Niels Thykier <niels@thykier.net>  Fri, 24 Feb 2012 09:40:30 +0100
+  * checks/binaries, collector/hardening-info*:
+    + Add ELF hardening checks.  (Closes: 650536)
+
+ -- Kees Cook <kees@ubuntu.com>  Sun, 04 Mar 2012 12:40:41 -0800
 
 lintian (2.5.5) unstable; urgency=low
 
diff --git a/debian/control b/debian/control
index b47a3a4..81885b8 100644
--- a/debian/control
+++ b/debian/control
@@ -16,9 +16,11 @@ Build-Depends: binutils,
                diffstat,
                docbook-utils,
                docbook-xml,
+               dpkg-dev (>= 1.16.2~wipmultiarch),
                fakeroot,
                file,
                gettext,
+               hardening-includes (>= 1.35),
                intltool-debian,
                javahelper (>= 0.32~),
                libapt-pkg-perl,
@@ -60,8 +62,10 @@ Architecture: all
 Depends: binutils,
          bzip2,
          diffstat,
+         dpkg-dev (>= 1.16.2~wipmultiarch),
          file,
          gettext,
+         hardening-includes (>= 1.35),
          intltool-debian,
          libapt-pkg-perl,
          libc-bin (>= 2.13) | locales,
@@ -80,7 +84,6 @@ Depends: binutils,
          unzip,
          ${misc:Depends}
 Suggests: binutils-multiarch,
-          dpkg-dev,
           libhtml-parser-perl,
           libtext-template-perl,
           man-db (>= 2.5.1-1),
diff --git a/lib/Lintian/Collect/Binary.pm b/lib/Lintian/Collect/Binary.pm
index b0d81de..fd7adcc 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) 2012 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..1d924eb
--- /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: amd64 i386
+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.9.1


Reply to: