clients: use fine-grained capabilities for privileged protocols
This commit is contained in:
parent
e543646944
commit
ef53d72ff8
13 changed files with 78 additions and 55 deletions
|
|
@ -1,6 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
client::ClientCaps,
|
||||
state::State,
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
||||
},
|
||||
|
|
@ -145,12 +146,16 @@ impl Acceptor {
|
|||
}
|
||||
let acc = Rc::new(Acceptor { socket });
|
||||
let futures = vec![
|
||||
state
|
||||
.eng
|
||||
.spawn(accept(acc.socket.secure.clone(), state.clone(), true)),
|
||||
state
|
||||
.eng
|
||||
.spawn(accept(acc.socket.insecure.clone(), state.clone(), false)),
|
||||
state.eng.spawn(accept(
|
||||
acc.socket.secure.clone(),
|
||||
state.clone(),
|
||||
ClientCaps::all(),
|
||||
)),
|
||||
state.eng.spawn(accept(
|
||||
acc.socket.insecure.clone(),
|
||||
state.clone(),
|
||||
ClientCaps::none(),
|
||||
)),
|
||||
];
|
||||
state.acceptor.set(Some(acc.clone()));
|
||||
Ok((acc, futures))
|
||||
|
|
@ -166,7 +171,7 @@ impl Acceptor {
|
|||
}
|
||||
}
|
||||
|
||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, caps: ClientCaps) {
|
||||
loop {
|
||||
let fd = match state.ring.accept(&fd, c::SOCK_CLOEXEC).await {
|
||||
Ok(fd) => fd,
|
||||
|
|
@ -176,7 +181,7 @@ async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
|||
}
|
||||
};
|
||||
let id = state.clients.id();
|
||||
if let Err(e) = state.clients.spawn(id, &state, fd, secure) {
|
||||
if let Err(e) = state.clients.spawn(id, &state, fd, caps) {
|
||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@ mod error;
|
|||
mod objects;
|
||||
mod tasks;
|
||||
|
||||
bitflags! {
|
||||
ClientCaps: u32;
|
||||
CAP_DATA_CONTROL_MANAGER = 1 << 0,
|
||||
CAP_VIRTUAL_KEYBOARD_MANAGER = 1 << 1,
|
||||
CAP_FOREIGN_TOPLEVEL_LIST = 1 << 2,
|
||||
CAP_IDLE_NOTIFIER = 1 << 3,
|
||||
CAP_SESSION_LOCK_MANAGER = 1 << 4,
|
||||
CAP_JAY_COMPOSITOR = 1 << 5,
|
||||
CAP_LAYER_SHELL = 1 << 6,
|
||||
CAP_SCREENCOPY_MANAGER = 1 << 7,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct ClientId(u64);
|
||||
|
||||
|
|
@ -101,7 +113,7 @@ impl Clients {
|
|||
id: ClientId,
|
||||
global: &Rc<State>,
|
||||
socket: Rc<OwnedFd>,
|
||||
secure: bool,
|
||||
caps: ClientCaps,
|
||||
) -> Result<(), ClientError> {
|
||||
let (uid, pid) = {
|
||||
let mut cred = c::ucred {
|
||||
|
|
@ -120,7 +132,7 @@ impl Clients {
|
|||
}
|
||||
}
|
||||
};
|
||||
self.spawn2(id, global, socket, uid, pid, secure, false)?;
|
||||
self.spawn2(id, global, socket, uid, pid, caps, false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +143,7 @@ impl Clients {
|
|||
socket: Rc<OwnedFd>,
|
||||
uid: c::uid_t,
|
||||
pid: c::pid_t,
|
||||
secure: bool,
|
||||
caps: ClientCaps,
|
||||
is_xwayland: bool,
|
||||
) -> Result<Rc<Client>, ClientError> {
|
||||
let data = Rc::new(Client {
|
||||
|
|
@ -145,7 +157,7 @@ impl Clients {
|
|||
shutdown: Default::default(),
|
||||
tracker: Default::default(),
|
||||
is_xwayland,
|
||||
secure,
|
||||
caps,
|
||||
last_enter_serial: Cell::new(0),
|
||||
pid_info: get_pid_info(uid, pid),
|
||||
serials: Default::default(),
|
||||
|
|
@ -165,13 +177,13 @@ impl Clients {
|
|||
data: data.clone(),
|
||||
};
|
||||
log::info!(
|
||||
"Client {} connected, pid: {}, uid: {}, fd: {}, secure: {}, comm: {:?}",
|
||||
"Client {} connected, pid: {}, uid: {}, fd: {}, comm: {:?}, caps: {:?}",
|
||||
id,
|
||||
pid,
|
||||
uid,
|
||||
client.data.socket.raw(),
|
||||
secure,
|
||||
data.pid_info.comm,
|
||||
caps,
|
||||
);
|
||||
self.clients.borrow_mut().insert(client.data.id, client);
|
||||
Ok(data)
|
||||
|
|
@ -193,13 +205,15 @@ impl Clients {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn broadcast<B>(&self, secure: bool, xwayland_only: bool, mut f: B)
|
||||
pub fn broadcast<B>(&self, required_caps: ClientCaps, xwayland_only: bool, mut f: B)
|
||||
where
|
||||
B: FnMut(&Rc<Client>),
|
||||
{
|
||||
let clients = self.clients.borrow();
|
||||
for client in clients.values() {
|
||||
if (!secure || client.data.secure) && (!xwayland_only || client.data.is_xwayland) {
|
||||
if client.data.caps.contains(required_caps)
|
||||
&& (!xwayland_only || client.data.is_xwayland)
|
||||
{
|
||||
f(&client.data);
|
||||
}
|
||||
}
|
||||
|
|
@ -258,7 +272,7 @@ pub struct Client {
|
|||
shutdown: AsyncEvent,
|
||||
pub tracker: Tracker<Client>,
|
||||
pub is_xwayland: bool,
|
||||
pub secure: bool,
|
||||
pub caps: ClientCaps,
|
||||
pub last_enter_serial: Cell<u32>,
|
||||
pub pid_info: PidInfo,
|
||||
pub serials: RefCell<VecDeque<SerialRange>>,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::Backend,
|
||||
client::Client,
|
||||
client::{Client, ClientCaps},
|
||||
ifs::{
|
||||
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1Global,
|
||||
ext_idle_notifier_v1::ExtIdleNotifierV1Global,
|
||||
|
|
@ -113,8 +113,8 @@ pub trait Global: GlobalBase {
|
|||
fn singleton(&self) -> bool;
|
||||
fn version(&self) -> u32;
|
||||
fn break_loops(&self) {}
|
||||
fn secure(&self) -> bool {
|
||||
false
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
ClientCaps::none()
|
||||
}
|
||||
fn xwayland_only(&self) -> bool {
|
||||
false
|
||||
|
|
@ -215,7 +215,7 @@ impl Globals {
|
|||
|
||||
fn insert(&self, state: &State, global: Rc<dyn Global>) {
|
||||
self.insert_no_broadcast_(&global);
|
||||
self.broadcast(state, global.secure(), global.xwayland_only(), |r| {
|
||||
self.broadcast(state, global.required_caps(), global.xwayland_only(), |r| {
|
||||
r.send_global(&global)
|
||||
});
|
||||
}
|
||||
|
|
@ -223,11 +223,13 @@ impl Globals {
|
|||
pub fn get(
|
||||
&self,
|
||||
name: GlobalName,
|
||||
allow_secure: bool,
|
||||
client_caps: ClientCaps,
|
||||
allow_xwayland_only: bool,
|
||||
) -> Result<Rc<dyn Global>, GlobalsError> {
|
||||
let global = self.take(name, false)?;
|
||||
if (global.secure() && !allow_secure) || (global.xwayland_only() && !allow_xwayland_only) {
|
||||
if client_caps.not_contains(global.required_caps())
|
||||
|| (global.xwayland_only() && !allow_xwayland_only)
|
||||
{
|
||||
return Err(GlobalsError::GlobalDoesNotExist(name));
|
||||
}
|
||||
Ok(global)
|
||||
|
|
@ -236,7 +238,7 @@ impl Globals {
|
|||
pub fn remove<T: WaylandGlobal>(&self, state: &State, global: &T) -> Result<(), GlobalsError> {
|
||||
let _global = self.take(global.name(), true)?;
|
||||
global.remove(self);
|
||||
self.broadcast(state, global.secure(), global.xwayland_only(), |r| {
|
||||
self.broadcast(state, global.required_caps(), global.xwayland_only(), |r| {
|
||||
r.send_global_remove(global.name())
|
||||
});
|
||||
Ok(())
|
||||
|
|
@ -247,14 +249,16 @@ impl Globals {
|
|||
}
|
||||
|
||||
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
|
||||
let secure = registry.client.secure;
|
||||
let caps = registry.client.caps;
|
||||
let xwayland = registry.client.is_xwayland;
|
||||
let globals = self.registry.lock();
|
||||
macro_rules! emit {
|
||||
($singleton:expr) => {
|
||||
for global in globals.values() {
|
||||
if global.singleton() == $singleton {
|
||||
if (secure || !global.secure()) && (xwayland || !global.xwayland_only()) {
|
||||
if caps.contains(global.required_caps())
|
||||
&& (xwayland || !global.xwayland_only())
|
||||
{
|
||||
registry.send_global(global);
|
||||
}
|
||||
}
|
||||
|
|
@ -268,11 +272,11 @@ impl Globals {
|
|||
fn broadcast<F: Fn(&Rc<WlRegistry>)>(
|
||||
&self,
|
||||
state: &State,
|
||||
secure: bool,
|
||||
required_caps: ClientCaps,
|
||||
xwayland_only: bool,
|
||||
f: F,
|
||||
) {
|
||||
state.clients.broadcast(secure, xwayland_only, |c| {
|
||||
state.clients.broadcast(required_caps, xwayland_only, |c| {
|
||||
let registries = c.lock_registries();
|
||||
for registry in registries.values() {
|
||||
f(registry);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_FOREIGN_TOPLEVEL_LIST},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::{
|
||||
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||
|
|
@ -145,8 +145,8 @@ impl Global for ExtForeignToplevelListV1Global {
|
|||
1
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_FOREIGN_TOPLEVEL_LIST
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_IDLE_NOTIFIER},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::ext_idle_notification_v1::ExtIdleNotificationV1,
|
||||
leaks::Tracker,
|
||||
|
|
@ -117,8 +117,8 @@ impl Global for ExtIdleNotifierV1Global {
|
|||
1
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_IDLE_NOTIFIER
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_SESSION_LOCK_MANAGER},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::ext_session_lock_v1::ExtSessionLockV1,
|
||||
leaks::Tracker,
|
||||
|
|
@ -98,8 +98,8 @@ impl Global for ExtSessionLockManagerV1Global {
|
|||
1
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_SESSION_LOCK_MANAGER
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_DATA_CONTROL_MANAGER},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::ipc::{
|
||||
zwlr_data_control_device_v1::{ZwlrDataControlDeviceV1, PRIMARY_SELECTION_SINCE},
|
||||
|
|
@ -111,8 +111,8 @@ impl Global for ZwlrDataControlManagerV1Global {
|
|||
2
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_DATA_CONTROL_MANAGER
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
cli::CliLogLevel,
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_JAY_COMPOSITOR},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::{
|
||||
jay_idle::JayIdle,
|
||||
|
|
@ -68,8 +68,8 @@ impl Global for JayCompositorGlobal {
|
|||
1
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_JAY_COMPOSITOR
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl WlRegistryRequestHandler for WlRegistry {
|
|||
fn bind(&self, bind: Bind, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let name = GlobalName::from_raw(bind.name);
|
||||
let globals = &self.client.state.globals;
|
||||
let global = globals.get(name, self.client.secure, self.client.is_xwayland)?;
|
||||
let global = globals.get(name, self.client.caps, self.client.is_xwayland)?;
|
||||
if global.interface().name() != bind.interface {
|
||||
return Err(WlRegistryError::InvalidInterface(InterfaceError {
|
||||
name: global.name(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_VIRTUAL_KEYBOARD_MANAGER},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::wl_seat::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
||||
leaks::Tracker,
|
||||
|
|
@ -61,8 +61,8 @@ impl Global for ZwpVirtualKeyboardManagerV1Global {
|
|||
1
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_VIRTUAL_KEYBOARD_MANAGER
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_LAYER_SHELL},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::wl_surface::zwlr_layer_surface_v1::{ZwlrLayerSurfaceV1, ZwlrLayerSurfaceV1Error},
|
||||
leaks::Tracker,
|
||||
|
|
@ -110,8 +110,8 @@ impl Global for ZwlrLayerShellV1Global {
|
|||
4
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_LAYER_SHELL
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
client::{Client, ClientCaps, ClientError, CAP_SCREENCOPY_MANAGER},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
||||
leaks::Tracker,
|
||||
|
|
@ -59,8 +59,8 @@ impl Global for ZwlrScreencopyManagerV1Global {
|
|||
3
|
||||
}
|
||||
|
||||
fn secure(&self) -> bool {
|
||||
true
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
CAP_SCREENCOPY_MANAGER
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ mod xwm;
|
|||
|
||||
use {
|
||||
crate::{
|
||||
client::ClientError,
|
||||
client::{ClientCaps, ClientError},
|
||||
compositor::DISPLAY,
|
||||
forker::{ForkerError, ForkerProxy},
|
||||
ifs::{
|
||||
|
|
@ -171,7 +171,7 @@ async fn run(
|
|||
Rc::new(client1),
|
||||
uapi::getuid(),
|
||||
pid,
|
||||
true,
|
||||
ClientCaps::all(),
|
||||
true,
|
||||
);
|
||||
let client = match client {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue