Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8a617af
observability(core): add append-only audit log infrastructure
minto-dane Apr 9, 2026
0b551bb
security(core): enable runtime CPU hardening controls
minto-dane Apr 9, 2026
f05c489
security(core): move user memory access to page-table-walk primitives
minto-dane Apr 9, 2026
e0c57c1
security(core): harden fs, exec, and pipe user-buffer handling
minto-dane Apr 9, 2026
1d4f130
security(core): update process and signal syscalls for hardened usercopy
minto-dane Apr 9, 2026
2b12efe
reliability(core): add audit-backed containment for low-level runtime…
minto-dane Apr 9, 2026
b3b34f7
Merge branch 'tas0dev:dev' into dev
minto-dane Apr 10, 2026
d7ecd6d
build: fail fast on image assembly and library copy errors
minto-dane Apr 10, 2026
762609b
build: parse service indexes safely and align ELF scripts with ramfs
minto-dane Apr 10, 2026
383b019
security: gate unfinished CFI and CET feature toggles
minto-dane Apr 10, 2026
b8b167a
fs: widen path handling and cache the fs service thread
minto-dane Apr 10, 2026
7c57ffd
signal: install fixed sigreturn stubs and harden exec mappings
minto-dane Apr 10, 2026
1bc166c
security: keep trap and int80 handling on kernel page tables
minto-dane Apr 10, 2026
abd2eba
mm: implement mprotect and surface unsupported POSIX setters
minto-dane Apr 10, 2026
98250ab
kmod: guard relocation writes against address overflow
minto-dane Apr 10, 2026
fef2463
driver: restrict autoloaded binaries to approved paths
minto-dane Apr 10, 2026
d74c15e
shell: remove static mut IPC buffering and parse quoted UTF-8 safely
minto-dane Apr 10, 2026
d0dbeb5
docs: update the hardening checklist and normalize repo metadata
minto-dane Apr 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .codex
Empty file.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ bench = false
[features]
default = ["uefi-dep"]
uefi-dep = ["dep:uefi"]
kcfi = []
cet-ibt = []
cet-shadow-stack = []

