From aff6c301e696c869bfc438866a473124d7f08404 Mon Sep 17 00:00:00 2001 From: km Date: Thu, 26 Mar 2026 11:04:14 +0900 Subject: [PATCH] =?UTF-8?q?Linux=20=E3=83=A1=E3=83=A2=E3=83=AA=E4=BF=9D?= =?UTF-8?q?=E8=AD=B7=E6=A9=9F=E8=83=BD=E3=81=AE=E5=AE=9F=E8=A3=85=20(mlock?= =?UTF-8?q?,=20MADV=5FDONTDUMP,=20MADV=5FWIPEONFORK)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit セキュリティ強化のため、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 クォータが必要 - 権限不足の場合でも機能は動作(保護なしで継続) - 本番環境では適切な権限設定を推奨 --- src/se050_i2c_hal.c | 7 ++-- src/se050_i2c_hal.o | Bin 4152 -> 4144 bytes src/se050_keystore.c | 84 ++++++++++++++++++++++++++++++++++++++- src/se050_keystore.o | Bin 3864 -> 5408 bytes src/se050_scp03.c | 82 ++++++++++++++++++++++++++++++++++++++ src/se050_scp03.o | Bin 7048 -> 8272 bytes tests/test_scp03_se050.c | 6 +-- 7 files changed, 172 insertions(+), 7 deletions(-) diff --git a/src/se050_i2c_hal.c b/src/se050_i2c_hal.c index bd87a83..ba20472 100644 --- a/src/se050_i2c_hal.c +++ b/src/se050_i2c_hal.c @@ -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; diff --git a/src/se050_i2c_hal.o b/src/se050_i2c_hal.o index 324c154f0de283c37e1932d22a7a4437217f4ded..028d43998a9cabe56dd7f9838d0833271fe2c6af 100644 GIT binary patch delta 450 zcmYk2F-QVo6vywKCntAm9!BSFN<`gcO&M4RLFf{6pi49q1VXd~QA0nyirZe1%Z}f>RUx`vsq&=$RSUR}!-(%As ztG@ViM61x`5*1L9Gi2gVPErwOAVX>F1d`OM-Uar_m?yyvi7~{o$Hwtk#*CsHd5={+ z_6ZxzMn$((;Jp!#J%q#Tug8vhtc<#%Q`F@(+N^$X>nf*_;E%E3#~91uJ~`OxsZkj0 zQ)7k)AHmZ^Th)!?V4^U%HMD6Yf;zP@7yM$MVuWVt2zJP#8#peTF14^l4cLqwIAKfd bO85vbPz>6LMeDE`SKu%{qRE(o7Mc79@TH48 delta 462 zcmYjNJxc>o5WGDvUM{&0qu`m!h#*lRAz0XXMhWIhEkp&e5)`x$M4NPe1{-A>Q=O?q z6jTIBVPPkR6pBAU1q(|p#1DkHPcPuW%zMksF8kg|tQ6ahQ|YvGfYi*>&9ilWgL%qR z8Sm5{>8e(%YnO{n*{#e+Hh=Z}f^K<^RnF>=E z1!Dqfc8`5mI2QAp_Y-Kr0=uiCi6PuZX3hOXF=UgDTh #include #include +#include + +/* Linux memory protection */ +#ifdef __linux__ +#include +#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); } diff --git a/src/se050_keystore.o b/src/se050_keystore.o index a8d4576e119aee33e4fefc3150a422fa22438720..85b73b36b7bed084520e1bc43634ac4d7eddf8cd 100644 GIT binary patch literal 5408 zcmd5=TWlQF89wVc*iDJ;a!EHLibkbHNd${SD8&&%3(3Y)8Yfo77O5iIjO}sQ#Cy@~ zY!cJD4K-9l_hFg1QnLeC*>&<`kZ@;Eh4MeKy*;PvoIiFbw z@0KEU0mVe9roK_G<~A$fZ5Vx(OT|zhky>6G0OHn2lsHuNyK_p?=rXJ~{aaS4|37wn zeSplBO7!f^vIu+J*_no@ZhEx~R<91@)aD(mUgz=Y5RtdpnN{)-ym~vH?qa4%wpLmL6Olxc+!l(wXr7r@K}DRw=aNDKQsOQq=Y}ago;m^k)An>16*a3$u-GBzG4P zcXnZ`JSXOB{$rU0f;tHBTTj>!y%)uwHZ5DGG`ZqQFYk@_{H z3!l+0rhB8v?JVG64IcS3YLw^%uO#fUL`l}FS6EdtD+iQkGAp>p>$6f9Lzyep?VrZ7 zl0@iDJM?DoygZeo_FY$}BF}AbU%Ls8};lJYE)+< zZQ?BT-K=A;%;{rd1o1PUW;$F8dRyO`_mUoXS^xXXK&%U(fA7 zeCW~r*^yB#s7I6*l+qc)*ksYfR!>Y4;PijwU@UHu+a(mCW z@3}WMcyDU=PEDZBZv5CB`JNj-lodGK1!5cUtV@2`s2hge#b{f%XhsP(Z59;V;3KW?zQy) zj5tOW{zUW*QwefV|L;k}_`*8+)`D^9q?ZR zzX|#DbiA_mfbrGR&hDQ(;D6M5F0q?p$Qs4`E`HSC)E7|JCa|j-pW@}jI4hq*e1f^1 zU4Ft)&xe{{)+l%#jlU;9Y=w}u3H(8gfA$%pw>J3HU1{rx*G*hL9>g1GH0+JMI_#KyzMC3v=b_7!pH0ZK*;2lo3X%r&YRT zA7b?0>ll=V_|5kl(;(ETQaiix^t>;dQ-`4XD3upZsKcBU5_CAAOw(y%R zypIMk=#R~xv2dIJ2OaPiI^ZwrdrbYdp1*a#-zFmlr_bYO{NJnZEAd+`JZs@wEPT7Z z$8r7(9dHM-91KH;BKK+eY~kj8aV&3hdwxaoT$Rhce?-WcXEQ1cUJg%0MWLjO!CQWIY2iPTu7B2qy~ zZN^K5f?ou!hz6L#x71yg&_iER`{TuG3M~&kE1ZT5HTh5ECIheFE64xGrvrJ0q>ne! zme#9XJrN`qI{XN{4J+14IzrUqS@}N`A->PVVz9SRmc5E2sU~p;X5zZ6H7dl3m|a7N z+rJY8>iloz`F%p2+D)v~C~Nzt4WMV^zkylTlsEm$;D6EbDFf))_;2Qift$6>dTZQJ zOy2Mw!GfmZ{wKA(V;J=uSIh4w+K>O*1qR)|y~crB zy>4s97qfOnCdO~A!Hh4(t5M(Tl=pu2n6`C67 zUmE9g5S0`B1#FQM(q{&ToQ+WqH2W^}c{rmO{0Pkh zyKqmM?bKs5`#$u?a1c*RxIjDSI5v!)_?+NlP*gVd5Q+O7$xorYFO-Vk0S^R!C-`GO zWJ3M09D2HqT@Ys^ZNY)vwe6XQ2R!_@m&0hgaS7Yji25boLfO1LA!=^sH4hJY@|+Sc zBE90_6CO^#Ypgb7m%E3QXw3nCyd0wHi9xsB^R}Kbs(^;u?!_kVw!7TKKYu^bx3Nl@HN>%K@q6Hpw=zTw!kBKElg`^clk++L0VU7 z+ox~heVD+I3a(7$JK?Tw$OUmn61bk=L-18I #include #include +#include + +/* Linux memory protection */ +#ifdef __linux__ +#include +#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); } diff --git a/src/se050_scp03.o b/src/se050_scp03.o index a86bf1497819f09d74d38022a7e663eca5470d02..26b681d607c3a7fa850963e2103c0c8cae074a3b 100644 GIT binary patch delta 2825 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 ZO>MgO1+^b#C49kMhr{N-Ht3FOe*s2s1quKF diff --git a/tests/test_scp03_se050.c b/tests/test_scp03_se050.c index b910b96..5b114d9 100644 --- a/tests/test_scp03_se050.c +++ b/tests/test_scp03_se050.c @@ -42,19 +42,19 @@ #if SE050_CHIP == CHIP_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 MAC_KEY SE050C0_MAC_KEY #define DEK_KEY SE050C0_DEK_KEY #elif SE050_CHIP == CHIP_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 MAC_KEY SE050C1_MAC_KEY #define DEK_KEY SE050C1_DEK_KEY #elif SE050_CHIP == CHIP_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 MAC_KEY SE050E2_MAC_KEY #define DEK_KEY SE050E2_DEK_KEY