# HG changeset patch # User Andre Heinecke # Date 1392048895 0 # Node ID 524cd4908656d61fe9f0e2c6f20a950922b82cb3 # Parent cb0cde2c5eb9571d46f6dc694a2488b063465c99 Build infrastructure Add hardening flags Add static_check target for flawfinder and cppcheck diff -r cb0cde2c5eb9 -r 524cd4908656 CMakeLists.txt --- a/CMakeLists.txt Fri Feb 07 11:41:15 2014 +0000 +++ b/CMakeLists.txt Mon Feb 10 16:14:55 2014 +0000 @@ -11,7 +11,6 @@ include_directories(${Qt5Widgets_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS}) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") set(M13UI_SOURCES ui/main.cpp @@ -22,6 +21,17 @@ ui/icons.qrc ) +# Warn level to be used for privileged parts +set(WARN_HARDENING_FLAGS " -Wall -Wextra -Wconversion -Wformat-security") + +# Hardening flags +set(HARDENING_FLAGS " -Werror -fstack-protector-all") +set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wstack-protector") +set(HARDENING_FLAGS " ${HARDENING_FLAGS} --param ssp-buffer-size=4") +set(HARDENING_FLAGS " ${HARDENING_FLAGS} -pie -fPIE -ftrapv") +set(HARDENING_FLAGS " ${HARDENING_FLAGS} -D_FORTIFY_SOURCE=2 -O2") +set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wl,-z,relro,-z,now") + if(UNIX) # See: https://bugreports.qt-project.org/browse/QTBUG-35918 # XCB_EXTRA_LIBS should be gotten automatically. @@ -48,10 +58,32 @@ -lglu32 -lopengl32 -lgdi32 -ljpeg -lpng -lQt5Core -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lz -lsicuin -lsicuuc -lsicudt -lpcre16) set(EXTRA_STATIC_LIBS Qt5::QWindowsIntegrationPlugin ${WINDOWS_EXTRA_LIBS}) + + set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wl,dynamicbase -Wl,nxcompat") endif() qt5_add_resources(M13UI_SOURCES ${M13UI_RESOURCES}) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${HARDENING_FLAGS}") + add_executable(m13ui ${M13UI_SOURCES}) target_link_libraries(m13ui Qt5::Widgets ${EXTRA_STATIC_LIBS}) + +add_custom_target(static_check) + +# CPPCheck +include(GenerateCppcheck) +generate_cppcheck(SOURCES ${M13UI_SOURCES} "" "" m13ui) +add_dependencies(static_check cppcheck) + +# FlawFinder +find_program(FLAWFINDER_PATH flawfinder DOC "flawfinder path") +if (FLAWFINDER_PATH) + add_custom_target(flawfinder COMMENT "FlawFinder" VERBATIM COMMAND ${FLAWFINDER_PATH} + ${CMAKE_SOURCE_DIR}/ui + ) + add_dependencies(static_check flawfinder) +endif (FLAWFINDER_PATH) + diff -r cb0cde2c5eb9 -r 524cd4908656 cmake/GenerateCppcheck.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/GenerateCppcheck.cmake Mon Feb 10 16:14:55 2014 +0000 @@ -0,0 +1,141 @@ +# - Generate a cppcheck documentation for a project. +# The function GENERATE_CPPCHECK is provided to create a "cppcheck" target that +# performs static code analysis using the cppcheck utility program. +# +# GENERATE_CPPCHECK(SOURCES +# [SUPPRESSION_FILE ] +# [ENABLE_IDS ] +# [TARGET_NAME ] +# [INCLUDES ]) +# +# Generates a target "cppcheck" that executes cppcheck on the specified sources. +# Sources may either be file names or directories containing files where all +# C++ files will be parsed automatically. Use directories whenever possible +# because there is a limitation in arguments to pass to the cppcheck binary. +# SUPPRESSION_FILE may be give additionally to specify suppressions for# +# cppcheck. The sources mentioned in the suppression file must be in the same +# format like given for SOURCES. This means if you specified them relative to +# CMAKE_CURRENT_SOURCE_DIR, then the same relative paths must be used in the +# suppression file. +# ENABLE_IDS allows to specify which additional cppcheck check ids to execute, +# e.g. all or style. They are combined with AND. +# With TARGET_NAME a different name for the generated check target can be +# specified. This is useful if several calles to this function are made in one +# CMake project, as otherwise the target names collide. +# Additional include directories for the cppcheck program can be given with +# INCLUDES. +# +# cppcheck will be executed with CMAKE_CURRENT_SOURCE_DIR as working directory. +# +# This function can always be called, even if no cppcheck was found. Then no +# target is created. +# +# Copyright (C) 2011 by Johannes Wienke +# +# 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, 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. +# + +GET_FILENAME_COMPONENT(GENERATE_CPPCHECK_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH) + +# FIND_PACKAGE(Cppcheck) +find_program(CPPCHECK_EXECUTABLE +cppcheck +) + +if(CPPCHECK_EXECUTABLE) + set(CPPCHECK_FOUND True) +endif() + +include(ParseArguments) + +FUNCTION(GENERATE_CPPCHECK) + + IF(CPPCHECK_FOUND) + + PARSE_ARGUMENTS(ARG "SOURCES;SUPPRESSION_FILE;ENABLE_IDS;TARGET_NAME;INCLUDES" "" ${ARGN}) + + SET(TARGET_NAME "cppcheck") + SET(TARGET_NAME_SUFFIX "") + # parse target name + LIST(LENGTH ARG_TARGET_NAME TARGET_NAME_LENGTH) + IF(${TARGET_NAME_LENGTH} EQUAL 1) + SET(TARGET_NAME ${ARG_TARGET_NAME}) + SET(TARGET_NAME_SUFFIX "-${ARG_TARGET_NAME}") + ENDIF() + + SET(CPPCHECK_CHECKFILE "${CMAKE_BINARY_DIR}/cppcheck-files${TARGET_NAME_SUFFIX}") + SET(CPPCHECK_REPORT_FILE "${CMAKE_BINARY_DIR}/cppcheck-report${TARGET_NAME_SUFFIX}.xml") + SET(CPPCHECK_WRAPPER_SCRIPT "${CMAKE_BINARY_DIR}/cppcheck${TARGET_NAME_SUFFIX}.cmake") + + # write a list file containing all sources to check for the call to + # cppcheck + SET(SOURCE_ARGS "") + FOREACH(SOURCE ${ARG_SOURCES}) + SET(SOURCE_ARGS "${SOURCE_ARGS} \"${SOURCE}\"") + ENDFOREACH() + + # prepare a cmake wrapper to write the stderr output of cppcheck to + # the result file + + # suppression argument + LIST(LENGTH ARG_SUPPRESSION_FILE SUPPRESSION_FILE_LENGTH) + IF(${SUPPRESSION_FILE_LENGTH} EQUAL 1) + GET_FILENAME_COMPONENT(ABS "${ARG_SUPPRESSION_FILE}" ABSOLUTE) + MESSAGE(STATUS "Using suppression file ${ABS}") + SET(SUPPRESSION_ARGUMENT --suppressions) + SET(SUPPRESSION_FILE "\"${ABS}\"") + ENDIF() + + # includes + SET(INCLUDE_ARGUMENTS "") + FOREACH(INCLUDE ${ARG_INCLUDES}) + SET(INCLUDE_ARGUMENTS "${INCLUDE_ARGUMENTS} \"-I${INCLUDE}\"") + ENDFOREACH() + + # enabled ids + SET(ID_LIST "") + FOREACH(ID ${ARG_ENABLE_IDS}) + SET(ID_LIST "${ID_LIST},${ID}") + ENDFOREACH() + IF(ID_LIST) + STRING(LENGTH ${ID_LIST} LIST_LENGTH) + MATH(EXPR FINAL_LIST_LENGTH "${LIST_LENGTH} - 1") + STRING(SUBSTRING ${ID_LIST} 1 ${FINAL_LIST_LENGTH} FINAL_ID_LIST) + SET(IDS_ARGUMENT "\"--enable=${FINAL_ID_LIST}\"") + ELSE() + SET(IDS_ARGUMENT "") + ENDIF() + + FILE(WRITE ${CPPCHECK_WRAPPER_SCRIPT} +" +EXECUTE_PROCESS(COMMAND \"${CPPCHECK_EXECUTABLE}\" ${INCLUDE_ARGUMENTS} ${SUPPRESSION_ARGUMENT} ${SUPPRESSION_FILE} ${IDS_ARGUMENT} --inline-suppr --xml ${SOURCE_ARGS} + RESULT_VARIABLE CPPCHECK_EXIT_CODE + ERROR_VARIABLE ERROR_OUT + WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\") +IF(NOT CPPCHECK_EXIT_CODE EQUAL 0) + MESSAGE(FATAL_ERROR \"Error executing cppcheck for target ${TARGET}, return code: \${CPPCHECK_EXIT_CODE}\") +ENDIF() +IF(ERROR_OUT) + MESSAGE(\"Detected errors:\\n\${ERROR_OUT}\") +ENDIF() +FILE(WRITE \"${CPPCHECK_REPORT_FILE}\" \"\${ERROR_OUT}\") +" + ) + + ADD_CUSTOM_TARGET(${TARGET_NAME} ${CMAKE_COMMAND} -P "${CPPCHECK_WRAPPER_SCRIPT}" + COMMENT "Generating cppcheck result ${TARGET_NAME}") + + MESSAGE(STATUS "Generating cppcheck target with name ${TARGET_NAME}") + + ENDIF() + +ENDFUNCTION() diff -r cb0cde2c5eb9 -r 524cd4908656 cmake/ParseArguments.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/ParseArguments.cmake Mon Feb 10 16:14:55 2014 +0000 @@ -0,0 +1,52 @@ +# Parse arguments passed to a function into several lists separated by +# upper-case identifiers and options that do not have an associated list e.g.: +# +# SET(arguments +# hello OPTION3 world +# LIST3 foo bar +# OPTION2 +# LIST1 fuz baz +# ) +# PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments}) +# +# results in 7 distinct variables: +# * ARG_DEFAULT_ARGS: hello;world +# * ARG_LIST1: fuz;baz +# * ARG_LIST2: +# * ARG_LIST3: foo;bar +# * ARG_OPTION1: FALSE +# * ARG_OPTION2: TRUE +# * ARG_OPTION3: TRUE +# +# taken from http://www.cmake.org/Wiki/CMakeMacroParseArguments + +MACRO(PARSE_ARGUMENTS prefix arg_names option_names) + SET(DEFAULT_ARGS) + FOREACH(arg_name ${arg_names}) + SET(${prefix}_${arg_name}) + ENDFOREACH(arg_name) + FOREACH(option ${option_names}) + SET(${prefix}_${option} FALSE) + ENDFOREACH(option) + + SET(current_arg_name DEFAULT_ARGS) + SET(current_arg_list) + FOREACH(arg ${ARGN}) + SET(larg_names ${arg_names}) + LIST(FIND larg_names "${arg}" is_arg_name) + IF (is_arg_name GREATER -1) + SET(${prefix}_${current_arg_name} ${current_arg_list}) + SET(current_arg_name ${arg}) + SET(current_arg_list) + ELSE (is_arg_name GREATER -1) + SET(loption_names ${option_names}) + LIST(FIND loption_names "${arg}" is_option) + IF (is_option GREATER -1) + SET(${prefix}_${arg} TRUE) + ELSE (is_option GREATER -1) + SET(current_arg_list ${current_arg_list} ${arg}) + ENDIF (is_option GREATER -1) + ENDIF (is_arg_name GREATER -1) + ENDFOREACH(arg) + SET(${prefix}_${current_arg_name} ${current_arg_list}) +ENDMACRO(PARSE_ARGUMENTS)