Доброго времени суток. Сегодня расскажу о том как выполнить часть работ по сертификации кода по требованиям РД ФСТЭК(контроль отсутствия недкларированных возможностей). В требованиях по статическому анализу есть требование контроля компиляции файлов или ответить на вопрос все ли файлы компилируются в объектные файлы и есть ли файлы которые не компилируются. Для этого составим списки файлов cpp, c, h. Для этого зайдем в папку с исходниками и выполним команду «find. -iname *.cpp», «find. -iname *.c», «find. -iname *.o» запишем выдачу в файлы «c_cpp_files.txt» и «h_files.txt».
У нас получится файлы со следующим содержимым:
и соответственно следующее:
Далее проанализируем какие Include-ы встречаются в каких *.c или *.cpp файлах. Для этого предназначен следующий код:
файл Incl.java:
файл InclPoints.java:
файл Includes.java:
файл Point.java:
и файл Main.java:
Алгоритм следующий:
Сначала просматриваем файлы с/cpp и ищем с помощью регулярного выражения директиву #include <…> запоминаем данную стоку и номер строки для файла. Далее для каждой найденной конструкции проверяем наличие include для h файлов. В итоге проверяем то же самое для *.h файлов. Если h файл не где не был подключен, то есть вероятность того, что он был подключен в используемых *.h файлах, для этого проверяем еще один раз наличие подключений *.h файлах в подключенных *.h файлах.
В итоге делаем отчет следующего вида:
У нас получится файлы со следующим содержимым:
./arch/powerpc/math-emu/fmul.c
./arch/powerpc/math-emu/lfd.c
./arch/powerpc/math-emu/fsqrt.c
./arch/powerpc/math-emu/fsub.c
./arch/powerpc/math-emu/fnmsub.c
./arch/powerpc/math-emu/frsqrte.c
./arch/powerpc/math-emu/mtfsb0.c
...
и соответственно следующее:
./arch/powerpc/include/asm/udbg.h
./arch/powerpc/include/asm/termios.h
./arch/powerpc/include/asm/immap_cpm2.h
./arch/powerpc/include/asm/linkage.h
./arch/powerpc/include/asm/rio.h
./arch/powerpc/include/asm/dma-mapping.h
...
Далее проанализируем какие Include-ы встречаются в каких *.c или *.cpp файлах. Для этого предназначен следующий код:
файл Incl.java:
/*
включение одного фала
со строкой и номером линии
*/
public class Incl {
public String text;
public int line;
}
файл InclPoints.java:
import java.io.File;
import java.util.List;
public class InclPoints {
public File headers;
public List<Point> points;
}
файл Includes.java:
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class Includes {
public File file; // файл в котором найден инклюд
public List<Incl> incl=new ArrayList<>(); // массив включений
}
файл Point.java:
import java.io.File;
public class Point
{
public File src;
public Incl incl;
}
и файл Main.java:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static File reportFile;
public static File header_file;
public static File sources_file;
public static Map<Integer,File> headers_nouse;
public static Map<Integer,File> headers_withuse;
public static int header_nouse_counter;
public static int header_withuse_counter;
private static List<InclPoints> incpo_lst;
//public List<InclPoints> incpo_lst;
public static void main(String[] args)
{
func1(args);
}
public static Map<Integer,File> readCodeList(String path_to_code)
{
Map<Integer,File> code_files= new TreeMap<>();
int file_counter=0;
try (BufferedReader br = new BufferedReader(new FileReader(path_to_code))) {
String current_source_line;
while ((current_source_line = br.readLine()) != null) {
current_source_line=current_source_line.trim();
code_files.put(file_counter, new File(current_source_line));
file_counter++;
}
}
catch(IOException ex){
System.out.println(ex.getMessage());
}
return code_files;
}
public static Map<Integer,File> readheadersFile(String header_file_path)
{
Map<Integer,File> header_files= new TreeMap<>();
int headers_counter=0;
try (BufferedReader br = new BufferedReader(new FileReader(header_file_path))) {
String current_header_line;
while ((current_header_line = br.readLine()) != null) {
current_header_line=current_header_line.trim();
header_files.put(headers_counter,new File(current_header_line));
headers_counter++;
}
}
catch(IOException ex){
System.out.println(ex.getMessage());
}
return header_files;
}
public static void func1(String[] args){
String header_file_name=args[0];
String sources_file_name=args[1];
reportFile=new File("Report.txt");
header_file=new File(header_file_name);
sources_file=new File(sources_file_name);
Map<Integer,File> code_files= readCodeList( sources_file.toPath().toString() );
System.out.println("Total number of source files="+code_files.size());
// прочитать список заголовочных файлов
Map<Integer,File> header_files=readheadersFile(header_file.toPath().toString());
System.out.println("Total number of header files = "+header_files.size());
//Проверяем заголовочные файлы на используемость
System.out.println("Proccessing Level 1 dependencies");
List<InclPoints> result1=search_headers2(header_files,code_files);
headers_nouse=new TreeMap<Integer,File>();
headers_withuse = new TreeMap<Integer,File>();
int headers_nouse_counter=0;
int headers_withuse_counter=0;
for(InclPoints ip:result1)
{
if(ip.points.size() ==0)
{
headers_nouse.put(headers_nouse_counter, ip.headers);
headers_nouse_counter++;
}
else
{
headers_withuse.put(headers_withuse_counter,ip.headers);
headers_withuse_counter++;
}
}
System.out.println("Proccessing Level 2 dependencies");
List<InclPoints> result2=search_headers2(headers_nouse,headers_withuse);
for(InclPoints ip: result1)
{
appendUsingOutputStream(reportFile.toPath().toString(),"Header file : "+ip.headers+"\n");
for(Point p: ip.points) {
appendUsingOutputStream(reportFile.toPath().toString(), " usage : "+p.src.toPath().toString()+" \n");
appendUsingOutputStream(reportFile.toPath().toString(), " line "+p.incl.line+" : "+p.incl.text+" \n");
}
appendUsingOutputStream(reportFile.toPath().toString(), "Number of entries = "+ip.points.size()+" \n\n");
}
for(InclPoints ip: result2)
{
appendUsingOutputStream(reportFile.toPath().toString(),"Header file : "+ip.headers+"\n");
for(Point p: ip.points) {
appendUsingOutputStream(reportFile.toPath().toString(), " usage : "+p.src.toPath().toString()+" \n");
appendUsingOutputStream(reportFile.toPath().toString(), " line "+p.incl.line+" : "+p.incl.text+" \n");
}
appendUsingOutputStream(reportFile.toPath().toString(), "Number of entries = "+ip.points.size()+" \n\n");
}
}
public static List<InclPoints> search_headers2(Map<Integer,File> headers,Map<Integer,File> sources)
{
List<Includes> incs_lst=new ArrayList<Includes>();
incpo_lst = new ArrayList<InclPoints>();
for(File curFilePath : sources.values())
{
Includes incs=new Includes();
incs.file=curFilePath;
try{
BufferedReader cur_file = new BufferedReader(new FileReader(curFilePath));
int line_number=0;
for(String cur_line; (cur_line = cur_file.readLine()) != null; line_number++) {
Pattern p1 = Pattern.compile("#include.+?\\W.+\\W");
Matcher m2 = p1.matcher(cur_line);
if(m2.find())
{
Incl incl=new Incl();
incl.text = cur_line.trim();
incl.line = line_number;
incs.incl.add(incl);
}
}
cur_file.close();
incs_lst.add(incs);
}catch(IOException e)
{
System.out.println(e.getMessage());
}
}
// перебираем heiders и ищим в инклюдах используемые
for(File current_header: headers.values())
{
InclPoints point=new InclPoints();
point.headers=current_header;
point.points= new ArrayList<Point>();
String header="";
Pattern p = Pattern.compile("\\/?([\\w\\-\\.]+?)\\.h");
String text=current_header.getPath();
Matcher m = p.matcher(text);
if(m.find())
{
System.out.println(String.format("|%-100s|",current_header));
header=current_header.getPath().substring(m.start(), m.end());
for(Includes inc:incs_lst)
{
for(Incl incl:inc.incl) {
Pattern p1 = Pattern.compile("#include.+?\\W" + header + "\\W");
Matcher m2 = p1.matcher(incl.text);
if (m2.find()) {
Point po= new Point();
po.src= inc.file;
po.incl=incl;
point.points.add(po);
System.out.println(String.format("|%-60s| %-40s |",po.src.toString() ,po.incl.text));
}
}
}
}
incpo_lst.add(point);
}
return incpo_lst;
}
// обновляем файл с помощью FileWriter
private static void appendUsingOutputStream(String fileName, String data) {
OutputStream os = null;
try {
//в конструкторе FileOutputStream используем флаг true, который обозначает обновление содержимого файла
os = new FileOutputStream(new File(fileName), true);
os.write(data.getBytes(), 0, data.length());
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Алгоритм следующий:
Сначала просматриваем файлы с/cpp и ищем с помощью регулярного выражения директиву #include <…> запоминаем данную стоку и номер строки для файла. Далее для каждой найденной конструкции проверяем наличие include для h файлов. В итоге проверяем то же самое для *.h файлов. Если h файл не где не был подключен, то есть вероятность того, что он был подключен в используемых *.h файлах, для этого проверяем еще один раз наличие подключений *.h файлах в подключенных *.h файлах.
В итоге делаем отчет следующего вида:
Proccessing Level 1 dependencies
Header file : ./arch/powerpc/include/asm/udbg.h
usage : ./arch/powerpc/platforms/85xx/izgib.c
line : #include <asm/udbg.h>
usage : ./arch/powerpc/sysdev/cpm_common.c
line : #include <asm/udbg.h>
usage : ./arch/powerpc/kernel/legacy_serial.c
line : #include <asm/udbg.h>
usage : ./arch/powerpc/kernel/setup-common.c
line : #include <asm/udbg.h>
usage : ./arch/powerpc/kernel/setup_32.c
line : #include <asm/udbg.h>
usage : ./arch/powerpc/kernel/udbg.c
line : #include <asm/udbg.h>
usage : ./arch/powerpc/kernel/irq.c
line : #include <asm/udbg.h>
usage : ./arch/powerpc/kernel/udbg_16550.c
line : #include <asm/udbg.h>
Number of entries = 8
Header file : ./arch/powerpc/include/asm/termios.h
usage : ./net/unix/af_unix.c
line : #include <linux/termios.h>
usage : ./net/netlink/af_netlink.c
line : #include <linux/termios.h>
usage : ./drivers/tty/tty_ioctl.c
line : #include <linux/termios.h>
Number of entries = 3
…