Hardening options for C and C++ in Slackware
I started documenting myself about this topic some time ago when I was trying to compile the 7-Zip archiver from sources. I got the first information about these compilation options from Arch Linux and OpenSUSE. Then I started to study how this is done in other distributions, i.e. Debian, Ubuntu, Fedora, OpenSUSE, Gentoo.
I found the document here which is quite clear and has references to the documentation of the distributions mentioned above. In the case of Slackware, the SlackBuilds have the SLKCFLAGS variable that contains the "-O2" option plus a few more (depends on the package) and which is then transferred to CFLAGS in the configuration stage. Macros (variables) CPPFLAGS, CXXFLAGS, LDFLAGS do not appear. I found somewhere that these options would be of less importance for home users (if they don't care about the security of their operating system) but they are important for servers. Is there interest in this in Slackware? I am in the process of securing the packages compiled by me (and they are not few, I compile from sources even some packages that already exist in Slackware but not in the configuration I need). Now I use the following macros in the configuration stage: CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" CFLAGS="-fPIE -fstack-protector-strong" CXXFLAGS="-fPIE -fstack-protector-strong" LDFLAGS="-Wl,-pie,-z,now,-s" I built the packages from sources like this: 7-Zip; DCC (Distributed Checksum Clearinghouses); and Squid. Testing the application of these options is done with the utility here. |
All Slackware sources are available with the buildscripts and any other related files. Surely, it would be easiest/best to replicate these builds as closely as possible by building the packages in the same way and adding your own customization?
|
I do this for packages compiled by me from sources.
I only use the Slackware skeleton, I compile the rest of the packages and apply these options. I wonder if Slackware should do something for the core packages (those not modified by system administrator). I ask this because I change for nothing the packages I use if the base remains unchanged. I don't have the necessary infrastructure to recompile the entire Slackware base. Some examples: Code:
checksec --file=/usr/sbin/named Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/usr/sbin/httpd Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/usr/bin/ssh Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/usr/bin/7zz Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/usr/local/squid/sbin/squid Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE |
Quote:
By all means use -pie if you want — though a lot of the time I think it's just security theatre and most things don't need this extra protection — but I'd suggest you stick with -fPIC unless you know the objects built won't be used in a library. |
Quote:
If you really want to search for problems like that, you might want to try -fsanitize=address together with -g which will give you more details about the memory problem than to just exit with an error code. However, again, this is at a (probably even bigger) performance cost. If some program that you have compiled with -fstack-protector-strong bails out with a warning/error you might want to track the problem down with -fsanitize=address or some separate tool like valgrind. If you been running with programs compiled with -fstack-protector-strong for some years and never seen any warning/error you might have wasted some performance, but at least you could feel a bit safer. regards Henrik |
Quote:
Quote:
Quote:
https://www.mjr19.org.uk/IT/pic_pie.html Quote:
1. file https://www.cybertuna.net/position-i...-and-aslr.html 2. readelf https://serializethoughts.com/2019/06/29/elf-pic-pie I do not change the compilation options without first documenting what it is about and analyzing the binaries/shared libraries from at least 2 important distributions, i.e. Ubuntu and Fedora. PIE implementation: https://isopenbsdsecu.re/mitigations/pie/ In the case of 7-Zip: -fPIC is defined in CFLAGS (compiler options) in the .mak file, so -fPIE is no longer necessary; -pie has been added to LDFLAGS (link options). |
You may get more informed responses in LQ Programming Forum :)
But very nice link and I will use those guidelines for things I write. But for me, I just keep what the developer decided to use in their projects, especially when it comes to '-O?'. Some optimization levels have been known to introduce runtime issues. For my objects I use -O1, but as you suggested I heard -O2 has no issues either. But I will keep an eye on your document. |
Quote:
In the case of CPPFLAGS it is a requirement for -D_FORTIFY_SOURCE=2 I opened this topic to signal the fact that other distributions use these hardening options. Even the GNU GCC compiler can be compiled with: --enable-default-pie and --enable-default-ssp to enable these options by default. The PIE implementation stage from a previous post indicates default use by Gentoo, Alpine Linux, Fedora, RHEL, Open BSD, Apple, Android. |
An example configuration for the lzop package using a modified SlackBuilds with the options from post 1 applied.
Quote:
|
The situation in the case of PHP:
Slackware (without hardening options) Code:
checksec --file=/usr/local/bin/php Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/usr/lib64/httpd/modules/libphp.so Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=php-fpm8.1-ubuntu Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=libphp8.1.so-ubuntu Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" CFLAGS="-fstack-protector-strong" CXXFLAGS="-fstack-protector-strong" LDFLAGS="-Wl,-z,now,-s" EXTRA_LDFLAGS_PROGRAM="-Wl,-pie" and adding options: --disable-rpath --with-pic Now I have: Code:
checksec --file=/usr/local/bin/php Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/usr/lib64/httpd/modules/libphp.so Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE |
Quote:
|
RELRO, STACK CANARY, PIE, FORTIFY differ from what Ubuntu has in the case of PHP.
Canary is one of the recommended hardening options in the document here and the list of contributors is impressive. I don't think I should bother myself if they proposed this. Other explanations: https://lwn.net/Articles/584225/ If Linus Torvalds also hit his head with this, it means that it is still something.:) https://www.redhat.com/en/blog/secur...-fortifysource |
beginning with GCC 14, new option is going to be introduced
Quote:
which will cover: Quote:
|
Quote:
We will need a mass rebuild and a lot of work.:) Some argue not to modify the compilation options that the packages come with by default, but the truth is that not all developers deal with these options, others leave it to the distribution maintainers. An example where the developers have taken care of this is ssh, although the Slackware SlackBuild only contains the options: Quote:
Code:
checksec --file=/usr/bin/ssh Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE |
For PostgreSQL
CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" CFLAGS="-fPIC -fstack-protector-strong" CXXFLAGS="-fPIC -fstack-protector-strong" LDFLAGS="-Wl,-z,now,-s" LDFLAGS_EX="-Wl,-pie" LDFLAGS_SL="-Wl,-shared" and adding option: --disable-rpath As an observation, the configuration in PostreSQL is very well done with the possibility to set: LDFLAGS_EX="-Wl,-pie" -> for executables LDFLAGS_SL="-Wl,-shared" -> for shared libraries |
Dovecot (like PostgreSQL), it is quite well built by default, the only changes are:
LDFLAGS="-Wl,-s,--enable-new-dtags" -s -> strip binary --enable-new-dtags -> change RPATH with RUNPATH |
I would suggest hardened malloc also please look at hardened Gentoo. I never had any problems with hardened Gentoo. Also some things worth checking out you can find at HardenedBSD site. In general you will almost need separate version of Slackware I doubt that this is feasible.
|
It seems like, if you want to use compiler hardening functions, and want your software to build/work, you have to do it on a case to case basis, rather than as a general rule, no?
In that case, it would be better to add compile time options in Slackbuild scripts, rather than to change compiler defaults. Or add a set of different variations/rules and #include these in Slackbuild scripts on a case to case basis.. |
Quote:
Compiling GCC by default with some of these hardening options would be a more elegant solution, but this also requires testing. The simplest solution is to add these options to the compilation from sources/SlackBuilds, but this also requires testing/studying the configure/Makefile files and of course the installation instructions. I say that there is still a lot of work to standardize approaches in this case. |
Postfix (without dynamically-linked library support).
Here the compilation is a bit different.:) From here (section 4.3 - Building with Postfix position-independent executables (Postfix ≥ 3.0)) To make makefiles command is added: pie=yes The other options are chosen (section 4.7 - Overriding other compile-time features) To make makefiles command is added: OPT="-O2" To CCARGS is added: "-Wl,-z,now,-s -fstack-protector-strong -D_FORTIFY_SOURCE=2" |
Network UPS Tools (NUT)
CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" CFLAGS="-fPIC -pie -fstack-protector-strong" CXXFLAGS="-fPIC -pie -fstack-protector-strong" LDFLAGS="-Wl,-z,now,-s" A slightly different configuration from the previous ones in the case of pie. Maybe because of the different GCC standards used in the Makefile (-std=gnu99, -std=gnu++11). |
This is the end of my experiment of using hardening options for packages compiled from sources.
The packages compiled in this way were: 1. 7-Zip (manual compilation from sources); 2. DCC (Distributed Checksum Clearinghouses); 3. pax (build from SlackBuilds); 4. lzop (compile from SlackBuilds); 5. PHP (manual compilation from sources); 6. PostgreSQL (manual compilation from sources); 7. Dovecot (manual compilation from sources); 8. Postfix (manual compilation from sources); 9. Network UPS Tools (NUT) (manual compilation from sources); 10. Squid (manual compilation from sources). After this exercise I could conclude: 1. some of these options could be enabled by default by the proper compilation of the compiler; Examples: GCC 13 --enable-default-pie and --enable-default-ssp GCC 14 -hardened 2. the following options were used in almost every package CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" CFLAGS="-fstack-protector-strong" CXXFLAGS="-fstack-protector-strong" LDFLAGS="-Wl,-z,now,-s" 3. some packages implement configuration options for some of these options Examples: --with-pic (does not always work and then the respective flag must be added) --disable-rpath pie=yes 4. not all packages properly implement separate options for executables and shared libraries 5. I tested all these changes for each package compiled in this way using the checksec utility (from Github with all pull requests accepted) and comparing my results with those of Ubuntu and Fedora (Fedora seems to me to compile packages more strictly than Ubuntu from the point of view of checksec). Once this stage is finished, I am thinking about the following stages: 1. compiling Clamav with these options (uses CMake, which I still have to learn about); 2. to apply these options also for the Slackware packages (which are part of the basic distribution, for example httpd, bind, etc.) that implement services used on my servers. |
Not sure "1." is a proper compilation of the compiler for packages that are suppose to build and generally work as intended across a large range of use cases. It might not even be the proper option for a specific use case, on a single computer. It's probably a better approach to do this on a case to case basis in the buildscripts, rather than as a default, which would be somewhat similar to Gentoo, no? Not sure even hardened Gentoo sets these things as defaults in the compiler.
It could be possible to test this just for fun with "make_world.sh". But heck, you'd need to change all the compilers. |
Quote:
However, I have also seen theories that support the application of these options to the compiler and their deactivation in specific cases where they do not work. https://wiki.gentoo.org/wiki/Hardened_Gentoo Quote:
|
Quote:
|
Quote:
Unfortunately, I don't have (now) neither the time nor the hardware for such a thing. Time is a luxury now (I'm very busy at my basic job) so all I can do is take it on individually chosen packages during breaks. So maybe I will reach a result if it is possible or not.:) For my basic job, Slackware is my choice (I could have used Ubuntu, Debian even Fedora considering that I started in the Linux world with Red Hat as long as it was free of charge) but also my responsibility, if something happens I am the only culprit. |
Clamav (with CMake)
It was quite easy until the end and I learned a lot.:) -D CMAKE_C_FLAGS="-O2 -D_FORTIFY_SOURCE=2 -fPIC -fstack-protector-strong" -D CMAKE_CXX_FLAGS="-O2 -D_FORTIFY_SOURCE=2 -fPIC -fstack-protector-strong" -D CMAKE_EXE_LINKER_FLAGS="-Wl,-pie,-z,now,-s" -D CMAKE_SHARED_LINKER_FLAGS="-Wl,-shared,-z,now,-s" -D CMAKE_SKIP_RPATH=ON The only problem that has arisen is related to the fact that CMake does not yet have support for CPPFLAGS. The friends at ArchLinux used the solution of adding the flags from CPPFLAGS to CFLAGS and CXXFLAGS. https://wiki.archlinux.org/title/Use...age_guidelines Quote:
|
Quote:
In this case, the correct solution would be to compile at source with these options, recompiling means twice the work. |
A few more useful observations:
1. some packages (depending on the compilation standard used or C/C++) do not accept the "-pie" flag in LDFLAGS (linking error), the solution is to add it to CFLAGS and CPPFLAGS. Examples bind, Network UPS Tools (NUT); 2. binary stripping can be done during compilation (LFDLAGS="-Wl,-s") or using the strip command on already generated executables. It seems that the first option is recommended. I have not met cases in which it is not possible; https://www.baeldung.com/linux/strip-executables 3. the most problematic verification in checksec is RPATH and RUNPATH, which are generally recommended not to be used (Fedora does this for all the packages I checked). If it is still needed, RUNPATH is recommended, which can be obtained by adding in LDFLAGS="-Wl,--enable-new-dtags" https://blog.tremily.us/posts/rpath/ |
Quote:
Code:
#!/bin/sh |
A good script!:)
I tested it on a test server and it found issues for: llvm-17.0.6-x86_64-1 ruby-3.2.2-x86_64-1 |
Bind (build from official Slackware source)
https://www.linuxquestions.org/quest...0/#post6472478 |
python-PyYAML (build from official Slackware source)
Code:
CFLAGS="-fPIC -fstack-protector-strong" CXXFLAGS="-fPIC -fstack-protector-strong" LDFLAGS="-Wl,-z,now,-s" python3 setup.py install --root=$PKG || exit 1 Quote:
|
iucode_tool (build from SlackBuilds)
Code:
CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" CXXFLAGS does not appear anywhere in the documentation or in the command output: Code:
./configure --help Quote:
Code:
checksec --file=/usr/sbin/iucode_tool Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE |
What's the point of hardening every executable in the distribution? I can see that those that run as root or that get arbitrary input from the network could use hardening, but the vast majority of executables just run under the user's identity. I don't think that stack smashing the latter would get you any special privileges.
|
Simple, as in real life, everything depends on the chosen security options.:)
At home, you can opt for the installation of a security system for the whole house, only for certain parts or not at all. In the business environment, I don't think you can afford to neglect security. Analogy: home = home PC business = business workstation/server In the first post of this thread, there is a link to a document related to this aspect made by representatives from Ericsson, Intel, Linux Foundation, IBM, Micro$oft, Google, Canonical (Ubuntu), RHEL, etc in section 7. Contributors. Also, section 10. References is quite extensive. The GNU Compiler Collection (GCC) has specific options for these hardening flags which, if enabled when compiling the compiler, become default when using the compiler executable thus generated (section 2.2. What should you do when compiling compilers?). In section 3. Recommended Compiler Options there are links related to this topic from major Linux distributions such as Debian, Gentoo, Fedora, OpenSUSE and Ubuntu. If we were discussing how difficult it would be to do this with the two possible solutions: 1. compiling the compiler with these options to become default (there will be cases of packages that do not compile and will have to be modified manually); 2. compiling each package with manual setting of these flags. Both variants require a lot of effort and a lot of testing, but other distributions have already done it. Even for distributions that have package maintainers (e.g. Debian) this took quite a long time but it was done. |
Duplicate post, I have no idea why?
I had no intention of repeating anything.:) If I delete it, both are deleted.:confused: |
Quote:
|
:DMaybe what I wrote seemed important to the forum and thought to repeat the post.:D
|
Apache (build from official Slackware source)
Code:
CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" Fix for build with libxml2-2.12.3 https://github.com/apache/httpd/pull/393/files |
Since glibc 2.34 and GCC 12, there has been a new fortification level (_FORTIFY_SOURCE=3).
Here for example : https://developers.redhat.com/articl...size_detection |
Quote:
-O2 is not a pre-processor option. It belongs in CFLAGS not CPPFLAGS. |
Quote:
I received a compilation error stating this. I will still study the problem and I will come back.:) So far I have found this https://steveyang.blog/en/tag/how-to...ization-level/ and: https://developers.redhat.com/articl...d_shadow_stack https://bbs.archlinux.org/viewtopic.php?id=225086 https://lists.gnu.org/archive/html/a.../msg00003.html https://lists.archlinux.org/pipermai...il/024776.html |
1 Attachment(s)
Quote:
An example for Clamav on my last Pull Request. https://github.com/Cisco-Talos/clama...cks#step:9:240 In the document from the first post of this thread it appears: Quote:
https://bugs.launchpad.net/ubuntu/+s...3/+bug/2012440 There has been some discussion in this thread about using these hardening options.:) I found in the previous link the reference to: https://github.com/jvoisin/compiler-flags-distro The respective document presents the status of the implementation of these options for several distributions of Linux, Android and Google Chrome. It is a bit difficult to read the document because of the scroll bars, but I am attaching it in Adobe Acrobat Reader format. |
GRUB 2.12 (build from official Slackware source)
Code:
CPPFLAGS="-O2 -D_FORTIFY_SOURCE=2" 1. Stack canary "-fstack-protector" (-fstack-protector!=-fstack-protector-strong) can be enabled by default through the "--enable-stack-protector" configuration option, but only for *-efi architectures by modifying grub.SlackBuild, something already done by Didier Spaier here. 2. Build as position-independent code (-fPIE -pie) is disabled by the GRUB maintainers in the configure.ac file, but Fedora and Ubuntu (as examples) have changed this. Code:
checksec --file=usr/sbin/grub2-install-fedora Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/tmp/2/grub-probe-fedora Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Code:
checksec --file=/tmp/2/grub-probe-ubuntu Code:
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE I will test the configuration for a few days and then when GRUB comes out of "testing" I will apply it to the production servers. |
A new version of the "Compiler Options Hardening Guide for C and C++" document.
Quote:
|
Given the concerns regarding software memory safety issues raised by NSA, White House Office of the National Cyber Director (ONCD) for C/C++ but also the fact that the recommendations regarding the use of other programming languages cannot be put into practice easily and immediately because the amount of C and C++ code written over the years is immense, the solution is to secure what we had now until we can move on to something else.
So let's build more secure ELF binaries and check what we're using. I've talked about building in previous posts, but I've also talked a bit about how to test binaries using checksec (Bash script). There is also the alternative HardeningMeter (Python based) which I haven't used yet, I just read about it. The author says that checksec should be improved, so I started to better document myself about the development of checksec and to test the new versions. After checking the test files (tests/binaries/output) from checksec with both applications, the conclusion is that HardeningMeter is the one that suffers from the lack of accuracy and I do not recommend its use. That's how I found out that there is a large rewrite in progress and it seems that things are moving. Checksec 2.7.0 was released last week and is already there checksec 2.7.1 tag with improved detection for Fortify source including tests for verification. If someone wants/is curious to find out how Slackware compares to, for example, Ubuntu, you can download the checksec script from the 2.7.1 link and run it to check all running processes: Code:
./checksec --proc-all Ubuntu 24.04 LTS (Noble Numbat) released, I will test it a bit.:scratch: |
Contrary to Linux From Scratch's warning:
Quote:
|
All times are GMT -5. The time now is 07:00 PM. |