Skip to content

Commit d21b5f2

Browse files
committed
fix(drivers): detect recursive bind-backed volumes
Signed-off-by: Evan Lezar <elezar@nvidia.com>
1 parent c9095c4 commit d21b5f2

3 files changed

Lines changed: 69 additions & 6 deletions

File tree

crates/openshell-driver-docker/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,9 +1821,10 @@ fn docker_tmpfs_option(option: &str) -> Result<Vec<String>, Status> {
18211821
fn docker_volume_is_bind_backed(volume: &bollard::models::Volume) -> bool {
18221822
volume.driver == "local"
18231823
&& volume.options.get("o").is_some_and(|options| {
1824-
options
1825-
.split(',')
1826-
.any(|option| option.trim().eq_ignore_ascii_case("bind"))
1824+
options.split(',').any(|option| {
1825+
let option = option.trim();
1826+
option.eq_ignore_ascii_case("bind") || option.eq_ignore_ascii_case("rbind")
1827+
})
18271828
})
18281829
}
18291830

crates/openshell-driver-docker/src/tests.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,20 @@ fn docker_local_volume_with_bind_option_is_bind_backed() {
871871
assert!(docker_volume_is_bind_backed(&volume));
872872
}
873873

874+
#[test]
875+
fn docker_local_volume_with_rbind_option_is_bind_backed() {
876+
let volume = inspected_volume(
877+
"local",
878+
HashMap::from([
879+
("type".to_string(), "none".to_string()),
880+
("o".to_string(), "rw,rbind".to_string()),
881+
("device".to_string(), "/tmp/openshell".to_string()),
882+
]),
883+
);
884+
885+
assert!(docker_volume_is_bind_backed(&volume));
886+
}
887+
874888
#[test]
875889
fn docker_local_volume_without_bind_option_is_not_bind_backed() {
876890
let volume = inspected_volume(

crates/openshell-driver-podman/src/driver.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ fn validated_container_name(sandbox_name: &str) -> Result<String, ComputeDriverE
6060
fn podman_volume_is_bind_backed(volume: &VolumeInspect) -> bool {
6161
(volume.driver.is_empty() || volume.driver == "local")
6262
&& volume.options.get("o").is_some_and(|options| {
63-
options
64-
.split(',')
65-
.any(|option| option.trim().eq_ignore_ascii_case("bind"))
63+
options.split(',').any(|option| {
64+
let option = option.trim();
65+
option.eq_ignore_ascii_case("bind") || option.eq_ignore_ascii_case("rbind")
66+
})
6667
})
6768
}
6869

@@ -889,6 +890,16 @@ mod tests {
889890
assert!(podman_volume_is_bind_backed(&volume));
890891
}
891892

893+
#[test]
894+
fn podman_local_volume_with_rbind_option_is_bind_backed() {
895+
let volume = VolumeInspect {
896+
driver: "local".to_string(),
897+
options: HashMap::from([("o".to_string(), "rw,rbind".to_string())]),
898+
};
899+
900+
assert!(podman_volume_is_bind_backed(&volume));
901+
}
902+
892903
#[test]
893904
fn podman_empty_driver_volume_with_bind_option_is_bind_backed() {
894905
let volume = VolumeInspect {
@@ -956,6 +967,43 @@ mod tests {
956967
let _ = std::fs::remove_file(socket_path);
957968
}
958969

970+
#[tokio::test]
971+
async fn validate_sandbox_rejects_rbind_backed_named_volume_unless_enabled() {
972+
let (socket_path, request_log, handle) = spawn_podman_stub(
973+
"rbind-volume-disabled",
974+
vec![StubResponse::new(
975+
StatusCode::OK,
976+
r#"{"Name":"work-rbind","Driver":"local","Options":{"type":"none","o":"rw,rbind","device":"/srv/work"}}"#,
977+
)],
978+
);
979+
let driver = test_driver(socket_path.clone());
980+
let sandbox = sandbox_with_volume_mount("work-rbind");
981+
982+
let err = driver
983+
.validate_sandbox_create(&sandbox)
984+
.await
985+
.expect_err("rbind-backed volume should require bind mount opt-in");
986+
987+
match err {
988+
ComputeDriverError::Precondition(message) => {
989+
assert!(message.contains("enable_bind_mounts = true"));
990+
}
991+
other => panic!("expected precondition error, got {other:?}"),
992+
}
993+
handle.await.expect("stub task should finish");
994+
assert_eq!(
995+
request_log
996+
.lock()
997+
.expect("request log lock should not be poisoned")
998+
.as_slice(),
999+
[format!(
1000+
"GET {}",
1001+
api_path("/libpod/volumes/work-rbind/json")
1002+
)]
1003+
);
1004+
let _ = std::fs::remove_file(socket_path);
1005+
}
1006+
9591007
#[tokio::test]
9601008
async fn validate_sandbox_allows_bind_backed_named_volume_when_enabled() {
9611009
let (socket_path, _request_log, handle) = spawn_podman_stub(

0 commit comments

Comments
 (0)