Пример embed_ext2

Пример показывает, как встроить новую файловую систему в виртуальную файловую систему (VFS), поставляемую в составе KasperskyOS Community Edition.

В этом примере сущность Client тестирует работу файловых систем (ext2, ext3, ext4) на блочных устройствах. Для этого Client обращается по IPC к драйверу файловой системы Ext2, а Ext2 в свою очередь обращается по IPC к блочному устройству.

Файловые системы ext2 и ext3 работают с настройками по умолчанию. Файловая система ext4 работает, если отключить все, кроме журнала (mkfs.ext4 -O ^extent,^huge_file,^flex_bg,^uninit_bg,^dir_nlink,^extra_isize /dev/foo).

Поставляемые ресурсы

В пример входят следующие образы жестких дисков с файловыми системами:

Для архитектуры Arm поддерживается работа только с одной SD-картой, поэтому используется образ hdd_arm.img.

Этот пример не содержит реализации драйверов блочных устройств, с которыми работает Client (сущности Ata, Sdcard). Эти драйверы поставляются в составе KasperskyOS Community Edition и добавляются в файле сборки ./CMakeLists.txt.

Портирование реализации файловых систем ext2, ext3 и ext4

Портированные файлы с исходным кодом из проекта lwext4 находятся в следующей директории:

./ext2/lwext4/src

Имплементация методов для работы с индексными узлами находится в следующем файле:

ext2/lwext4/src/kos/ext.c

static struct inode_operations _inode_ops =

{

.create = _folder_create_file,

.mkdir = _folder_create_dir,

.unlink = _folder_unlink,

.link = _folder_link,

.symlink = _folder_symlink,

.ftruncate = _ftruncate,

.rename = _folder_rename,

.readdir = _folder_readdir,

.read = _read_file,

.read_symname = _read_symname,

.write = _write_file,

.compare = NULL,

};

EDL-описания сущностей

Client.edl

entity client.Client

Ext2.edl

entity ext2.Ext2

components {

vfs: kl.Vfs

}

Реализация сущности Client

main.c

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/mount.h>

#include <sys/types.h>

enum { MAX_FS_PATH_SIZE = 1024 };

#define TEST_MESSAGE "test_message"

#define TEST_MESSAGE_LEN 12

struct mount_point {

int device_num;

int partition_num;

char *fs_name;

};

/* Точки монтирования для файловых систем ext2, ext3, ext4. */

#ifdef __arm__

static struct mount_point mount_points[] =

{

{ 0, 0, "ext2" },

{ 0, 1, "ext3" },

{ 0, 2, "ext4" }

};

#else

static struct mount_point mount_points[] =

{

{ 0, 0, "ext2" },

{ 1, 0, "ext3" },

{ 2, 0, "ext4" }

};

#endif

/* Функция, монтирующая соответствующую файловую систему для каждого теста. */

static int prepare_mount_point(int case_num, const char *path)

{

char fs_path[MAX_FS_PATH_SIZE];

if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO)) {

printf("Failed to create \"%s\" dir. error %d: \"%s\"\n",

path,

errno,

strerror(errno));

return -1;

}

sprintf(fs_path, "%s%d,%d",

BLKDEV,

mount_points[case_num].device_num,

mount_points[case_num].partition_num);

if (mount(fs_path, path, mount_points[case_num].fs_name, 0, "")) {

printf("Failed to mount %s, %s, %s. error %d: \"%s\"\n",

fs_path,

path,

mount_points[case_num].fs_name,

errno,

strerror(errno));

return -1;

}

return 0;

}

static int perform_test(const char *fs_name, const char *mount_point)

{

char file_name[MAX_FS_PATH_SIZE];

char buffer[TEST_MESSAGE_LEN + 1];

int ret;

int fd;

strcpy(file_name, mount_point);

strcat(file_name, "new_file");

memset(buffer, 0, TEST_MESSAGE_LEN);

fd = open(file_name, O_RDWR | O_CREAT);

if (fd == -1) {

printf("Failed to create new file new_file (error %d: \"%s\")\n",

errno,

strerror(errno));

return -1;

}

ret = write(fd, TEST_MESSAGE, TEST_MESSAGE_LEN);

if (ret != TEST_MESSAGE_LEN) {

printf("Failed to write message to new_file. write() returned %d\n",

ret);

return -1;

}

if (close(fd)) {

printf("Failed to close new_file (error %d: \"%s\")\n",

errno,

strerror(errno));

return -1;

}

fd = open(file_name, O_RDONLY);

if (fd == -1) {

printf("Failed to open existing file new_file (error %d: \"%s\")\n",

errno,

strerror(errno));

return -1;

}

ret = read(fd, buffer, TEST_MESSAGE_LEN);

if (ret != TEST_MESSAGE_LEN) {

printf("Failed to read message from new_file. read() returned %d\n",

ret);

return -1;

}

buffer[TEST_MESSAGE_LEN] = '\0';

printf("%s: %s\n", fs_name, buffer);

if (close(fd)) {

printf("Failed to finally close new_file (error %d: \"%s\")\n",

errno,

strerror(errno));

return -1;

}

if (unlink(file_name)) {

printf("Failed to finally unlink new_file (error %d: \"%s\")\n",

errno,

strerror(errno));

return -1;

}

return 0;

}

int main(void)

{

size_t i;

if (prepare_mount_point(0, "/c")) {

return EXIT_FAILURE;

}

perform_test("ext2", "/c");

if (prepare_mount_point(1, "/d")) {

return EXIT_FAILURE;

}

perform_test("ext3", "/d");

if (prepare_mount_point(2, "/e")) {

return EXIT_FAILURE;

}

perform_test("ext4", "/e");

if (umount("/e") != 0) {

printf("Failed to umount /e. error %d: \"%s\"\n",

errno,

strerror(errno));

return EXIT_FAILURE;

}

if (umount("/d") != 0) {

printf("Failed to umount /d. error %d: \"%s\"\n",

errno,

strerror(errno));

return EXIT_FAILURE;

}

if (umount("/c") != 0) {

printf("Failed to umount /c. error %d: \"%s\"\n",

errno,

strerror(errno));

return EXIT_FAILURE;

}

printf("All devices successfully unmounted\n");

return EXIT_SUCCESS;

}

Init-описание

Сущность Client работает с блочным устройством через драйвер файловой системы ext2.

init.yaml.in

entities:

- name: client.Client

path: client

connections:

- target: ext2.Ext2

id: {var: _VFS_CONNECTION_ID, include: vfs/defs.h}

@INIT_Client_ENTITY_CONNECTIONS+@

- name: ext2.Ext2

path: ext2

@INIT_ext2_ENTITY_CONNECTIONS@

@INIT_EXTERNAL_ENTITIES@

Конфигурация безопасности

Конфигурация безопасности в этом примере разрешает запуск всех сущностей и позволяет любой сущности обращаться к сущностям Core, ext2 и к драйверу блочного устройства.

common.psl

/* Конфигурация безопасности для примера "embed_ext2". */

use nk.base._

/* Объявление сущностей. */

use EDL kl.core.Core

use EDL Einit

use EDL client.Client

use EDL ext2.Ext2

/* Запуск сущностей разрешен. */

execute {

grant ()

}

/* Сообщения типа request разрешены */

request {

grant ()

}

/* Сообщения типа response разрешены */

response {

grant ()

}

/* Вызовы к security interface игнорируются. */

security {

grant ()

}

security_arm.psl

/* Общая политика безопасности */

use common._

/* Только для arm */

use EDL kl.drivers.SDCard

use EDL kl.drivers.BSP

security_x86.psl

/* Общая политика безопасности */

use common._

/* Только для x86 */

use EDL kl.drivers.ATA

use EDL kl.drivers.PCIE

Конфигурация сборки

Генерация EDL-описаний сущностей Client и Ext2 осуществляется непосредственно в скриптах CMake с помощью функции build_entity, которую предоставляет NK.

Инструкции сборки сущности Client

./client/CMakeLists.txt

project (client)

# Инструментарий для работы с парсером NK.

