blob: a0e8bb1a55d054e886e47321ba40d74868e17f28 [file] [log] [blame]
Richard Marian Thomaiyar14fddef2018-07-13 23:55:56 +05301#!/bin/sh
2# rpm-chksec
3#
4# Copyright (c) 2011-2013 Steve Grubb. ALL RIGHTS RESERVED.
5# sgrubb@redhat.com
6#
7# This software may be freely redistributed under the terms of the GNU
8# public license.
9#
10# You should have received a copy of the GNU General Public License
11# along with this program; if not, write to the Free Software
12# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
13#
14# Given an rpm, it will look at each file to check that its compiled with
15# the intended flags to make it more secure. Things that are green are OK.
16# Anything in yellow could be better but is passable. Anything in red needs
17# attention.
18#
19# If the --all option is given, it will generate a list of rpms and then
20# summarize the rpm's state. For yes, then all files are in the expected
21# state. Just one file not compiled with the right flags can turn the
22# answer to no. Re-run passing that package (instead of --all) for the details.
23#
24# To save to file: ./rpm-chksec | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | tee output.txt
25
26VERSION="0.5.2"
27
28usage () {
29 echo "rpm-chksec [--version|--all|<rpmname>...]"
30 if [ ! -x /usr/bin/filecap ] ; then
31 echo "You need to install libcap-ng-utils to test capabilities"
32 fi
33 if [ $EUID != 0 ] ; then
34 echo "You might need to be root to read some files"
35 fi
36 exit 0
37}
38
39if [ "$1" = "--help" -o $# -eq 0 ] ; then
40 usage
41fi
42if [ "$1" = "--version" ] ; then
43 echo "rpm-chksec $VERSION"
44 exit 0
45fi
46if [ "$1" = "--all" ] ; then
47 MODE="all"
48else
49 MODE="single"
50fi
51
52do_one () {
53if ! rpm -q $1 >/dev/null 2>&1 ; then
54 if [ "$MODE" = "single" ] ; then
55 echo "$1 is not installed"
56 exit 1
57 else
58 echo "not installed"
59 return
60 fi
61fi
62files=`rpm -ql $1`
63
64# Look for daemons, need this for later...
65DAEMON=""
66for f in $files
67do
68 if [ ! -f "$f" ] ; then
69 continue
70 fi
71 if [ `echo "$f" | grep '\/etc\/rc.d\/init.d'` ] ; then
72 n=`basename "$f"`
73 t=`which "$n" 2>/dev/null`
74 if [ x"$t" != "x" ] ; then
75 DAEMON="$DAEMON $t"
76 continue
77 fi
78 t=`which "$n"d 2>/dev/null`
79 if [ x"$t" != "x" ] ; then
80 DAEMON="$DAEMON $t"
81 continue
82 fi
83 t=`cat "$f" 2>/dev/null | grep 'bin' | grep 'exit 5' | grep -v '\$'`
84 if [ x"$t" != "x" ] ; then
85 DAEMON="$DAEMON $t"
86 continue
87 fi
88 if [ "$MODE" = "single" ] ; then
89 echo "Can't find the executable in $f but daemon rules would apply"
90 fi
91 elif [ `echo "$f" | grep '\/lib\/systemd\/'` ] ; then
92 t=`cat "$f" | grep -i '^ExecStart=' | tr '=' ' ' | awk '{ print $2 }'`
93 if [ x"$t" != "x" ] ; then
94 DAEMON="$DAEMON $t"
95 continue
96 fi
97 fi
98done
99
100# Prevent garbled output when doing --all.
101skip_current=0
102
103for f in $files
104do
105 if [ ! -f "$f" ] ; then
106 continue
107 fi
108 # Some packages have files with ~ in them. This avoids it.
109 if ! echo "$f" | grep '^/' >/dev/null ; then
110 continue
111 fi
112 if [ ! -r "$f" ] && [ $EUID != 0 ] ; then
113 if [ $MODE = "single" ] ; then
114 echo "Please re-test $f as the root user"
115 else
116 # Don't print results.
117 skip_current=1
118 echo "Please re-test $1 as the root user"
119 fi
120 continue
121 fi
122 if ! file "$f" | grep -qw 'ELF'; then
123 continue
124 fi
125 RELRO="no"
126 if readelf -l "$f" 2>/dev/null | grep -q 'GNU_RELRO'; then
127 RELRO="partial"
128 fi
129 if readelf -d "$f" 2>/dev/null | grep -q 'BIND_NOW'; then
130 RELRO="full"
131 fi
132 PIE="no"
133 if readelf -h "$f" 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then
134 PIE="DSO"
135 if readelf -d "$f" 2>/dev/null | grep -q '(DEBUG)'; then
136 PIE="yes"
137 fi
138 fi
139 APP=""
140 if [ x"$DAEMON" != "x" ] ; then
141 for d in $DAEMON
142 do
143 if [ "$f" = "$d" ] ; then
144 APP="daemon"
145 break
146 fi
147 done
148 fi
149 if [ x"$APP" = "x" ] ; then
150 # See if this is a library or a setuid app
151 if [ `echo "$f" | grep '\/lib' | grep '\.so'` ] ; then
152 APP="library"
153 elif [ `find "$f" -perm -004000 -type f -print` ] ; then
154 APP="setuid"
155 elif [ `find "$f" -perm -002000 -type f -print` ] ; then
156 APP="setgid"
157 elif [ -x /usr/bin/filecap ] && [ `filecap "$f" 2> /dev/null | wc -w` -gt 0 ] ; then
158 APP="setcap"
159 else
160 syms1=`/usr/bin/readelf -s "$f" 2>/dev/null | egrep ' connect@.*GLIBC| listen@.*GLIBC| accept@.*GLIBC|accept4@.*GLIBC'`
161 syms2=`/usr/bin/readelf -s "$f" 2>/dev/null | egrep ' getaddrinfo@.*GLIBC| getnameinfo@.*GLIBC| getservent@.*GLIBC| getservbyname@.*GLIBC| getservbyport@.*GLIBC|gethostbyname@.*GLIBC| gethostbyname2@.*GLIBC| gethostbyaddr@.*GLIBC| gethostbyaddr2@.*GLIBC'`
162 if [ x"$syms1" != "x" ] ; then
163 if [ x"$syms2" != "x" ] ; then
164 APP="network-ip"
165 else
166 APP="network-local"
167 fi
168 fi
169 fi
170 fi
171 if [ x"$APP" = "x" ] ; then
172 APP="exec"
173 fi
174
175 # OK, ready for the output
176 if [ "$MODE" = "single" ] ; then
177 printf "%-56s %-10s " "$f" $APP
178 if [ "$APP" = "daemon" -o "$APP" = "setuid" -o "$APP" = "setgid" -o "$APP" = "setcap" -o "$APP" = "network-ip" -o "$APP" = "network-local" ] ; then
179 if [ "$RELRO" = "full" ] ; then
180 printf "\033[32m%-7s\033[m " $RELRO
181 elif [ "$RELRO" = "partial" ] ; then
182 printf "\033[33m%-7s\033[m " $RELRO
183 else
184 printf "\033[31m%-7s\033[m " $RELRO
185 fi
186 if [ "$PIE" = "yes" ] ; then
187 printf "\033[32m%-4s\033[m" $PIE
188 else
189 printf "\033[31m%-4s\033[m" $PIE
190 fi
191 elif [ "$APP" = "library" ] ; then
192 if [ "$RELRO" = "full" -o "$RELRO" = "partial" ] ; then
193 printf "\033[32m%-7s\033[m " $RELRO
194 else
195 printf "\033[31m%-7s\033[m " $RELRO
196 fi
197 printf "\033[32m%-4s\033[m" $PIE
198 else
199 # $APP = exec - we want partial relro
200 if [ "$RELRO" = "no" ] ; then
201 printf "\033[31m%-7s\033[m " $RELRO
202 else
203 printf "\033[32m%-7s\033[m " $RELRO
204 fi
205 printf "\033[32m%-4s\033[m" $PIE
206 fi
207 echo
208 else
209 if [ "$APP" = "daemon" -o "$APP" = "setuid" -o "$APP" = "setgid" -o "$APP" = "setcap" -o "$APP" = "network-ip" -o "$APP" = "network-local" ] ; then
210 if [ "$RELRO" = "no" ] ; then
211 RELRO_SUM="no"
212 APP_SUM="$APP"
213 fi
214 if [ "$PIE" = "no" ] ; then
215 PIE_SUM="no"
216 APP_SUM="$APP"
217 fi
218 elif [ "$APP" = "library" ] ; then
219 if [ "$RELRO" = "no" ] ; then
220 RELRO_SUM="no"
221 APP_SUM="$APP"
222 fi
223 # $APP = exec - must have partial or full relro
224 elif [ "$RELRO" = "no" ] ; then
225 RELRO_SUM="no"
226 APP_SUM="$APP"
227 fi
228 fi
229done
230}
231
232if [ "$MODE" = "single" ] ; then
233 printf "%-56s %-10s %-7s %-4s" "FILE" "TYPE" "RELRO" "PIE"
234 echo
235 for i; do
236 f=$(basename $1)
237 # Strip the .rpm extension, if present.
238 do_one ${f%%.rpm}
239 shift
240 done
241 exit 0
242fi
243
244# Skip the kernel as its special
245packages=`rpm -qa | egrep -v 'kernel.|debuginfo.|.noarch|gpg-pubkey' | sort`
246printf "%-50s %-5s %-4s %-14s" "PACKAGE" "RELRO" "PIE" "CLASS"
247echo
248for p in $packages
249do
250 RELRO_SUM="yes"
251 PIE_SUM="yes"
252 APP_SUM=""
253 printf "%-50s " $p
254 do_one $p
255 if [[ $skip_current -eq 1 ]] ; then
256 continue
257 fi
258 if [ "$RELRO_SUM" = "yes" ] ; then
259 printf "\033[32m%-5s\033[m " "$RELRO_SUM"
260 else
261 printf "\033[31m%-5s\033[m " "$RELRO_SUM"
262 fi
263 if [ "$PIE_SUM" = "yes" ] ; then
264 printf "\033[32m%-4s\033[m" "$PIE_SUM"
265 if [ "$RELRO_SUM" = "no" ] ; then
266 printf " %-14s" "$APP_SUM"
267 fi
268 else
269 if [ "$APP_SUM" = "network-local" ] ; then
270 printf "\033[33m%-4s\033[m %-14s" "$PIE_SUM" "$APP_SUM"
271 else
272 printf "\033[31m%-4s\033[m %-14s" "$PIE_SUM" "$APP_SUM"
273 fi
274 fi
275 echo
276done
277exit 0
278
279