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:
km
2026-03-26 11:04:14 +09:00
parent eb468c1ba1
commit aff6c301e6
7 changed files with 172 additions and 7 deletions
+4 -3
View File
@@ -29,8 +29,8 @@
#endif
#endif
/* SE050 default I2C address */
#define SE050_I2C_ADDR_DEFAULT 0x90
/* SE050 default I2C address (7-bit) */
#define SE050_I2C_ADDR_DEFAULT 0x48
/* I2C timeout in milliseconds */
#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 ret;
ret = ioctl(fd, I2C_SLAVE, addr >> 1);
/* addr is already 7-bit address */
ret = ioctl(fd, I2C_SLAVE, addr);
if (ret < 0) {
perror("I2C set slave address failed");
return SE050_ERR_I2C;
Binary file not shown.
+83 -1
View File
@@ -7,12 +7,72 @@
* License: MIT (Clean-room implementation)
*/
#define _GNU_SOURCE /* For MADV_DONTDUMP, MADV_WIPEONFORK */
#define _POSIX_C_SOURCE 200809L
#include "se050_wireguard.h"
#include "se050_crypto_utils.h"
#include "se050_keystore_internal.h"
#include <stdio.h>
#include <stdlib.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
@@ -21,6 +81,7 @@
se050_status_t se050_keystore_init(se050_keystore_ctx_t **ctx, se050_session_ctx_t *session)
{
se050_keystore_ctx_t *keystore;
size_t ctx_size;
if (!ctx || !session) {
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;
}
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->max_objects = 16; /* Maximum 16 keys */
keystore->objects = (key_object_t *)calloc(keystore->max_objects, sizeof(key_object_t));
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);
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) {
release_memory_protection(ctx->objects, ctx->max_objects * sizeof(key_object_t));
free(ctx->objects);
ctx->objects = NULL;
}
@@ -74,6 +153,9 @@ void se050_keystore_free(se050_keystore_ctx_t *ctx)
ctx->num_objects = 0;
ctx->max_objects = 0;
/* Release memory protection for context */
release_memory_protection(ctx, sizeof(*ctx));
/* Free key store context */
free(ctx);
}
Binary file not shown.
+82
View File
@@ -7,11 +7,20 @@
* License: MIT (Clean-room implementation)
*/
#define _GNU_SOURCE /* For MADV_DONTDUMP, MADV_WIPEONFORK */
#define _POSIX_C_SOURCE 200809L
#include "se050_wireguard.h"
#include "se050_crypto_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* Linux memory protection */
#ifdef __linux__
#include <sys/mman.h>
#endif
/* SCP03 constants */
#define SCP03_KEY_SIZE 16
@@ -24,6 +33,67 @@
#define SCP03_SW_SUCCESS 0x9000
#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
*/
@@ -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_scp03_ctx_t *scp03;
size_t ctx_size;
if (!ctx || !session) {
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;
}
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->cmd_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));
}
/* Release memory protection before freeing */
release_memory_protection(ctx, sizeof(*ctx));
/* Free SCP03 context */
free(ctx);
}
BIN
View File
Binary file not shown.