Доброго времени суток. Сегодня расскажу о том как выполнить часть работ по сертификации кода по требованиям РД ФСТЭК(контроль отсутствия недкларированных возможностей). В требованиях по статическому анализу есть требование контроля компиляции файлов или ответить на вопрос все ли файлы компилируются в объектные файлы и есть ли файлы которые не компилируются. Для этого составим списки файлов 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
…