Skip to content

Commit ff4af79

Browse files
tamirdRebase bot
authored andcommitted
[starnix] Plug handle leak
Update the signature of `ServiceConnector::connect` to clarify ownership semantics and cache handles in SocketProviderServiceConnector. Before this change, each call to `service_connector` would mint a handle connected to the service provider without retaining ownership, resulting in one handle leaked for every network socket created. This leak appeared in commit 97583af. Change-Id: I8ec2c144e79906afe8da5d60540073d9a03de025 Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/871479 Reviewed-by: Vickie Cheng <[email protected]> Reviewed-by: Ghanan Gowripalan <[email protected]> Fuchsia-Auto-Submit: Tamir Duberstein <[email protected]> Commit-Queue: Auto-Submit <[email protected]>
1 parent f43b9f9 commit ff4af79

File tree

2 files changed

+51
-51
lines changed

2 files changed

+51
-51
lines changed

src/starnix/kernel/fs/socket/socket_inet.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,39 @@ use crate::{
1111
task::*,
1212
types::*,
1313
};
14-
use fidl::endpoints::ProtocolMarker;
14+
use fidl::endpoints::DiscoverableProtocolMarker as _;
1515
use fidl_fuchsia_posix_socket as fposix_socket;
1616
use fidl_fuchsia_posix_socket_raw as fposix_socket_raw;
17-
use fuchsia_component::client::connect_channel_to_protocol;
1817
use fuchsia_zircon as zx;
1918
use static_assertions::const_assert_eq;
20-
use std::{ffi::CStr, sync::Arc};
19+
use std::{cell::OnceCell, ffi::CStr, sync::Arc};
2120
use syncio::{ControlMessage, RecvMessageInfo, ServiceConnector, Zxio};
2221

2322
/// Connects to `fuchsia_posix_socket::Provider` or
2423
/// `fuchsia_posix_socket_raw::Provider`.
2524
struct SocketProviderServiceConnector;
2625

2726
impl ServiceConnector for SocketProviderServiceConnector {
28-
fn connect(service: &str, server_end: zx::Channel) -> zx::Status {
29-
let result = if service == fposix_socket_raw::ProviderMarker::DEBUG_NAME {
30-
connect_channel_to_protocol::<fposix_socket_raw::ProviderMarker>(server_end)
31-
} else if service == fposix_socket::ProviderMarker::DEBUG_NAME {
32-
connect_channel_to_protocol::<fposix_socket::ProviderMarker>(server_end)
33-
} else {
34-
return zx::Status::INTERNAL;
35-
};
36-
37-
if let Err(err) = result {
38-
if let Some(status) = err.downcast_ref::<zx::Status>() {
39-
return *status;
27+
fn connect(service_name: &str) -> Result<&'static zx::Channel, zx::Status> {
28+
match service_name {
29+
fposix_socket::ProviderMarker::PROTOCOL_NAME => {
30+
static mut CHANNEL: OnceCell<Result<zx::Channel, zx::Status>> = OnceCell::new();
31+
unsafe { &CHANNEL }
4032
}
41-
return zx::Status::INTERNAL;
33+
fposix_socket_raw::ProviderMarker::PROTOCOL_NAME => {
34+
static mut CHANNEL: OnceCell<Result<zx::Channel, zx::Status>> = OnceCell::new();
35+
unsafe { &CHANNEL }
36+
}
37+
_ => return Err(zx::Status::INTERNAL),
4238
}
43-
44-
zx::Status::OK
39+
.get_or_init(|| {
40+
let (client, server) = zx::Channel::create();
41+
let protocol_path = format!("/svc/{service_name}");
42+
fdio::service_connect(&protocol_path, server)?;
43+
Ok(client)
44+
})
45+
.as_ref()
46+
.map_err(|status| *status)
4547
}
4648
}
4749

src/starnix/lib/syncio/src/lib.rs

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ use crate::zxio::{
1111
use bitflags::bitflags;
1212
use fidl::{encoding::const_assert_eq, endpoints::ServerEnd};
1313
use fidl_fuchsia_io as fio;
14-
use fuchsia_zircon::{
15-
self as zx,
16-
sys::{ZX_ERR_INVALID_ARGS, ZX_ERR_NO_MEMORY, ZX_OK},
17-
zx_status_t, HandleBased,
18-
};
14+
use fuchsia_zircon::{self as zx, AsHandleRef as _, HandleBased as _};
1915
use std::{
2016
ffi::CStr,
2117
mem::{size_of, size_of_val},
@@ -24,7 +20,7 @@ use std::{
2420
};
2521
use zerocopy::{AsBytes, FromBytes};
2622
use zxio::{
27-
msghdr, sockaddr, sockaddr_storage, socklen_t, zx_handle_t, zxio_object_type_t,
23+
msghdr, sockaddr, sockaddr_storage, socklen_t, zx_handle_t, zx_status_t, zxio_object_type_t,
2824
zxio_seek_origin_t, zxio_storage_t, ZXIO_SHUTDOWN_OPTIONS_READ, ZXIO_SHUTDOWN_OPTIONS_WRITE,
2925
};
3026

@@ -411,31 +407,30 @@ impl std::fmt::Debug for Zxio {
411407
// in a more general function pointer (`fn(&str, zx::Channel) -> zx::Status`)
412408
// rather than having to implement this trait.
413409
pub trait ServiceConnector {
414-
/// Connect `server_end` to the protocol available at `service`.
415-
fn connect(service: &str, server_end: zx::Channel) -> zx::Status;
410+
/// Returns a channel to the service named by `service_name`.
411+
fn connect(service_name: &str) -> Result<&'static zx::Channel, zx::Status>;
416412
}
417413

418-
/// Connect a handle to a specified service.
414+
/// Sets `provider_handle` to a handle to the service named by `service_name`.
415+
///
416+
/// This function is intended to be passed to zxio_socket().
419417
///
420418
/// SAFETY: Dereferences the raw pointers `service_name` and `provider_handle`.
421419
unsafe extern "C" fn service_connector<S: ServiceConnector>(
422420
service_name: *const c_char,
423421
provider_handle: *mut zx_handle_t,
424422
) -> zx_status_t {
425-
let (client_end, server_end) = zx::Channel::create();
426-
427-
let service = match CStr::from_ptr(service_name).to_str() {
428-
Ok(s) => s,
429-
Err(_) => return ZX_ERR_INVALID_ARGS,
430-
};
431-
432-
let status = S::connect(service, server_end).into_raw();
433-
if status != ZX_OK {
434-
return status;
435-
}
436-
437-
*provider_handle = client_end.into_handle().into_raw();
438-
ZX_OK
423+
let status: zx::Status = (|| {
424+
let service_name = CStr::from_ptr(service_name)
425+
.to_str()
426+
.map_err(|std::str::Utf8Error { .. }| zx::Status::INVALID_ARGS)?;
427+
428+
S::connect(service_name).map(|channel| {
429+
*provider_handle = channel.raw_handle();
430+
})
431+
})()
432+
.into();
433+
status.into_raw()
439434
}
440435

441436
/// Sets `out_storage` as the zxio_storage of `out_context`.
@@ -449,13 +444,17 @@ unsafe extern "C" fn storage_allocator(
449444
out_context: *mut *mut c_void,
450445
) -> zx_status_t {
451446
let zxio_ptr_ptr = out_context as *mut *mut zxio_storage_t;
452-
if let Some(zxio_ptr) = zxio_ptr_ptr.as_mut() {
453-
if let Some(zxio) = zxio_ptr.as_mut() {
454-
*out_storage = zxio;
455-
return ZX_OK;
447+
let status: zx::Status = (|| {
448+
if let Some(zxio_ptr) = zxio_ptr_ptr.as_mut() {
449+
if let Some(zxio) = zxio_ptr.as_mut() {
450+
*out_storage = zxio;
451+
return Ok(());
452+
}
456453
}
457-
}
458-
ZX_ERR_NO_MEMORY
454+
Err(zx::Status::NO_MEMORY)
455+
})()
456+
.into();
457+
status.into_raw()
459458
}
460459

461460
impl Zxio {
@@ -1305,11 +1304,10 @@ mod test {
13051304
use super::*;
13061305

13071306
use anyhow::Error;
1308-
use fidl::endpoints::Proxy;
1307+
use fidl::endpoints::Proxy as _;
13091308
use fidl_fuchsia_io as fio;
13101309
use fuchsia_async as fasync;
13111310
use fuchsia_fs::directory;
1312-
use fuchsia_zircon::{AsHandleRef, HandleBased};
13131311

13141312
fn open_pkg() -> fio::DirectorySynchronousProxy {
13151313
let pkg_proxy = directory::open_in_namespace(
@@ -1470,7 +1468,7 @@ mod test {
14701468
&mut out_context_ptr as *mut *mut Zxio as *mut *mut c_void,
14711469
)
14721470
};
1473-
assert_eq!(out, ZX_OK);
1471+
assert_eq!(out, zx::sys::ZX_OK);
14741472
}
14751473

14761474
#[fuchsia::test]
@@ -1487,6 +1485,6 @@ mod test {
14871485
out_context,
14881486
)
14891487
};
1490-
assert_eq!(out, ZX_ERR_NO_MEMORY);
1488+
assert_eq!(out, zx::sys::ZX_ERR_NO_MEMORY);
14911489
}
14921490
}

0 commit comments

Comments
 (0)