include (platform/nk)

if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")

set (BLKDEV "mmc")

else ()

set (BLKDEV "Ahci0Port")

endif ()

nk_build_edl_files (client_edl_files NK_MODULE "client" EDL "${CMAKE_SOURCE_DIR}/resources/edl/Client.edl")

add_executable (client "src/main.c")

add_dependencies (client client_edl_files)

set_target_compiler_flags_default (client "STANDARD_GNU_11:YES" "STRICT_WARNINGS:YES")

target_link_libraries (client ${vfs_CLIENT_LIB})

set_target_properties (client PROPERTIES COMPILE_DEFINITIONS BLKDEV="${BLKDEV}")

#set_target_properties (client PROPERTIES LINK_FLAGS "-Ttext 0x00800000")

# We do not need default VFS entity here, which comes from ${vfs_CLIENT_LIB}

set_target_properties (client PROPERTIES ${vfs_ENTITY}_REPLACEMENT "")

Инструкции сборки сущности Ext2

./ext2/CMakeLists.txt

project (ext2)

# Реализация файловых систем ext2/3/4

set (HAVE_READDIR YES)

add_subdirectory (lwext4)

# Инструментарий для работы с парсером NK.

include (platform/nk)

nk_build_edl_files (ext2_edl_files NK_MODULE "ext2" EDL "${CMAKE_SOURCE_DIR}/resources/edl/Ext2.edl")

# Target - ext2

add_executable (ext2 "main.c")

add_dependencies (ext2 ext2_edl_files)

# Установка флагов компилятора.

set_target_compiler_flags_default (ext2 "STANDARD_GNU_C99:YES")

# vfs_SERVER_LIB - реализация серверной части сущности файловой системы.

# vfs_IMPLEMENTATION_LIB - реализация виртуальной файловой системы и

# файловых систем ROMFS, RAMFS.

target_link_libraries (ext2 ${vfs_SERVER_LIB} ${vfs_FS_LIB} "-Wl,--whole-archive" lwext4 "-Wl,--no-whole-archive")

#set_target_properties (ext2 PROPERTIES LINK_FLAGS "-Ttext 0x02800000")

Инструкции сборки сущности Einit и образа системы

./einit/CMakeLists.txt

project (einit)

# Инструментарий для работы с образами KasperskyOS.

include (platform/image)

# Установка флагов компиляции.

project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO")

if ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm|aarch64")

set(SECURITY_PSL_FILE src/security_arm.psl)

# Подключение пакета, импортирующего компоненты для работы с SD-картой.

find_package (sdcard REQUIRED)

include_directories (${sdcard_INCLUDE})

# We need SDCARD driver to be connected with our implementation of VFS

set_target_properties (ext2 PROPERTIES ${blkdev_ENTITY}_REPLACEMENT ${sdcard_ENTITY})

# Добавляем цель с копированием образа диска в директорию сборки примера.

add_custom_target (hdd.img

COMMAND ${CMAKE_COMMAND} -E make_directory

${CMAKE_BINARY_DIR}/hdd_part1

COMMAND ${CMAKE_COMMAND} -E make_directory

${CMAKE_BINARY_DIR}/hdd_part2

COMMAND ${CMAKE_COMMAND} -E make_directory

${CMAKE_BINARY_DIR}/hdd_part3

COMMAND ${CMAKE_COMMAND} -E copy_directory

${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd_part1

COMMAND ${CMAKE_COMMAND} -E copy_directory

${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd_part2

COMMAND ${CMAKE_COMMAND} -E copy_directory

${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd_part3

COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -s 128 -%1 33 -%2 33 -%3 33 -p1 ${CMAKE_BINARY_DIR}/hdd_part1 -p2 ${CMAKE_BINARY_DIR}/hdd_part2 -p3 ${CMAKE_BINARY_DIR}/hdd_part3 -img hdd.img)

# Для архитектуры Arm поддерживается работа только с одной SD-картой.

set (QEMU_FLAGS "-nographic -monitor none -sd hdd.img")

set (QEMU_DEPENDENCIES hdd.img)

else ()

set(SECURITY_PSL_FILE src/security_x86.psl)

# Подключение пакета, импортирующего компоненты для работы с ata-устройством.

find_package (ata REQUIRED)

include_directories (${ata_INCLUDE})

# We need ATA driver to be connected with our implementation of VFS

set_target_properties (ext2 PROPERTIES ${blkdev_ENTITY}_REPLACEMENT ${ata_ENTITY})

# Добавляем цели с копированием образов дисков в директорию сборки примера.

add_custom_target (hdd1.img

COMMAND ${CMAKE_COMMAND} -E make_directory

${CMAKE_BINARY_DIR}/hdd1

COMMAND ${CMAKE_COMMAND} -E copy_directory

${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd1

COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${CMAKE_BINARY_DIR}/hdd1 -img hdd1.img -f ext2)

add_custom_target (hdd2.img

COMMAND ${CMAKE_COMMAND} -E make_directory

${CMAKE_BINARY_DIR}/hdd2

COMMAND ${CMAKE_COMMAND} -E copy_directory

${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd2

COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${CMAKE_BINARY_DIR}/hdd2 -img hdd2.img -f ext2)

add_custom_target (hdd3.img

COMMAND ${CMAKE_COMMAND} -E make_directory

${CMAKE_BINARY_DIR}/hdd3

COMMAND ${CMAKE_COMMAND} -E copy_directory

${KL_SDK_ROOT_PATH}/common/hdd ${CMAKE_BINARY_DIR}/hdd3

COMMAND ${KL_SDK_ROOT_PATH}/common/prepare_hdd_img.sh -d ${CMAKE_BINARY_DIR}/hdd3 -img hdd3.img -f ext2)

set (QEMU_FLAGS "-nographic -monitor none \

-device ahci,id=ahci \

-drive id=disk1,file=hdd1.img,if=none -device ide-drive,drive=disk1,bus=ahci.0 \

-drive id=disk2,file=hdd2.img,if=none -device ide-drive,drive=disk2,bus=ahci.1 \

-drive id=disk3,file=hdd3.img,if=none -device ide-drive,drive=disk3,bus=ahci.2")

set (QEMU_DEPENDENCIES hdd1.img hdd2.img hdd3.img)

endif ()

# Образ KasperskyOS для аппаратной платформы.

build_kos_hw_image (kos-image

EINIT_ENTITY EinitHw

CONNECTIONS_CFG "src/init.yaml.in"

SECURITY_PSL "${SECURITY_PSL_FILE}"

IMAGE_FILES client ext2)

# Образ KasperskyOS для QEMU с целями эмуляции (sim, gdbsim, gdb).

build_kos_qemu_image (kos-qemu-image

EINIT_ENTITY EinitQemu

CONNECTIONS_CFG "src/init.yaml.in"

SECURITY_PSL "${SECURITY_PSL_FILE}"

IMAGE_FILES client ext2

QEMU_FLAGS "${QEMU_FLAGS}"

QEMU_DEPENDENCIES "${QEMU_DEPENDENCIES}")

#set_target_properties (EinitQemu PROPERTIES LINK_FLAGS "-Ttext 0x00200000")

Инструкции сборки решения

./CMakeLists.txt

cmake_minimum_required (VERSION 3.12)

# Инициализация библиотеки CMake

include (platform)

initialize_platform ()

# Добавление документации в формате Doxygen

include (platform/doxygen)

add_project_documentation_main_target ()

# Подключение функций установки артефактов.

include (platform/install)

# Подключение пакета, импортирующего компоненты для работы с

# виртуальной файловой системой.

find_package (vfs REQUIRED COMPONENTS FS_LIB CLIENT_LIB SERVER_LIB)

include_directories (${vfs_INCLUDE})

add_subdirectory (client)

add_subdirectory (ext2)

add_subdirectory (einit)

Сборка с помощью CMake

Для сборки и запуска примера необходимо выполнить следующий скрипт:

/opt/KasperskyOS-Community-Edition-<version>/examples/embed_ext2/cross-build.sh

В начало