Skip to content

Commit 2d957d5

Browse files
committed
sandlock-core: confine COW upper-layer and commit writes against symlink escape
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent bdeecaf commit 2d957d5

3 files changed

Lines changed: 498 additions & 67 deletions

File tree

crates/sandlock-core/src/cow/dispatch.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,11 @@ pub(crate) async fn handle_cow_open(
259259
CowOpenPlan::Resolved(p) | CowOpenPlan::UpperReady { upper: p } => p,
260260
CowOpenPlan::NeedsCopy { upper, lower: _lower, file_size, rel_path } => {
261261
// Do the potentially-expensive copy on a blocking thread
262-
let upper_clone = upper.clone();
263262
let root = workdir_root.clone();
263+
let uroot = upper_root.clone();
264264
let rel = rel_path.clone();
265265
let copy_result = tokio::task::spawn_blocking(move || {
266-
crate::cow::seccomp::SeccompCowBranch::execute_copy(&root, &rel, &upper_clone)
266+
crate::cow::seccomp::SeccompCowBranch::execute_copy(&root, &uroot, &rel)
267267
}).await;
268268

269269
match copy_result {
@@ -510,13 +510,13 @@ fn cow_copy_rel<'a>(
510510
async fn execute_deferred_copy(
511511
cow_state: &Arc<Mutex<CowState>>,
512512
workdir_root: std::path::PathBuf,
513+
upper_root: std::path::PathBuf,
513514
rel: String,
514515
upper: std::path::PathBuf,
515516
file_size: u64,
516517
) -> Option<std::path::PathBuf> {
517-
let upper_clone = upper.clone();
518518
let copy_result = tokio::task::spawn_blocking(move || {
519-
crate::cow::seccomp::SeccompCowBranch::execute_copy(&workdir_root, &rel, &upper_clone)
519+
crate::cow::seccomp::SeccompCowBranch::execute_copy(&workdir_root, &upper_root, &rel)
520520
}).await;
521521
match copy_result {
522522
Ok(Ok(())) => Some(upper),
@@ -575,7 +575,17 @@ pub(crate) async fn handle_cow_write(
575575

576576
// Phase 2: execute the file copy outside the lock (if needed)
577577
if let Some(crate::cow::seccomp::CowCopyPlan::NeedsCopy { upper, lower: _lower, file_size }) = copy_plan {
578-
if execute_deferred_copy(cow_state, copy_workdir, copy_rel, upper, file_size).await.is_none() {
578+
// copy_workdir is workdir_root; we need upper_root for the dest side.
579+
// Re-acquire it briefly: execute_deferred_copy needs both roots.
580+
let uroot = {
581+
let st = cow_state.lock().await;
582+
st.branch.as_ref().map(|c| c.upper_dir().to_path_buf())
583+
};
584+
let uroot = match uroot {
585+
Some(p) => p,
586+
None => return NotifAction::Continue,
587+
};
588+
if execute_deferred_copy(cow_state, copy_workdir, uroot, copy_rel, upper, file_size).await.is_none() {
579589
return NotifAction::Continue;
580590
}
581591
}

0 commit comments

Comments
 (0)