kernel: support proc:{thread_fd}/<sub-handle> path format
The relibc fork's pthread_setname_np / pthread_getname_np /
pthread_setaffinity_np / pthread_getaffinity_np and
mutex_owner_id_is_live all use the path format
'proc:{thread_fd}/<sub-handle>' (e.g.
'proc:123/name' or 'proc:123/sched-affinity') via a single
Sys::open() call.
Previously the proc scheme's OpenTy::Auth handler in
src/scheme/proc.rs only recognized 'new-context' and
'cur-context' as literal strings, so '123/name' would
hit the _ => ENOENT arm and the relibc calls would
fail with ENOENT at runtime.
Fix: add a third arm in OpenTy::Auth that splits the
operation string on the first '/', parses the prefix as
a numeric context id, looks up the corresponding
ContextHandle in the HANDLES map, and recursively
dispatches to openat_context with the suffix as the
sub-handle path. This makes 'proc:123/name' resolve to
the same handle chain that 'dup(123, "name")' would
have produced.
The recursive call is safe because openat_context
doesn't depend on the Authority-only state. The
HANDLES map is read-locked; we drop the lock before
the recursive call by scoping the handles variable.
Discovered by Oracle review of Phase 0c patches
(Issue 1). The bug was latent in the original
P5-proc-setschedpolicy patch (before Phase 0c) and
survived because the relibc code paths were never
exercised at runtime.
This commit is contained in:
+58
-20
@@ -309,27 +309,65 @@ impl ProcScheme {
|
||||
}
|
||||
OpenTy::Auth => {
|
||||
extern "C" fn ret() {}
|
||||
let context = match operation_str.ok_or(Error::new(ENOENT))? {
|
||||
"new-context" => {
|
||||
let id = NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed))
|
||||
.ok_or(Error::new(EMFILE))?;
|
||||
let context = context::spawn(true, Some(id), ret, token)?;
|
||||
{
|
||||
let parent_groups =
|
||||
context::current().read(token.token()).groups.clone();
|
||||
context.write(token.token()).groups = parent_groups;
|
||||
}
|
||||
HANDLES.write(token.token()).insert(
|
||||
id.get(),
|
||||
Handle {
|
||||
context,
|
||||
kind: ContextHandle::OpenViaDup,
|
||||
},
|
||||
);
|
||||
return Ok((id.get(), InternalFlags::empty()));
|
||||
let operation_str = operation_str.ok_or(Error::new(ENOENT))?;
|
||||
// The relibc fork's pthread_setname_np / getname_np /
|
||||
// setaffinity_np / getaffinity_np all use the path
|
||||
// format "proc:{thread_fd}/<sub-handle>" via a single
|
||||
// Sys::open() call. To support this, we need to parse
|
||||
// the leading numeric prefix as a context id and the
|
||||
// remaining suffix as the sub-handle path. The
|
||||
// existing "new-context" and "cur-context" arms are
|
||||
// kept for the "literal" paths that don't have a
|
||||
// numeric prefix.
|
||||
let context = if operation_str == "new-context" {
|
||||
let id = NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed))
|
||||
.ok_or(Error::new(EMFILE))?;
|
||||
let context = context::spawn(true, Some(id), ret, token)?;
|
||||
{
|
||||
let parent_groups =
|
||||
context::current().read(token.token()).groups.clone();
|
||||
context.write(token.token()).groups = parent_groups;
|
||||
}
|
||||
"cur-context" => context::current(),
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
HANDLES.write(token.token()).insert(
|
||||
id.get(),
|
||||
Handle {
|
||||
context: context.clone(),
|
||||
kind: ContextHandle::OpenViaDup,
|
||||
},
|
||||
);
|
||||
return Ok((id.get(), InternalFlags::empty()));
|
||||
} else if operation_str == "cur-context" {
|
||||
context::current()
|
||||
} else if let Some(slash) = operation_str.find('/') {
|
||||
// Path format "<thread_fd>/<sub-handle>" used by
|
||||
// relibc's pthread_setname_np / getname_np /
|
||||
// setaffinity_np / getaffinity_np. Split on the
|
||||
// first '/' to get the numeric context id and
|
||||
// the sub-handle name. Look up the context by id
|
||||
// in the HANDLES map.
|
||||
let id_str = &operation_str[..slash];
|
||||
let sub_path = &operation_str[slash + 1..];
|
||||
let id = id_str.parse::<usize>().map_err(|_| Error::new(EINVAL))?;
|
||||
let context = {
|
||||
let handles = HANDLES.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(ENOENT))?;
|
||||
if !matches!(
|
||||
handle.kind,
|
||||
ContextHandle::OpenViaDup | ContextHandle::Authority
|
||||
) {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
handle.context.clone()
|
||||
};
|
||||
// Re-call openat_context with the sub-path. This
|
||||
// is a recursive open_inner which works because
|
||||
// openat_context doesn't depend on the open
|
||||
// path's Authority state.
|
||||
return self
|
||||
.open_inner(OpenTy::Ctxt(context), Some(sub_path), _flags, token)
|
||||
.map(|(id, flags)| (id, flags));
|
||||
} else {
|
||||
return Err(Error::new(ENOENT));
|
||||
};
|
||||
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user