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: