feat: use privileged sockets
This commit is contained in:
parent
6d0826f319
commit
fd2dc23fac
6 changed files with 186 additions and 42 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
|
@ -61,7 +61,7 @@ dependencies = [
|
|||
"log",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix",
|
||||
"rustix 0.37.23",
|
||||
"slab",
|
||||
"socket2",
|
||||
"waker-fn",
|
||||
|
|
@ -89,7 +89,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix",
|
||||
"rustix 0.37.23",
|
||||
"signal-hook",
|
||||
"windows-sys",
|
||||
]
|
||||
|
|
@ -166,6 +166,12 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
|
|
@ -276,7 +282,7 @@ dependencies = [
|
|||
"launch-pad",
|
||||
"libc",
|
||||
"log-panics",
|
||||
"nix 0.26.2",
|
||||
"rustix 0.38.13",
|
||||
"scopeguard",
|
||||
"sendfd",
|
||||
"serde",
|
||||
|
|
@ -566,7 +572,7 @@ checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
|||
[[package]]
|
||||
name = "launch-pad"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/pop-os/launch-pad#702bb0531bcd0aca6c17b85e1b516e46f31ddaa1"
|
||||
source = "git+https://github.com/pop-os/launch-pad#4707088eb1111946fc5ea91e9b02ff2737552462"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix 0.26.2",
|
||||
|
|
@ -595,6 +601,12 @@ version = "0.3.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
|
|
@ -680,7 +692,7 @@ version = "0.23.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -693,7 +705,7 @@ version = "0.26.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.7.1",
|
||||
|
|
@ -796,7 +808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"libc",
|
||||
|
|
@ -875,7 +887,7 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -934,11 +946,24 @@ version = "0.37.23"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.3.8",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.11",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
|
|
@ -1117,7 +1142,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall",
|
||||
"rustix",
|
||||
"rustix 0.37.23",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ futures-util = "0.3"
|
|||
launch-pad = { git = "https://github.com/pop-os/launch-pad" }
|
||||
libc = "0.2"
|
||||
log-panics = { version = "2", features = ["with-backtrace"] }
|
||||
nix = { version = "0.26", features = ["fs"], default-features = false }
|
||||
rustix = "0.38"
|
||||
scopeguard = "1"
|
||||
sendfd = { version = "0.4", features = ["tokio"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
|
|
|||
32
src/comp.rs
32
src/comp.rs
|
|
@ -101,6 +101,31 @@ async fn receive_ipc(state: &mut IpcState, rx: &mut OwnedReadHalf) -> Result<()>
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_privileged_socket(
|
||||
sockets: &mut Vec<UnixStream>,
|
||||
env_vars: &[(String, String)],
|
||||
) -> Result<(Vec<(String, String)>, OwnedFd)> {
|
||||
// Create a new pair of unnamed Unix sockets
|
||||
let (comp_socket, client_socket) =
|
||||
UnixStream::pair().wrap_err("failed to create socket pair")?;
|
||||
// Push one socket to the list of sockets we were passed
|
||||
sockets.push(comp_socket);
|
||||
// Turn the other socket into a non-blocking fd, which we can pass to the child
|
||||
// process
|
||||
let client_fd = {
|
||||
let std_stream = client_socket
|
||||
.into_std()
|
||||
.wrap_err("failed to convert client socket to std socket")?;
|
||||
std_stream
|
||||
.set_nonblocking(true)
|
||||
.wrap_err("failed to mark client socket as non-blocking")?;
|
||||
OwnedFd::from(std_stream)
|
||||
};
|
||||
let mut env_vars = env_vars.to_vec();
|
||||
env_vars.push(("WAYLAND_SOCKET".into(), client_fd.as_raw_fd().to_string()));
|
||||
Ok((env_vars, client_fd))
|
||||
}
|
||||
|
||||
async fn send_fd(session_tx: &mut OwnedWriteHalf, stream: Vec<UnixStream>) -> Result<()> {
|
||||
// Turn our list of Unix streams into non-blocking file descriptors.
|
||||
let fds = stream
|
||||
|
|
@ -134,12 +159,15 @@ async fn send_fd(session_tx: &mut OwnedWriteHalf, stream: Vec<UnixStream>) -> Re
|
|||
tokio::time::sleep(std::time::Duration::from_micros(100)).await;
|
||||
// Send our file descriptors.
|
||||
let fd: &UnixStream = session_tx.as_ref();
|
||||
info!("sending {} fds", fds.len());
|
||||
|
||||
fd.send_with_fd(
|
||||
&[0],
|
||||
&fds.iter().map(|fd| fd.as_raw_fd()).collect::<Vec<_>>(),
|
||||
&fds.into_iter()
|
||||
.map(|fd| fd.into_raw_fd())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.wrap_err("failed to send fd")?;
|
||||
info!("sent {} fds", fds.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
81
src/main.rs
81
src/main.rs
|
|
@ -9,17 +9,19 @@ mod service;
|
|||
mod systemd;
|
||||
|
||||
use std::{
|
||||
os::fd::AsRawFd,
|
||||
os::fd::{AsRawFd, IntoRawFd},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use async_signals::Signals;
|
||||
use color_eyre::{eyre::WrapErr, Result};
|
||||
use comp::create_privileged_socket;
|
||||
use cosmic_notifications_util::{DAEMON_NOTIFICATIONS_FD, PANEL_NOTIFICATIONS_FD};
|
||||
use futures_util::StreamExt;
|
||||
use launch_pad::{process::Process, ProcessManager};
|
||||
use service::SessionRequest;
|
||||
use tokio::{
|
||||
net::UnixStream,
|
||||
sync::{
|
||||
mpsc::{self, Receiver, Sender},
|
||||
oneshot,
|
||||
|
|
@ -99,7 +101,7 @@ async fn start(
|
|||
))
|
||||
.await;
|
||||
let token = CancellationToken::new();
|
||||
let (_, socket_rx) = mpsc::unbounded_channel();
|
||||
let (socket_tx, socket_rx) = mpsc::unbounded_channel();
|
||||
let (env_tx, env_rx) = oneshot::channel();
|
||||
let compositor_handle = comp::run_compositor(
|
||||
&process_manager,
|
||||
|
|
@ -160,6 +162,7 @@ async fn start(
|
|||
panel_key.clone(),
|
||||
panel_env_vars.clone(),
|
||||
panel_notifications_fd.as_raw_fd(),
|
||||
socket_tx.clone(),
|
||||
))
|
||||
.await
|
||||
.expect("failed to start notifications daemon"),
|
||||
|
|
@ -180,6 +183,7 @@ async fn start(
|
|||
notif_key,
|
||||
daemon_env_vars,
|
||||
daemon_notifications_fd.as_raw_fd(),
|
||||
socket_tx.clone(),
|
||||
))
|
||||
.await
|
||||
.expect("failed to start panel"),
|
||||
|
|
@ -187,19 +191,40 @@ async fn start(
|
|||
drop(guard);
|
||||
|
||||
let span = info_span!(parent: None, "cosmic-app-library");
|
||||
start_component("cosmic-app-library", span, &process_manager, &env_vars).await;
|
||||
start_component(
|
||||
"cosmic-app-library",
|
||||
span,
|
||||
&process_manager,
|
||||
&env_vars,
|
||||
&socket_tx,
|
||||
)
|
||||
.await;
|
||||
|
||||
let span = info_span!(parent: None, "cosmic-launcher");
|
||||
start_component("cosmic-launcher", span, &process_manager, &env_vars).await;
|
||||
start_component(
|
||||
"cosmic-launcher",
|
||||
span,
|
||||
&process_manager,
|
||||
&env_vars,
|
||||
&socket_tx,
|
||||
)
|
||||
.await;
|
||||
|
||||
let span = info_span!(parent: None, "cosmic-workspaces");
|
||||
start_component("cosmic-workspaces", span, &process_manager, &env_vars).await;
|
||||
start_component(
|
||||
"cosmic-workspaces",
|
||||
span,
|
||||
&process_manager,
|
||||
&env_vars,
|
||||
&socket_tx,
|
||||
)
|
||||
.await;
|
||||
|
||||
let span = info_span!(parent: None, "cosmic-osd");
|
||||
start_component("cosmic-osd", span, &process_manager, &env_vars).await;
|
||||
start_component("cosmic-osd", span, &process_manager, &env_vars, &socket_tx).await;
|
||||
|
||||
let span = info_span!(parent: None, "cosmic-bg");
|
||||
start_component("cosmic-bg", span, &process_manager, &env_vars).await;
|
||||
start_component("cosmic-bg", span, &process_manager, &env_vars, &socket_tx).await;
|
||||
|
||||
let span = info_span!(parent: None, "xdg-desktop-portal-cosmic");
|
||||
start_component(
|
||||
|
|
@ -207,6 +232,7 @@ async fn start(
|
|||
span,
|
||||
&process_manager,
|
||||
&env_vars,
|
||||
&socket_tx,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
@ -258,9 +284,18 @@ async fn start_component(
|
|||
span: tracing::Span,
|
||||
process_manager: &ProcessManager,
|
||||
env_vars: &[(String, String)],
|
||||
socket_tx: &mpsc::UnboundedSender<Vec<UnixStream>>,
|
||||
) {
|
||||
let mut sockets = Vec::with_capacity(1);
|
||||
let (env_vars, fd) = create_privileged_socket(&mut sockets, env_vars).unwrap();
|
||||
let fd = fd.into_raw_fd();
|
||||
if let Err(why) = socket_tx.send(sockets) {
|
||||
error!(?why, "Failed to send the privileged socket");
|
||||
}
|
||||
let socket_tx_clone = socket_tx.clone();
|
||||
let stdout_span = span.clone();
|
||||
let stderr_span = span.clone();
|
||||
let cmd_clone = cmd.to_string();
|
||||
process_manager
|
||||
.start(
|
||||
Process::new()
|
||||
|
|
@ -279,7 +314,37 @@ async fn start_component(
|
|||
warn!("{}", line);
|
||||
}
|
||||
.instrument(stderr_span)
|
||||
}),
|
||||
})
|
||||
.with_on_exit(move |mut pman, key, err_code, will_restart| {
|
||||
if let Some(err) = err_code {
|
||||
error!("{cmd_clone} exited with error {}", err.to_string());
|
||||
}
|
||||
|
||||
let socket_tx_clone = socket_tx_clone.clone();
|
||||
async move {
|
||||
if !will_restart {
|
||||
return;
|
||||
}
|
||||
let mut sockets = Vec::with_capacity(1);
|
||||
let env_vars = Vec::with_capacity(1);
|
||||
let (env_vars, new_fd) =
|
||||
create_privileged_socket(&mut sockets, &env_vars).unwrap();
|
||||
|
||||
let new_fd = new_fd.into_raw_fd();
|
||||
|
||||
if let Err(why) = socket_tx_clone.send(sockets) {
|
||||
error!(?why, "Failed to send the privileged socket");
|
||||
}
|
||||
if let Err(why) = pman.update_process_env(&key, env_vars).await {
|
||||
error!(?why, "Failed to update environment variables");
|
||||
}
|
||||
if let Err(why) = pman.update_process_fds(&key, move || vec![new_fd]).await
|
||||
{
|
||||
error!(?why, "Failed to update fds");
|
||||
}
|
||||
}
|
||||
})
|
||||
.with_fds(move || vec![fd]),
|
||||
)
|
||||
.await
|
||||
.expect(&format!("failed to start {}", cmd));
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@ use color_eyre::eyre::Context;
|
|||
use color_eyre::Result;
|
||||
use launch_pad::process::Process;
|
||||
use launch_pad::ProcessKey;
|
||||
use std::os::fd::{OwnedFd, RawFd};
|
||||
use std::os::fd::{IntoRawFd, OwnedFd, RawFd};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::Instrument;
|
||||
|
||||
use crate::comp::create_privileged_socket;
|
||||
|
||||
pub fn create_socket() -> Result<(OwnedFd, OwnedFd)> {
|
||||
// Create a new pair of unnamed Unix sockets
|
||||
let (sock_1, sock_2) = UnixStream::pair().wrap_err("failed to create socket pair")?;
|
||||
|
|
@ -28,20 +31,28 @@ pub fn notifications_process(
|
|||
span: tracing::Span,
|
||||
cmd: &'static str,
|
||||
key: Arc<Mutex<Option<ProcessKey>>>,
|
||||
env_vars: Vec<(String, String)>,
|
||||
mut env_vars: Vec<(String, String)>,
|
||||
fd: RawFd,
|
||||
restart_span: tracing::Span,
|
||||
restart_cmd: &'static str,
|
||||
restart_key: Arc<Mutex<Option<ProcessKey>>>,
|
||||
restart_env_vars: Vec<(String, String)>,
|
||||
restart_fd: RawFd,
|
||||
socket_tx: mpsc::UnboundedSender<Vec<tokio::net::UnixStream>>,
|
||||
) -> Process {
|
||||
env_vars.retain(|v| &v.0 != "WAYLAND_SOCKET");
|
||||
|
||||
let stdout_span = span.clone();
|
||||
let stderr_span = span.clone();
|
||||
let mut sockets = Vec::with_capacity(1);
|
||||
let (env_vars, privileged_fd) = create_privileged_socket(&mut sockets, &env_vars).unwrap();
|
||||
_ = socket_tx.send(sockets);
|
||||
let env_clone = env_vars.clone();
|
||||
let socket_tx_clone = socket_tx.clone();
|
||||
let privileged_fd = privileged_fd.into_raw_fd();
|
||||
Process::new()
|
||||
.with_executable(cmd)
|
||||
.with_fds(move || vec![fd])
|
||||
.with_fds(move || vec![privileged_fd, fd])
|
||||
.with_on_stdout(move |_, _, line| {
|
||||
let stdout_span = stdout_span.clone();
|
||||
async move {
|
||||
|
|
@ -56,7 +67,7 @@ pub fn notifications_process(
|
|||
}
|
||||
.instrument(stderr_span)
|
||||
})
|
||||
.with_on_exit(move |pman, _, _, will_restart| {
|
||||
.with_on_exit(move |pman, my_key, _, will_restart| {
|
||||
// force restart of notifications / panel when the other exits
|
||||
let new_process = notifications_process(
|
||||
restart_span.clone(),
|
||||
|
|
@ -69,13 +80,37 @@ pub fn notifications_process(
|
|||
key.clone(),
|
||||
env_clone.clone(),
|
||||
fd,
|
||||
socket_tx_clone.clone(),
|
||||
);
|
||||
let restart_key = restart_key.clone();
|
||||
let socket_tx_clone = socket_tx_clone.clone();
|
||||
|
||||
let env_clone = env_clone.clone();
|
||||
let mut pman_clone = pman.clone();
|
||||
async move {
|
||||
if will_restart {
|
||||
let mut sockets = Vec::with_capacity(1);
|
||||
let (env_vars, new_fd) =
|
||||
create_privileged_socket(&mut sockets, &env_clone).unwrap();
|
||||
|
||||
let new_fd = new_fd.into_raw_fd();
|
||||
|
||||
if let Err(why) = socket_tx_clone.send(sockets) {
|
||||
error!(?why, "Failed to send the privileged socket");
|
||||
}
|
||||
if let Err(why) = pman_clone.update_process_env(&my_key, env_vars).await {
|
||||
error!(?why, "Failed to update environment variables");
|
||||
}
|
||||
if let Err(why) = pman_clone
|
||||
.update_process_fds(&my_key, move || vec![new_fd, fd])
|
||||
.await
|
||||
{
|
||||
error!(?why, "Failed to update fds");
|
||||
}
|
||||
|
||||
let Some(old) = restart_key.lock().unwrap().clone() else {
|
||||
error!("Couldn't stop previous invocation of {}", cmd);
|
||||
return;
|
||||
error!("Couldn't stop previous invocation of {}", cmd);
|
||||
return;
|
||||
};
|
||||
_ = pman.stop_process(old).await;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
use color_eyre::eyre::{ContextCompat, Result, WrapErr};
|
||||
use nix::fcntl;
|
||||
use color_eyre::eyre::{Result, WrapErr};
|
||||
use rustix::io::FdFlags;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
pub(crate) fn mark_as_not_cloexec(file: &impl AsFd) -> Result<()> {
|
||||
let raw_fd = file.as_fd().as_raw_fd();
|
||||
let fd_flags = fcntl::FdFlag::from_bits(
|
||||
fcntl::fcntl(raw_fd, fcntl::FcntlArg::F_GETFD)
|
||||
.wrap_err("failed to get GETFD value of stream")?,
|
||||
)
|
||||
.wrap_err("failed to get fd flags from file")?;
|
||||
fcntl::fcntl(
|
||||
raw_fd,
|
||||
fcntl::FcntlArg::F_SETFD(fd_flags.difference(fcntl::FdFlag::FD_CLOEXEC)),
|
||||
)
|
||||
.wrap_err("failed to set CLOEXEC on file")?;
|
||||
Ok(())
|
||||
let flags = rustix::io::fcntl_getfd(file).wrap_err("failed to get GETFD value of stream")?;
|
||||
rustix::io::fcntl_setfd(file, flags.difference(FdFlags::CLOEXEC))
|
||||
.wrap_err("failed to unset CLOEXEC on file")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue