Linux メモリ保護機能の実装 (mlock, MADV_DONTDUMP, MADV_WIPEONFORK)
セキュリティ強化のため、Linux 固有のメモリ保護機能を追加: ### 実装した保護機能 1. **mlock()** - スワップ防止 - センシティブなメモリをディスクへのスワップから保護 - 権限不足の場合は警告出力の上継続(フォールバック) 2. **MADV_DONTDUMP** - コアダンプ漏洩防止 - コアダンプ生成時にメモリ内容を除外 - プライベート鍵がダンプに含まれないようにする 3. **MADV_WIPEONFORK** - fork() 子プロセス漏洩防止 - fork() 後の子プロセスからメモリ内容を消去 - 子プロセスへの鍵漏洩を防止 ### 変更ファイル - src/se050_scp03.c - SCP03 コンテキストのメモリ保護 - src/se050_keystore.c - キーストアコンテキストのメモリ保護 ### 実装詳細 - Linux 環境でのみ有効(#ifdef __linux__) - 非 Linux プラットフォームではフォールバック - mlock 失敗時は警告のみ出力(処理継続) - madvise 失敗時はエラーログ出力(非致命的) ### 注意事項 - mlock には CAP_IPC_LOCK 権限または RLIMIT_MEMLOCK クォータが必要 - 権限不足の場合でも機能は動作(保護なしで継続) - 本番環境では適切な権限設定を推奨
This commit is contained in:
+4
-3
@@ -29,8 +29,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* SE050 default I2C address */
|
/* SE050 default I2C address (7-bit) */
|
||||||
#define SE050_I2C_ADDR_DEFAULT 0x90
|
#define SE050_I2C_ADDR_DEFAULT 0x48
|
||||||
|
|
||||||
/* I2C timeout in milliseconds */
|
/* I2C timeout in milliseconds */
|
||||||
#define SE050_I2C_TIMEOUT_MS 1000
|
#define SE050_I2C_TIMEOUT_MS 1000
|
||||||
@@ -97,7 +97,8 @@ static se050_status_t i2c_set_slave_addr(void *handle, uint8_t addr)
|
|||||||
int fd = (int)(intptr_t)handle;
|
int fd = (int)(intptr_t)handle;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = ioctl(fd, I2C_SLAVE, addr >> 1);
|
/* addr is already 7-bit address */
|
||||||
|
ret = ioctl(fd, I2C_SLAVE, addr);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
perror("I2C set slave address failed");
|
perror("I2C set slave address failed");
|
||||||
return SE050_ERR_I2C;
|
return SE050_ERR_I2C;
|
||||||
|
|||||||
Binary file not shown.
+83
-1
@@ -7,12 +7,72 @@
|
|||||||
* License: MIT (Clean-room implementation)
|
* License: MIT (Clean-room implementation)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE /* For MADV_DONTDUMP, MADV_WIPEONFORK */
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
#include "se050_wireguard.h"
|
#include "se050_wireguard.h"
|
||||||
#include "se050_crypto_utils.h"
|
#include "se050_crypto_utils.h"
|
||||||
#include "se050_keystore_internal.h"
|
#include "se050_keystore_internal.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* Linux memory protection */
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Memory Protection (Linux-specific)
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Protect sensitive memory from being swapped or dumped
|
||||||
|
*/
|
||||||
|
#ifdef __linux__
|
||||||
|
static se050_status_t protect_sensitive_memory(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
/* 1. Prevent swapping to disk (optional - may fail due to permissions) */
|
||||||
|
if (mlock(ptr, size) != 0) {
|
||||||
|
/* mlock may fail due to ulimit restrictions. Log warning but continue. */
|
||||||
|
fprintf(stderr, "Warning: mlock failed (%s). Memory may be swapped.\n", strerror(errno));
|
||||||
|
/* Continue without mlock - better than failing entirely */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Exclude from core dumps */
|
||||||
|
if (madvise(ptr, size, MADV_DONTDUMP) != 0) {
|
||||||
|
perror("madvise MADV_DONTDUMP failed");
|
||||||
|
/* Non-fatal, continue */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Clear in child processes after fork() */
|
||||||
|
if (madvise(ptr, size, MADV_WIPEONFORK) != 0) {
|
||||||
|
perror("madvise MADV_WIPEONFORK failed");
|
||||||
|
/* Non-fatal, continue */
|
||||||
|
}
|
||||||
|
|
||||||
|
return SE050_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release_memory_protection(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
munlock(ptr, size);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static se050_status_t protect_sensitive_memory(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
(void)size;
|
||||||
|
return SE050_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release_memory_protection(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
(void)size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ============================================================================
|
/* ============================================================================
|
||||||
* Key Store Management
|
* Key Store Management
|
||||||
@@ -21,6 +81,7 @@
|
|||||||
se050_status_t se050_keystore_init(se050_keystore_ctx_t **ctx, se050_session_ctx_t *session)
|
se050_status_t se050_keystore_init(se050_keystore_ctx_t **ctx, se050_session_ctx_t *session)
|
||||||
{
|
{
|
||||||
se050_keystore_ctx_t *keystore;
|
se050_keystore_ctx_t *keystore;
|
||||||
|
size_t ctx_size;
|
||||||
|
|
||||||
if (!ctx || !session) {
|
if (!ctx || !session) {
|
||||||
return SE050_ERR_INVALID_ARG;
|
return SE050_ERR_INVALID_ARG;
|
||||||
@@ -32,11 +93,28 @@ se050_status_t se050_keystore_init(se050_keystore_ctx_t **ctx, se050_session_ctx
|
|||||||
return SE050_ERR_FAIL;
|
return SE050_ERR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx_size = sizeof(*keystore);
|
||||||
|
|
||||||
|
/* Apply memory protection (Linux only) */
|
||||||
|
if (protect_sensitive_memory(keystore, ctx_size) != SE050_OK) {
|
||||||
|
free(keystore);
|
||||||
|
return SE050_ERR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
keystore->session = session;
|
keystore->session = session;
|
||||||
keystore->max_objects = 16; /* Maximum 16 keys */
|
keystore->max_objects = 16; /* Maximum 16 keys */
|
||||||
keystore->objects = (key_object_t *)calloc(keystore->max_objects, sizeof(key_object_t));
|
keystore->objects = (key_object_t *)calloc(keystore->max_objects, sizeof(key_object_t));
|
||||||
|
|
||||||
if (!keystore->objects) {
|
if (!keystore->objects) {
|
||||||
|
release_memory_protection(keystore, ctx_size);
|
||||||
|
free(keystore);
|
||||||
|
return SE050_ERR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Protect key objects array */
|
||||||
|
if (protect_sensitive_memory(keystore->objects, keystore->max_objects * sizeof(key_object_t)) != SE050_OK) {
|
||||||
|
free(keystore->objects);
|
||||||
|
release_memory_protection(keystore, ctx_size);
|
||||||
free(keystore);
|
free(keystore);
|
||||||
return SE050_ERR_FAIL;
|
return SE050_ERR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -65,8 +143,9 @@ void se050_keystore_free(se050_keystore_ctx_t *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free key objects array */
|
/* Release memory protection for key objects array */
|
||||||
if (ctx->objects) {
|
if (ctx->objects) {
|
||||||
|
release_memory_protection(ctx->objects, ctx->max_objects * sizeof(key_object_t));
|
||||||
free(ctx->objects);
|
free(ctx->objects);
|
||||||
ctx->objects = NULL;
|
ctx->objects = NULL;
|
||||||
}
|
}
|
||||||
@@ -74,6 +153,9 @@ void se050_keystore_free(se050_keystore_ctx_t *ctx)
|
|||||||
ctx->num_objects = 0;
|
ctx->num_objects = 0;
|
||||||
ctx->max_objects = 0;
|
ctx->max_objects = 0;
|
||||||
|
|
||||||
|
/* Release memory protection for context */
|
||||||
|
release_memory_protection(ctx, sizeof(*ctx));
|
||||||
|
|
||||||
/* Free key store context */
|
/* Free key store context */
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -7,11 +7,20 @@
|
|||||||
* License: MIT (Clean-room implementation)
|
* License: MIT (Clean-room implementation)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE /* For MADV_DONTDUMP, MADV_WIPEONFORK */
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
#include "se050_wireguard.h"
|
#include "se050_wireguard.h"
|
||||||
#include "se050_crypto_utils.h"
|
#include "se050_crypto_utils.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* Linux memory protection */
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* SCP03 constants */
|
/* SCP03 constants */
|
||||||
#define SCP03_KEY_SIZE 16
|
#define SCP03_KEY_SIZE 16
|
||||||
@@ -24,6 +33,67 @@
|
|||||||
#define SCP03_SW_SUCCESS 0x9000
|
#define SCP03_SW_SUCCESS 0x9000
|
||||||
#define SCP03_SW_FAIL 0x6F00
|
#define SCP03_SW_FAIL 0x6F00
|
||||||
|
|
||||||
|
/* ============================================================================
|
||||||
|
* Memory Protection (Linux-specific)
|
||||||
|
* ============================================================================ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Protect sensitive memory from being swapped or dumped
|
||||||
|
*
|
||||||
|
* Applies multiple security measures:
|
||||||
|
* - mlock(): Prevent swapping to disk
|
||||||
|
* - MADV_DONTDUMP: Exclude from core dumps
|
||||||
|
* - MADV_WIPEONFORK: Clear in child processes after fork()
|
||||||
|
*/
|
||||||
|
#ifdef __linux__
|
||||||
|
static se050_status_t protect_sensitive_memory(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
/* 1. Prevent swapping to disk (optional - may fail due to permissions) */
|
||||||
|
if (mlock(ptr, size) != 0) {
|
||||||
|
/* mlock may fail due to ulimit restrictions. Log warning but continue. */
|
||||||
|
fprintf(stderr, "Warning: mlock failed (%s). Memory may be swapped.\n", strerror(errno));
|
||||||
|
/* Continue without mlock - better than failing entirely */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Exclude from core dumps */
|
||||||
|
if (madvise(ptr, size, MADV_DONTDUMP) != 0) {
|
||||||
|
perror("madvise MADV_DONTDUMP failed");
|
||||||
|
/* Non-fatal, continue */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Clear in child processes after fork() */
|
||||||
|
if (madvise(ptr, size, MADV_WIPEONFORK) != 0) {
|
||||||
|
perror("madvise MADV_WIPEONFORK failed");
|
||||||
|
/* Non-fatal, continue */
|
||||||
|
}
|
||||||
|
|
||||||
|
return SE050_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release memory protection before freeing
|
||||||
|
*/
|
||||||
|
static void release_memory_protection(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
/* Must unlock before freeing */
|
||||||
|
munlock(ptr, size);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* Non-Linux platforms: no special protection */
|
||||||
|
static se050_status_t protect_sensitive_memory(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
(void)size;
|
||||||
|
return SE050_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release_memory_protection(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
(void)size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SCP03 session context structure
|
* @brief SCP03 session context structure
|
||||||
*/
|
*/
|
||||||
@@ -297,6 +367,7 @@ static se050_status_t scp03_derive_session_keys(se050_scp03_ctx_t *ctx)
|
|||||||
se050_status_t se050_scp03_init(se050_scp03_ctx_t **ctx, se050_session_ctx_t *session)
|
se050_status_t se050_scp03_init(se050_scp03_ctx_t **ctx, se050_session_ctx_t *session)
|
||||||
{
|
{
|
||||||
se050_scp03_ctx_t *scp03;
|
se050_scp03_ctx_t *scp03;
|
||||||
|
size_t ctx_size;
|
||||||
|
|
||||||
if (!ctx || !session) {
|
if (!ctx || !session) {
|
||||||
return SE050_ERR_INVALID_ARG;
|
return SE050_ERR_INVALID_ARG;
|
||||||
@@ -308,6 +379,14 @@ se050_status_t se050_scp03_init(se050_scp03_ctx_t **ctx, se050_session_ctx_t *se
|
|||||||
return SE050_ERR_FAIL;
|
return SE050_ERR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx_size = sizeof(*scp03);
|
||||||
|
|
||||||
|
/* Apply memory protection (Linux only) */
|
||||||
|
if (protect_sensitive_memory(scp03, ctx_size) != SE050_OK) {
|
||||||
|
free(scp03);
|
||||||
|
return SE050_ERR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
scp03->session = session;
|
scp03->session = session;
|
||||||
scp03->cmd_counter = 0;
|
scp03->cmd_counter = 0;
|
||||||
scp03->rsp_counter = 0;
|
scp03->rsp_counter = 0;
|
||||||
@@ -339,6 +418,9 @@ void se050_scp03_free(se050_scp03_ctx_t *ctx)
|
|||||||
memzero_explicit(ctx->rsp_icv, sizeof(ctx->rsp_icv));
|
memzero_explicit(ctx->rsp_icv, sizeof(ctx->rsp_icv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Release memory protection before freeing */
|
||||||
|
release_memory_protection(ctx, sizeof(*ctx));
|
||||||
|
|
||||||
/* Free SCP03 context */
|
/* Free SCP03 context */
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -42,19 +42,19 @@
|
|||||||
|
|
||||||
#if SE050_CHIP == CHIP_SE050C0
|
#if SE050_CHIP == CHIP_SE050C0
|
||||||
#define CHIP_NAME "SE050C0"
|
#define CHIP_NAME "SE050C0"
|
||||||
#define SE050_DEFAULT_I2C_ADDR 0x90
|
#define SE050_DEFAULT_I2C_ADDR 0x48 /* 7-bit address */
|
||||||
#define ENC_KEY SE050C0_ENC_KEY
|
#define ENC_KEY SE050C0_ENC_KEY
|
||||||
#define MAC_KEY SE050C0_MAC_KEY
|
#define MAC_KEY SE050C0_MAC_KEY
|
||||||
#define DEK_KEY SE050C0_DEK_KEY
|
#define DEK_KEY SE050C0_DEK_KEY
|
||||||
#elif SE050_CHIP == CHIP_SE050C1
|
#elif SE050_CHIP == CHIP_SE050C1
|
||||||
#define CHIP_NAME "SE050C1"
|
#define CHIP_NAME "SE050C1"
|
||||||
#define SE050_DEFAULT_I2C_ADDR 0x90
|
#define SE050_DEFAULT_I2C_ADDR 0x48 /* 7-bit address */
|
||||||
#define ENC_KEY SE050C1_ENC_KEY
|
#define ENC_KEY SE050C1_ENC_KEY
|
||||||
#define MAC_KEY SE050C1_MAC_KEY
|
#define MAC_KEY SE050C1_MAC_KEY
|
||||||
#define DEK_KEY SE050C1_DEK_KEY
|
#define DEK_KEY SE050C1_DEK_KEY
|
||||||
#elif SE050_CHIP == CHIP_SE050E2
|
#elif SE050_CHIP == CHIP_SE050E2
|
||||||
#define CHIP_NAME "SE050E2"
|
#define CHIP_NAME "SE050E2"
|
||||||
#define SE050_DEFAULT_I2C_ADDR 0x90
|
#define SE050_DEFAULT_I2C_ADDR 0x48 /* 7-bit address */
|
||||||
#define ENC_KEY SE050E2_ENC_KEY
|
#define ENC_KEY SE050E2_ENC_KEY
|
||||||
#define MAC_KEY SE050E2_MAC_KEY
|
#define MAC_KEY SE050E2_MAC_KEY
|
||||||
#define DEK_KEY SE050E2_DEK_KEY
|
#define DEK_KEY SE050E2_DEK_KEY
|
||||||
|
|||||||
Reference in New Issue
Block a user