1#!/usr/bin/perl
2
3#
4#//===----------------------------------------------------------------------===//
5#//
6#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
7#// See https://llvm.org/LICENSE.txt for license information.
8#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
9#//
10#//===----------------------------------------------------------------------===//
11#
12
13use strict;
14use warnings;
15
16use FindBin;
17use lib "$FindBin::Bin/lib";
18
19use tools;
20
21our $VERSION = "0.002";
22my $target_arch;
23
24sub execstack($) {
25    my ( $file ) = @_;
26    my @output;
27    my @stack;
28    my $tool;
29    if($target_arch eq "mic") {
30        $tool = "x86_64-k1om-linux-readelf";
31    } else {
32        $tool = "readelf";
33    }
34    execute( [ $tool, "-l", "-W", $file ], -stdout => \@output );
35    @stack = grep( $_ =~ m{\A\s*(?:GNU_)?STACK\s+}, @output );
36    if ( not @stack ) {
37        # Interpret missed "STACK" line as error.
38        runtime_error( "$file: No stack segment found; looks like stack would be executable." );
39    }; # if
40    if ( @stack > 1 ) {
41        runtime_error( "$file: More than one stack segment found.", "readelf output:", @output, "(eof)" );
42    }; # if
43    # Typical stack lines are:
44    # Linux* OS IA-32 architecture:
45    #    GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
46    # Linux* OS Intel(R) 64:
47    #    GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x8
48    if ( $stack[ 0 ] !~ m{\A\s*(?:GNU_)?STACK(?:\s+0x[0-9a-f]+){5}\s+([R ][W ][E ])\s+0x[0-9a-f]+\s*\z} ) {
49        runtime_error( "$file: Cannot parse stack segment line:", ">>> $stack[ 0 ]" );
50    }; # if
51    my $attrs = $1;
52    if ( $attrs =~ m{E} ) {
53        runtime_error( "$file: Stack is executable" );
54    }; # if
55}; # sub execstack
56
57get_options(
58    "arch=s" => \$target_arch,
59);
60
61foreach my $file ( @ARGV ) {
62    execstack( $file );
63}; # foreach $file
64
65exit( 0 );
66
67__END__
68
69=pod
70
71=head1 NAME
72
73B<check-execstack.pl> -- Check whether stack is executable, issue an error if so.
74
75=head1 SYNOPSIS
76
77B<check-execstack.pl> I<option>... I<file>...
78
79=head1 DESCRIPTION
80
81The script checks whether stack of specified executable file, and issues error if stack is
82executable. If stack is not executable, the script exits silently with zero exit code.
83
84The script runs C<readelf> utility to get information about specified executable file. So, the
85script fails if C<readelf> is not available. Effectively it means the script works only on Linux* OS
86(and, probably, Intel(R) Many Integrated Core Architecture).
87
88=head1 OPTIONS
89
90=over
91
92=item Standard Options
93
94=over
95
96=item B<--doc>
97
98=item B<--manual>
99
100Print full help message and exit.
101
102=item B<--help>
103
104Print short help message and exit.
105
106=item B<--usage>
107
108Print very short usage message and exit.
109
110=item B<--verbose>
111
112Do print informational messages.
113
114=item B<--version>
115
116Print program version and exit.
117
118=item B<--quiet>
119
120Work quiet, do not print informational messages.
121
122=back
123
124=back
125
126=head1 ARGUMENTS
127
128=over
129
130=item I<file>
131
132A name of executable or shared object to check. Multiple files may be specified.
133
134=back
135
136=head1 EXAMPLES
137
138Check libomp.so library:
139
140    $ check-execstack.pl libomp.so
141
142=cut
143
144# end of file #
145
146