mirror of
https://github.com/denoland/deno.git
synced 2025-01-18 11:53:59 -05:00
fix(permissions): Allow ancestor path for --allow-ffi (#16765)
This commit changes "--allow-ffi" flag to support "parent paths", ie. if an FFI library is loaded we are checking if the library has an ancestor path in the allowlist for the FFI permission descriptor.
This commit is contained in:
parent
9e9e8f1e38
commit
ddd3506e69
1 changed files with 75 additions and 24 deletions
|
@ -1211,14 +1211,20 @@ impl UnaryPermission<FfiDescriptor> {
|
||||||
if self.global_state == PermissionState::Denied
|
if self.global_state == PermissionState::Denied
|
||||||
&& match path.as_ref() {
|
&& match path.as_ref() {
|
||||||
None => true,
|
None => true,
|
||||||
Some(path) => self.denied_list.contains(&FfiDescriptor(path.clone())),
|
Some(path) => self
|
||||||
|
.denied_list
|
||||||
|
.iter()
|
||||||
|
.any(|path_| path_.0.starts_with(path)),
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PermissionState::Denied
|
PermissionState::Denied
|
||||||
} else if self.global_state == PermissionState::Granted
|
} else if self.global_state == PermissionState::Granted
|
||||||
|| match path.as_ref() {
|
|| match path.as_ref() {
|
||||||
None => false,
|
None => false,
|
||||||
Some(path) => self.granted_list.contains(&FfiDescriptor(path.clone())),
|
Some(path) => self
|
||||||
|
.granted_list
|
||||||
|
.iter()
|
||||||
|
.any(|path_| path.starts_with(&path_.0)),
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
|
@ -1274,7 +1280,9 @@ impl UnaryPermission<FfiDescriptor> {
|
||||||
pub fn revoke(&mut self, path: Option<&Path>) -> PermissionState {
|
pub fn revoke(&mut self, path: Option<&Path>) -> PermissionState {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
let path = resolve_from_cwd(path).unwrap();
|
let path = resolve_from_cwd(path).unwrap();
|
||||||
self.granted_list.remove(&FfiDescriptor(path));
|
self
|
||||||
|
.granted_list
|
||||||
|
.retain(|path_| !path.starts_with(&path_.0));
|
||||||
} else {
|
} else {
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
}
|
}
|
||||||
|
@ -2489,7 +2497,8 @@ mod tests {
|
||||||
|
|
||||||
let mut perms = Permissions::from_options(&PermissionsOptions {
|
let mut perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_read: Some(allowlist.clone()),
|
allow_read: Some(allowlist.clone()),
|
||||||
allow_write: Some(allowlist),
|
allow_write: Some(allowlist.clone()),
|
||||||
|
allow_ffi: Some(allowlist),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -2503,6 +2512,10 @@ mod tests {
|
||||||
.write
|
.write
|
||||||
.check(Path::new("/a/specific/dir/name"), None)
|
.check(Path::new("/a/specific/dir/name"), None)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
assert!(perms
|
||||||
|
.ffi
|
||||||
|
.check(Some(Path::new("/a/specific/dir/name")))
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
// Inside of /a/specific but outside of /a/specific/dir/name
|
// Inside of /a/specific but outside of /a/specific/dir/name
|
||||||
assert!(perms.read.check(Path::new("/a/specific/dir"), None).is_ok());
|
assert!(perms.read.check(Path::new("/a/specific/dir"), None).is_ok());
|
||||||
|
@ -2510,6 +2523,7 @@ mod tests {
|
||||||
.write
|
.write
|
||||||
.check(Path::new("/a/specific/dir"), None)
|
.check(Path::new("/a/specific/dir"), None)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/a/specific/dir"))).is_ok());
|
||||||
|
|
||||||
// Inside of /a/specific and /a/specific/dir/name
|
// Inside of /a/specific and /a/specific/dir/name
|
||||||
assert!(perms
|
assert!(perms
|
||||||
|
@ -2520,6 +2534,10 @@ mod tests {
|
||||||
.write
|
.write
|
||||||
.check(Path::new("/a/specific/dir/name/inner"), None)
|
.check(Path::new("/a/specific/dir/name/inner"), None)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
assert!(perms
|
||||||
|
.ffi
|
||||||
|
.check(Some(Path::new("/a/specific/dir/name/inner")))
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
// Inside of /a/specific but outside of /a/specific/dir/name
|
// Inside of /a/specific but outside of /a/specific/dir/name
|
||||||
assert!(perms
|
assert!(perms
|
||||||
|
@ -2530,14 +2548,20 @@ mod tests {
|
||||||
.write
|
.write
|
||||||
.check(Path::new("/a/specific/other/dir"), None)
|
.check(Path::new("/a/specific/other/dir"), None)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
assert!(perms
|
||||||
|
.ffi
|
||||||
|
.check(Some(Path::new("/a/specific/other/dir")))
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
// Exact match with /b/c
|
// Exact match with /b/c
|
||||||
assert!(perms.read.check(Path::new("/b/c"), None).is_ok());
|
assert!(perms.read.check(Path::new("/b/c"), None).is_ok());
|
||||||
assert!(perms.write.check(Path::new("/b/c"), None).is_ok());
|
assert!(perms.write.check(Path::new("/b/c"), None).is_ok());
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/b/c"))).is_ok());
|
||||||
|
|
||||||
// Sub path within /b/c
|
// Sub path within /b/c
|
||||||
assert!(perms.read.check(Path::new("/b/c/sub/path"), None).is_ok());
|
assert!(perms.read.check(Path::new("/b/c/sub/path"), None).is_ok());
|
||||||
assert!(perms.write.check(Path::new("/b/c/sub/path"), None).is_ok());
|
assert!(perms.write.check(Path::new("/b/c/sub/path"), None).is_ok());
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/b/c/sub/path"))).is_ok());
|
||||||
|
|
||||||
// Sub path within /b/c, needs normalizing
|
// Sub path within /b/c, needs normalizing
|
||||||
assert!(perms
|
assert!(perms
|
||||||
|
@ -2548,14 +2572,20 @@ mod tests {
|
||||||
.write
|
.write
|
||||||
.check(Path::new("/b/c/sub/path/../path/."), None)
|
.check(Path::new("/b/c/sub/path/../path/."), None)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
assert!(perms
|
||||||
|
.ffi
|
||||||
|
.check(Some(Path::new("/b/c/sub/path/../path/.")))
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
// Inside of /b but outside of /b/c
|
// Inside of /b but outside of /b/c
|
||||||
assert!(perms.read.check(Path::new("/b/e"), None).is_err());
|
assert!(perms.read.check(Path::new("/b/e"), None).is_err());
|
||||||
assert!(perms.write.check(Path::new("/b/e"), None).is_err());
|
assert!(perms.write.check(Path::new("/b/e"), None).is_err());
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/b/e"))).is_err());
|
||||||
|
|
||||||
// Inside of /a but outside of /a/specific
|
// Inside of /a but outside of /a/specific
|
||||||
assert!(perms.read.check(Path::new("/a/b"), None).is_err());
|
assert!(perms.read.check(Path::new("/a/b"), None).is_err());
|
||||||
assert!(perms.write.check(Path::new("/a/b"), None).is_err());
|
assert!(perms.write.check(Path::new("/a/b"), None).is_err());
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/a/b"))).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -2809,6 +2839,12 @@ mod tests {
|
||||||
..Permissions::new_write(&Some(vec![PathBuf::from("/foo")]), false)
|
..Permissions::new_write(&Some(vec![PathBuf::from("/foo")]), false)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
ffi: UnaryPermission {
|
||||||
|
global_state: PermissionState::Prompt,
|
||||||
|
..Permissions::new_ffi(&Some(vec![PathBuf::from("/foo")]), false)
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
|
|
||||||
net: UnaryPermission {
|
net: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_net(&Some(svec!["127.0.0.1:8000"]), false).unwrap()
|
..Permissions::new_net(&Some(svec!["127.0.0.1:8000"]), false).unwrap()
|
||||||
|
@ -2825,11 +2861,6 @@ mod tests {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_run(&Some(svec!["deno"]), false).unwrap()
|
..Permissions::new_run(&Some(svec!["deno"]), false).unwrap()
|
||||||
},
|
},
|
||||||
ffi: UnaryPermission {
|
|
||||||
global_state: PermissionState::Prompt,
|
|
||||||
..Permissions::new_ffi(&Some(vec![PathBuf::from("deno")]), false)
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
hrtime: UnitPermission {
|
hrtime: UnitPermission {
|
||||||
state: PermissionState::Prompt,
|
state: PermissionState::Prompt,
|
||||||
..Permissions::new_hrtime(false)
|
..Permissions::new_hrtime(false)
|
||||||
|
@ -2847,6 +2878,11 @@ mod tests {
|
||||||
assert_eq!(perms2.write.query(None), PermissionState::Prompt);
|
assert_eq!(perms2.write.query(None), PermissionState::Prompt);
|
||||||
assert_eq!(perms2.write.query(Some(Path::new("/foo"))), PermissionState::Granted);
|
assert_eq!(perms2.write.query(Some(Path::new("/foo"))), PermissionState::Granted);
|
||||||
assert_eq!(perms2.write.query(Some(Path::new("/foo/bar"))), PermissionState::Granted);
|
assert_eq!(perms2.write.query(Some(Path::new("/foo/bar"))), PermissionState::Granted);
|
||||||
|
assert_eq!(perms1.ffi.query(None), PermissionState::Granted);
|
||||||
|
assert_eq!(perms1.ffi.query(Some(Path::new("/foo"))), PermissionState::Granted);
|
||||||
|
assert_eq!(perms2.ffi.query(None), PermissionState::Prompt);
|
||||||
|
assert_eq!(perms2.ffi.query(Some(Path::new("/foo"))), PermissionState::Granted);
|
||||||
|
assert_eq!(perms2.ffi.query(Some(Path::new("/foo/bar"))), PermissionState::Granted);
|
||||||
assert_eq!(perms1.net.query::<&str>(None), PermissionState::Granted);
|
assert_eq!(perms1.net.query::<&str>(None), PermissionState::Granted);
|
||||||
assert_eq!(perms1.net.query(Some(&("127.0.0.1", None))), PermissionState::Granted);
|
assert_eq!(perms1.net.query(Some(&("127.0.0.1", None))), PermissionState::Granted);
|
||||||
assert_eq!(perms2.net.query::<&str>(None), PermissionState::Prompt);
|
assert_eq!(perms2.net.query::<&str>(None), PermissionState::Prompt);
|
||||||
|
@ -2863,10 +2899,6 @@ mod tests {
|
||||||
assert_eq!(perms1.run.query(Some("deno")), PermissionState::Granted);
|
assert_eq!(perms1.run.query(Some("deno")), PermissionState::Granted);
|
||||||
assert_eq!(perms2.run.query(None), PermissionState::Prompt);
|
assert_eq!(perms2.run.query(None), PermissionState::Prompt);
|
||||||
assert_eq!(perms2.run.query(Some("deno")), PermissionState::Granted);
|
assert_eq!(perms2.run.query(Some("deno")), PermissionState::Granted);
|
||||||
assert_eq!(perms1.ffi.query(None), PermissionState::Granted);
|
|
||||||
assert_eq!(perms1.ffi.query(Some(Path::new("deno"))), PermissionState::Granted);
|
|
||||||
assert_eq!(perms2.ffi.query(None), PermissionState::Prompt);
|
|
||||||
assert_eq!(perms2.ffi.query(Some(Path::new("deno"))), PermissionState::Granted);
|
|
||||||
assert_eq!(perms1.hrtime.query(), PermissionState::Granted);
|
assert_eq!(perms1.hrtime.query(), PermissionState::Granted);
|
||||||
assert_eq!(perms2.hrtime.query(), PermissionState::Prompt);
|
assert_eq!(perms2.hrtime.query(), PermissionState::Prompt);
|
||||||
};
|
};
|
||||||
|
@ -2888,6 +2920,11 @@ mod tests {
|
||||||
assert_eq!(perms.write.query(Some(Path::new("/foo/bar"))), PermissionState::Prompt);
|
assert_eq!(perms.write.query(Some(Path::new("/foo/bar"))), PermissionState::Prompt);
|
||||||
prompt_value.set(true);
|
prompt_value.set(true);
|
||||||
assert_eq!(perms.write.request(None), PermissionState::Denied);
|
assert_eq!(perms.write.request(None), PermissionState::Denied);
|
||||||
|
prompt_value.set(false);
|
||||||
|
assert_eq!(perms.ffi.request(Some(Path::new("/foo"))), PermissionState::Denied);
|
||||||
|
assert_eq!(perms.ffi.query(Some(Path::new("/foo/bar"))), PermissionState::Prompt);
|
||||||
|
prompt_value.set(true);
|
||||||
|
assert_eq!(perms.ffi.request(None), PermissionState::Denied);
|
||||||
prompt_value.set(true);
|
prompt_value.set(true);
|
||||||
assert_eq!(perms.net.request(Some(&("127.0.0.1", None))), PermissionState::Granted);
|
assert_eq!(perms.net.request(Some(&("127.0.0.1", None))), PermissionState::Granted);
|
||||||
prompt_value.set(false);
|
prompt_value.set(false);
|
||||||
|
@ -2907,11 +2944,6 @@ mod tests {
|
||||||
assert_eq!(perms.run.query(None), PermissionState::Prompt);
|
assert_eq!(perms.run.query(None), PermissionState::Prompt);
|
||||||
prompt_value.set(false);
|
prompt_value.set(false);
|
||||||
assert_eq!(perms.run.request(Some("deno")), PermissionState::Granted);
|
assert_eq!(perms.run.request(Some("deno")), PermissionState::Granted);
|
||||||
prompt_value.set(true);
|
|
||||||
assert_eq!(perms.ffi.request(Some(Path::new("deno"))), PermissionState::Granted);
|
|
||||||
assert_eq!(perms.ffi.query(None), PermissionState::Prompt);
|
|
||||||
prompt_value.set(false);
|
|
||||||
assert_eq!(perms.ffi.request(Some(Path::new("deno"))), PermissionState::Granted);
|
|
||||||
prompt_value.set(false);
|
prompt_value.set(false);
|
||||||
assert_eq!(perms.hrtime.request(), PermissionState::Denied);
|
assert_eq!(perms.hrtime.request(), PermissionState::Denied);
|
||||||
prompt_value.set(true);
|
prompt_value.set(true);
|
||||||
|
@ -2938,6 +2970,14 @@ mod tests {
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
|
ffi: UnaryPermission {
|
||||||
|
global_state: PermissionState::Prompt,
|
||||||
|
..Permissions::new_ffi(
|
||||||
|
&Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
net: UnaryPermission {
|
net: UnaryPermission {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_net(
|
..Permissions::new_net(
|
||||||
|
@ -2958,11 +2998,6 @@ mod tests {
|
||||||
global_state: PermissionState::Prompt,
|
global_state: PermissionState::Prompt,
|
||||||
..Permissions::new_run(&Some(svec!["deno"]), false).unwrap()
|
..Permissions::new_run(&Some(svec!["deno"]), false).unwrap()
|
||||||
},
|
},
|
||||||
ffi: UnaryPermission {
|
|
||||||
global_state: PermissionState::Prompt,
|
|
||||||
..Permissions::new_ffi(&Some(vec![PathBuf::from("deno")]), false)
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
hrtime: UnitPermission {
|
hrtime: UnitPermission {
|
||||||
state: PermissionState::Denied,
|
state: PermissionState::Denied,
|
||||||
..Permissions::new_hrtime(false)
|
..Permissions::new_hrtime(false)
|
||||||
|
@ -2976,13 +3011,15 @@ mod tests {
|
||||||
assert_eq!(perms.write.revoke(Some(Path::new("/foo/bar"))), PermissionState::Prompt);
|
assert_eq!(perms.write.revoke(Some(Path::new("/foo/bar"))), PermissionState::Prompt);
|
||||||
assert_eq!(perms.write.query(Some(Path::new("/foo"))), PermissionState::Prompt);
|
assert_eq!(perms.write.query(Some(Path::new("/foo"))), PermissionState::Prompt);
|
||||||
assert_eq!(perms.write.query(Some(Path::new("/foo/baz"))), PermissionState::Granted);
|
assert_eq!(perms.write.query(Some(Path::new("/foo/baz"))), PermissionState::Granted);
|
||||||
|
assert_eq!(perms.ffi.revoke(Some(Path::new("/foo/bar"))), PermissionState::Prompt);
|
||||||
|
assert_eq!(perms.ffi.query(Some(Path::new("/foo"))), PermissionState::Prompt);
|
||||||
|
assert_eq!(perms.ffi.query(Some(Path::new("/foo/baz"))), PermissionState::Granted);
|
||||||
assert_eq!(perms.net.revoke(Some(&("127.0.0.1", Some(9000)))), PermissionState::Prompt);
|
assert_eq!(perms.net.revoke(Some(&("127.0.0.1", Some(9000)))), PermissionState::Prompt);
|
||||||
assert_eq!(perms.net.query(Some(&("127.0.0.1", None))), PermissionState::Prompt);
|
assert_eq!(perms.net.query(Some(&("127.0.0.1", None))), PermissionState::Prompt);
|
||||||
assert_eq!(perms.net.query(Some(&("127.0.0.1", Some(8000)))), PermissionState::Granted);
|
assert_eq!(perms.net.query(Some(&("127.0.0.1", Some(8000)))), PermissionState::Granted);
|
||||||
assert_eq!(perms.env.revoke(Some("HOME")), PermissionState::Prompt);
|
assert_eq!(perms.env.revoke(Some("HOME")), PermissionState::Prompt);
|
||||||
assert_eq!(perms.env.revoke(Some("hostname")), PermissionState::Prompt);
|
assert_eq!(perms.env.revoke(Some("hostname")), PermissionState::Prompt);
|
||||||
assert_eq!(perms.run.revoke(Some("deno")), PermissionState::Prompt);
|
assert_eq!(perms.run.revoke(Some("deno")), PermissionState::Prompt);
|
||||||
assert_eq!(perms.ffi.revoke(Some(Path::new("deno"))), PermissionState::Prompt);
|
|
||||||
assert_eq!(perms.hrtime.revoke(), PermissionState::Denied);
|
assert_eq!(perms.hrtime.revoke(), PermissionState::Denied);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3014,6 +3051,12 @@ mod tests {
|
||||||
assert!(perms.write.check(Path::new("/foo"), None).is_ok());
|
assert!(perms.write.check(Path::new("/foo"), None).is_ok());
|
||||||
assert!(perms.write.check(Path::new("/bar"), None).is_err());
|
assert!(perms.write.check(Path::new("/bar"), None).is_err());
|
||||||
|
|
||||||
|
prompt_value.set(true);
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/foo"))).is_ok());
|
||||||
|
prompt_value.set(false);
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/foo"))).is_ok());
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/bar"))).is_err());
|
||||||
|
|
||||||
prompt_value.set(true);
|
prompt_value.set(true);
|
||||||
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_ok());
|
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_ok());
|
||||||
prompt_value.set(false);
|
prompt_value.set(false);
|
||||||
|
@ -3075,6 +3118,14 @@ mod tests {
|
||||||
prompt_value.set(false);
|
prompt_value.set(false);
|
||||||
assert!(perms.write.check(Path::new("/bar"), None).is_ok());
|
assert!(perms.write.check(Path::new("/bar"), None).is_ok());
|
||||||
|
|
||||||
|
prompt_value.set(false);
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/foo"))).is_err());
|
||||||
|
prompt_value.set(true);
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/foo"))).is_err());
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/bar"))).is_ok());
|
||||||
|
prompt_value.set(false);
|
||||||
|
assert!(perms.ffi.check(Some(Path::new("/bar"))).is_ok());
|
||||||
|
|
||||||
prompt_value.set(false);
|
prompt_value.set(false);
|
||||||
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_err());
|
assert!(perms.net.check(&("127.0.0.1", Some(8000)), None).is_err());
|
||||||
prompt_value.set(true);
|
prompt_value.set(true);
|
||||||
|
|
Loading…
Add table
Reference in a new issue