[dependencies]
uefi = { version = "0.30", features = ["alloc", "logger", "global_allocator"], optional = true }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ mochiOSはハイブリッドアーキテクチャを採用した、新しいOS
<div align="center">
<img src="src/resources/Resources/mochimochi-kun.png" width="50" alt="mochimochi-kun">
<small>< みんなの貢献待ってるよ!</small>
</div>
</div>
27 changes: 20 additions & 7 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ fn ensure_busybox_binary(fs_dir: &Path) -> Result<(), String> {
"--silent",
"--show-error",
"--max-time",
"30",
"120",
"--output",
])
.arg(&temp)
Expand Down Expand Up @@ -289,10 +289,7 @@ fn prune_stale_module_artifacts(
modules: &[builders::modules::ModuleEntry],
ramfs_dir: &Path,
) -> Result<(), String> {
let expected: HashSet<String> = modules
.iter()
.map(|m| format!("{}.cext", m.name))
.collect();
let expected: HashSet<String> = modules.iter().map(|m| format!("{}.cext", m.name)).collect();
let modules_dir = ramfs_dir.join("Modules");
if let Ok(entries) = fs::read_dir(&modules_dir) {
for entry in entries.flatten() {
Expand Down Expand Up @@ -495,7 +492,8 @@ fn main() {
.expect("Failed to prune stale service artifacts");

let modules = default_modules();
prune_stale_module_artifacts(&modules, &ramfs_dir).expect("Failed to prune stale module artifacts");
prune_stale_module_artifacts(&modules, &ramfs_dir)
.expect("Failed to prune stale module artifacts");

// サービスをビルド
let services_base_dir = manifest_dir.join("src/services");
Expand Down Expand Up @@ -593,7 +591,22 @@ fn main() {
// make_image.sh を実行(UEFIイメージ作成)
let mkimage_script = manifest_dir.join("scripts/make_image.sh");
if mkimage_script.exists() {
let _ = std::process::Command::new(mkimage_script).status();
match std::process::Command::new(&mkimage_script).status() {
Ok(status) if status.success() => {}
Ok(status) => {
panic!(
"make_image.sh failed with exit code {}",
status.code().unwrap_or(-1)
);
}
Err(e) => {
panic!(
"failed to execute make_image.sh ({}): {}",
mkimage_script.display(),
e
);
}
}
}

println!("Build completed successfully!");
Expand Down
48 changes: 46 additions & 2 deletions builders/fs_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,57 @@ fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<(), String> {

/// newlibライブラリをディレクトリにコピー
pub fn copy_newlib_libs(libc_dir: &Path, dest_dir: &Path) -> Result<(), String> {
fn copy_atomic(src: &Path, dest: &Path) -> Result<(), String> {
let tmp = dest.with_extension(format!("tmp-copy-{}", std::process::id()));
if tmp.exists() {
let _ = fs::remove_file(&tmp);
}

fs::copy(src, &tmp).map_err(|e| {
format!(
"Failed to copy {} to temporary file {}: {}",
src.display(),
tmp.display(),
e
)
})?;

let src_len = fs::metadata(src)
.map_err(|e| format!("Failed to stat {}: {}", src.display(), e))?
.len();
let tmp_len = fs::metadata(&tmp)
.map_err(|e| format!("Failed to stat {}: {}", tmp.display(), e))?
.len();
if src_len != tmp_len {
let _ = fs::remove_file(&tmp);
return Err(format!(
"Short copy detected while copying {} to {} ({} != {})",
src.display(),
dest.display(),
src_len,
tmp_len
));
}

fs::rename(&tmp, dest).map_err(|e| {
let _ = fs::remove_file(&tmp);
format!(
"Failed to atomically install {} from {}: {}",
dest.display(),
src.display(),
e
)
})?;
Ok(())
}

fs::create_dir_all(dest_dir)
.map_err(|e| format!("Failed to create {}: {}", dest_dir.display(), e))?;

// crt0.oをコピー
let crt0_src = libc_dir.join("crt0.o");
let crt0_dest = dest_dir.join("crt0.o");
fs::copy(&crt0_src, &crt0_dest)
copy_atomic(&crt0_src, &crt0_dest)
.map_err(|e| format!("Failed to copy crt0.o to {}: {}", dest_dir.display(), e))?;
println!("Copied crt0.o to {}", dest_dir.display());

Expand All @@ -349,7 +393,7 @@ pub fn copy_newlib_libs(libc_dir: &Path, dest_dir: &Path) -> Result<(), String>
for lib in &libs {
let src = libc_dir.join(lib);
let dest = dest_dir.join(lib);
fs::copy(&src, &dest).map_err(|e| {
copy_atomic(&src, &dest).map_err(|e| {
format!(
"Failed to copy {} to {}: {}. Make sure newlib is built correctly.",
lib,
Expand Down
4 changes: 2 additions & 2 deletions builders/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
pub mod apps;
pub mod drivers;
pub mod fs_image;
pub mod newlib;
pub mod modules;
pub mod newlib;
pub mod services;
pub mod utils;

pub use apps::{build_apps, build_utils};
pub use drivers::build_drivers;
pub use fs_image::{copy_newlib_libs, create_ext2_image, create_initfs_image, setup_fs_layout};
pub use newlib::{build_newlib, build_user_libs};
pub use modules::{build_module, default_modules};
pub use newlib::{build_newlib, build_user_libs};
pub use services::{build_service, parse_service_index};
42 changes: 38 additions & 4 deletions builders/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@ pub fn parse_service_index(index_path: &Path) -> Result<Vec<ServiceEntry>, Strin
let content =
fs::read_to_string(index_path).map_err(|e| format!("Failed to read index.toml: {}", e))?;

fn strip_inline_comment(line: &str) -> &str {
let mut in_single = false;
let mut in_double = false;
let mut escaped = false;
for (i, ch) in line.char_indices() {
if escaped {
escaped = false;
continue;
}
if ch == '\\' {
escaped = true;
continue;
}
match ch {
'\'' if !in_double => in_single = !in_single,
'"' if !in_single => in_double = !in_double,
'#' if !in_single && !in_double => return &line[..i],
_ => {}
}
}
line
}

// 簡易的なTOML解析(tomlクレートを使わずに)
let mut services = Vec::new();

Expand All @@ -31,8 +54,11 @@ pub fn parse_service_index(index_path: &Path) -> Result<Vec<ServiceEntry>, Strin
let mut current_autostart = false;
let mut current_order = 999;

for line in content.lines() {
let line = line.trim();
for raw_line in content.lines() {
let line = strip_inline_comment(raw_line).trim();
if line.is_empty() {
continue;
}

// [core.service] または [core.service.NAME] を解析
if line.starts_with("[core.service") && line.ends_with(']') {
Expand Down Expand Up @@ -77,9 +103,17 @@ pub fn parse_service_index(index_path: &Path) -> Result<Vec<ServiceEntry>, Strin
} else if let Some(rest) = line.strip_prefix("description = ") {
current_desc = rest.trim_matches('"').trim_matches('\'').to_string();
} else if let Some(rest) = line.strip_prefix("autostart = ") {
current_autostart = rest.trim().parse().unwrap_or(false);
current_autostart = rest.trim().parse().map_err(|_| {
format!(
"Invalid autostart value in {}: {}",
index_path.display(),
line
)
})?;
} else if let Some(rest) = line.strip_prefix("order = ") {
current_order = rest.trim().parse().unwrap_or(999);
current_order = rest.trim().parse().map_err(|_| {
format!("Invalid order value in {}: {}", index_path.display(), line)
})?;
}
}

Expand Down
7 changes: 6 additions & 1 deletion scripts/build-user-elf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -euo pipefail

ROOT_DIR=$(cd "$(dirname "$0")/.." && pwd)
INITFS_DIR="$ROOT_DIR/src/initfs"
INITFS_DIR="$ROOT_DIR/ramfs"
ASM="$INITFS_DIR/hello.asm"
OUT="$INITFS_DIR/hello"

Expand All @@ -18,6 +18,11 @@ if ! command -v "$LD" >/dev/null 2>&1; then
echo "Error: ld not found. Install binutils or pass linker as second arg."
exit 1
fi
if [ ! -f "$ASM" ]; then
echo "Error: source not found: $ASM"
echo "Hint: this legacy script expects $INITFS_DIR/hello.asm"
exit 1
fi

echo "Assembling with: $NASM; linking with: $LD"

Expand Down
14 changes: 7 additions & 7 deletions scripts/test_elf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ echo ""

# 1. ユーザーアプリをビルド
echo "[1/4] Building user application..."
cd src/user/test_app
cd src/apps/tests
./build.sh
cd ../../..

# 2. initfsの内容確認
echo ""
echo "[2/4] Checking initfs contents..."
ls -lh src/initfs/
echo "[2/4] Checking ramfs contents..."
ls -lh ramfs/

# 3. test.elfのELFヘッダ確認
# 3. tests.elfのELFヘッダ確認
echo ""
echo "[3/4] Verifying ELF header..."
file src/initfs/test.elf
readelf -h src/initfs/test.elf | grep "Entry point"
file ramfs/tests.elf
readelf -h ramfs/tests.elf | grep "Entry point"

# 4. カーネルをビルド
echo ""
Expand All @@ -29,4 +29,4 @@ cargo build

echo ""
echo "===== Build Complete ====="
echo "Run 'cargo run' to execute the kernel with test.elf"
echo "Run 'cargo run' to execute the kernel with tests.elf"
2 changes: 1 addition & 1 deletion src/apps/tests/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ cargo build --release \
-Z build-std=core,alloc \
--package "$APP_NAME"

INITFS_DIR="$PROJECT_ROOT/initfs"
INITFS_DIR="$PROJECT_ROOT/ramfs"
mkdir -p "$INITFS_DIR"

SOURCE_BIN="target/x86_64-mochios/release/$APP_NAME"
Expand Down
1 change: 0 additions & 1 deletion src/boot/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ unsafe fn load_initfs(
(0, 0)
}


/// 指定ハンドルから任意ファイルをページ単位でロードし (物理アドレス, サイズ) を返す
unsafe fn try_load_raw(
bt: &BootServices,
Expand Down
5 changes: 5 additions & 0 deletions src/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ bench = false
mochios = { package = "mochiOS", path = "../..", default-features = false }
linked_list_allocator = "0.10.5"

[features]
kcfi = ["mochios/kcfi"]
cet-ibt = ["mochios/cet-ibt"]
cet-shadow-stack = ["mochios/cet-shadow-stack"]

[profile.dev]
panic = "abort"

Expand Down
Loading