config: allow configuring client capabilities
This commit is contained in:
parent
76a1a86091
commit
e680a3dc09
21 changed files with 624 additions and 39 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
client::{CAPS_DEFAULT, ClientCaps},
|
||||
client::ClientCaps,
|
||||
security_context_acceptor::AcceptorMetadata,
|
||||
state::State,
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
||||
|
|
@ -149,11 +149,11 @@ impl Acceptor {
|
|||
let futures = vec![
|
||||
state.eng.spawn(
|
||||
"secure acceptor",
|
||||
accept(acc.socket.secure.clone(), state.clone(), ClientCaps::all()),
|
||||
accept(acc.socket.secure.clone(), state.clone(), true),
|
||||
),
|
||||
state.eng.spawn(
|
||||
"insecure acceptor",
|
||||
accept(acc.socket.insecure.clone(), state.clone(), CAPS_DEFAULT),
|
||||
accept(acc.socket.insecure.clone(), state.clone(), false),
|
||||
),
|
||||
];
|
||||
state.acceptor.set(Some(acc.clone()));
|
||||
|
|
@ -170,8 +170,11 @@ impl Acceptor {
|
|||
}
|
||||
}
|
||||
|
||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, effective_caps: ClientCaps) {
|
||||
let metadata = Rc::new(AcceptorMetadata::default());
|
||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
||||
let metadata = Rc::new(AcceptorMetadata {
|
||||
secure,
|
||||
..Default::default()
|
||||
});
|
||||
loop {
|
||||
let fd = match state.ring.accept(&fd, c::SOCK_CLOEXEC).await {
|
||||
Ok(fd) => fd,
|
||||
|
|
@ -181,10 +184,9 @@ async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, effective_caps: ClientCaps) {
|
|||
}
|
||||
};
|
||||
let id = state.clients.id();
|
||||
if let Err(e) =
|
||||
state
|
||||
.clients
|
||||
.spawn(id, &state, fd, effective_caps, ClientCaps::all(), &metadata)
|
||||
if let Err(e) = state
|
||||
.clients
|
||||
.spawn(id, &state, fd, ClientCaps::all(), false, &metadata)
|
||||
{
|
||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ impl Clients {
|
|||
id: ClientId,
|
||||
global: &Rc<State>,
|
||||
socket: Rc<OwnedFd>,
|
||||
effective_caps: ClientCaps,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps_for_children: bool,
|
||||
acceptor: &Rc<AcceptorMetadata>,
|
||||
) -> Result<(), ClientError> {
|
||||
let Some((uid, pid)) = get_socket_creds(&socket) else {
|
||||
|
|
@ -139,8 +139,8 @@ impl Clients {
|
|||
socket,
|
||||
uid,
|
||||
pid,
|
||||
effective_caps,
|
||||
bounding_caps,
|
||||
set_bounding_caps_for_children,
|
||||
false,
|
||||
acceptor,
|
||||
)?;
|
||||
|
|
@ -154,11 +154,15 @@ impl Clients {
|
|||
socket: Rc<OwnedFd>,
|
||||
uid: c::uid_t,
|
||||
pid: c::pid_t,
|
||||
effective_caps: ClientCaps,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps_for_children: bool,
|
||||
is_xwayland: bool,
|
||||
acceptor: &Rc<AcceptorMetadata>,
|
||||
) -> Result<Rc<Client>, ClientError> {
|
||||
let effective_caps = match acceptor.sandboxed {
|
||||
true => CAPS_DEFAULT_SANDBOXED,
|
||||
false => CAPS_DEFAULT,
|
||||
};
|
||||
let data = Rc::new_cyclic(|slf| Client {
|
||||
id,
|
||||
state: global.clone(),
|
||||
|
|
@ -170,8 +174,8 @@ impl Clients {
|
|||
shutdown: Default::default(),
|
||||
tracker: Default::default(),
|
||||
is_xwayland,
|
||||
effective_caps,
|
||||
bounding_caps,
|
||||
effective_caps: Cell::new(effective_caps & bounding_caps),
|
||||
bounding_caps_for_children: Cell::new(bounding_caps),
|
||||
last_enter_serial: Default::default(),
|
||||
pid_info: get_pid_info(uid, pid),
|
||||
serials: Default::default(),
|
||||
|
|
@ -192,6 +196,10 @@ impl Clients {
|
|||
acceptor: acceptor.clone(),
|
||||
});
|
||||
track!(data, data);
|
||||
global.update_capabilities(&data, bounding_caps, set_bounding_caps_for_children);
|
||||
if acceptor.secure || is_xwayland {
|
||||
data.effective_caps.set(ClientCaps::all());
|
||||
}
|
||||
let display = Rc::new(WlDisplay::new(&data));
|
||||
track!(data, display);
|
||||
data.objects.display.set(Some(display.clone()));
|
||||
|
|
@ -207,7 +215,7 @@ impl Clients {
|
|||
uid,
|
||||
client.data.socket.raw(),
|
||||
data.pid_info.comm,
|
||||
effective_caps,
|
||||
data.effective_caps.get(),
|
||||
);
|
||||
client.data.property_changed(CL_CHANGED_NEW);
|
||||
self.clients.borrow_mut().insert(client.data.id, client);
|
||||
|
|
@ -236,7 +244,7 @@ impl Clients {
|
|||
{
|
||||
let clients = self.clients.borrow();
|
||||
for client in clients.values() {
|
||||
if client.data.effective_caps.contains(required_caps)
|
||||
if client.data.effective_caps.get().contains(required_caps)
|
||||
&& (!xwayland_only || client.data.is_xwayland)
|
||||
{
|
||||
f(&client.data);
|
||||
|
|
@ -298,8 +306,8 @@ pub struct Client {
|
|||
shutdown: AsyncEvent,
|
||||
pub tracker: Tracker<Client>,
|
||||
pub is_xwayland: bool,
|
||||
pub effective_caps: ClientCaps,
|
||||
pub bounding_caps: ClientCaps,
|
||||
pub effective_caps: Cell<ClientCaps>,
|
||||
pub bounding_caps_for_children: Cell<ClientCaps>,
|
||||
pub last_enter_serial: Cell<Option<u64>>,
|
||||
pub pid_info: PidInfo,
|
||||
pub serials: RefCell<VecDeque<SerialRange>>,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use crate::it::test_config::TEST_CONFIG_ENTRY;
|
|||
use {
|
||||
crate::{
|
||||
backend::{ConnectorId, DrmDeviceId, InputDeviceId},
|
||||
client::{Client, ClientCaps},
|
||||
config::handler::ConfigProxyHandler,
|
||||
ifs::wl_seat::SeatId,
|
||||
state::State,
|
||||
|
|
@ -180,6 +181,17 @@ impl ConfigProxy {
|
|||
pub fn initial_tile_state(&self, data: &ToplevelData) -> Option<TileState> {
|
||||
self.handler.get()?.initial_tile_state(data)
|
||||
}
|
||||
|
||||
pub fn update_capabilities(
|
||||
&self,
|
||||
data: &Rc<Client>,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps: bool,
|
||||
) {
|
||||
if let Some(handler) = self.handler.get() {
|
||||
handler.update_capabilities(data, bounding_caps, set_bounding_caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ConfigProxy {
|
||||
|
|
@ -238,6 +250,8 @@ impl ConfigProxy {
|
|||
client_matchers: Default::default(),
|
||||
client_matcher_cache: Default::default(),
|
||||
client_matcher_leafs: Default::default(),
|
||||
client_matcher_capabilities: Default::default(),
|
||||
client_matcher_bounding_capabilities: Default::default(),
|
||||
window_matcher_ids: NumCell::new(1),
|
||||
window_matchers: Default::default(),
|
||||
window_matcher_cache: Default::default(),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use {
|
|||
InputDeviceAccelProfile, InputDeviceCapability, InputDeviceClickMethod, InputDeviceId,
|
||||
transaction::BackendConnectorTransactionError,
|
||||
},
|
||||
client::{Client, ClientId},
|
||||
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientId},
|
||||
cmm::cmm_eotf::Eotf,
|
||||
compositor::MAX_EXTENTS,
|
||||
config::ConfigProxy,
|
||||
|
|
@ -53,7 +53,7 @@ use {
|
|||
ipc::{ClientMessage, Response, ServerMessage, WorkspaceSource},
|
||||
},
|
||||
Axis, Direction, Workspace,
|
||||
client::{Client as ConfigClient, ClientMatcher},
|
||||
client::{Client as ConfigClient, ClientCapabilities, ClientMatcher},
|
||||
input::{
|
||||
FocusFollowsMouseMode, InputDevice, LayerDirection, Seat, Timeline,
|
||||
acceleration::{ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT, AccelProfile},
|
||||
|
|
@ -127,6 +127,20 @@ pub(super) struct ConfigProxyHandler {
|
|||
CopyHashMap<ClientMatcher, Rc<CachedCriterion<ClientCriterionIpc, Rc<Client>>>>,
|
||||
pub client_matcher_cache: CriterionCache<ClientCriterionIpc, Rc<Client>>,
|
||||
pub client_matcher_leafs: CopyHashMap<ClientMatcher, Rc<ClmLeafMatcher>>,
|
||||
pub client_matcher_capabilities: CopyHashMap<
|
||||
ClientMatcher,
|
||||
(
|
||||
Rc<CachedCriterion<ClientCriterionIpc, Rc<Client>>>,
|
||||
ClientCaps,
|
||||
),
|
||||
>,
|
||||
pub client_matcher_bounding_capabilities: CopyHashMap<
|
||||
ClientMatcher,
|
||||
(
|
||||
Rc<CachedCriterion<ClientCriterionIpc, Rc<Client>>>,
|
||||
ClientCaps,
|
||||
),
|
||||
>,
|
||||
|
||||
pub window_matcher_ids: NumCell<u64>,
|
||||
pub window_matchers:
|
||||
|
|
@ -2009,6 +2023,8 @@ impl ConfigProxyHandler {
|
|||
fn handle_destroy_client_matcher(&self, matcher: ClientMatcher) {
|
||||
self.client_matchers.remove(&matcher);
|
||||
self.client_matcher_leafs.remove(&matcher);
|
||||
self.client_matcher_capabilities.remove(&matcher);
|
||||
self.client_matcher_bounding_capabilities.remove(&matcher);
|
||||
}
|
||||
|
||||
fn handle_enable_client_matcher_events(
|
||||
|
|
@ -2579,6 +2595,28 @@ impl ConfigProxyHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_client_matcher_capabilities(
|
||||
&self,
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
) -> Result<(), CphError> {
|
||||
let m = self.get_client_matcher(matcher)?;
|
||||
self.client_matcher_capabilities
|
||||
.set(matcher, (m, caps.to_client_caps()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_client_matcher_bounding_capabilities(
|
||||
&self,
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
) -> Result<(), CphError> {
|
||||
let m = self.get_client_matcher(matcher)?;
|
||||
self.client_matcher_bounding_capabilities
|
||||
.set(matcher, (m, caps.to_client_caps()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_request(self: &Rc<Self>, msg: &[u8]) {
|
||||
if let Err(e) = self.handle_request_(msg) {
|
||||
log::error!("Could not handle client request: {}", ErrorFmt(e));
|
||||
|
|
@ -3159,6 +3197,12 @@ impl ConfigProxyHandler {
|
|||
.wrn("connector_set_blend_space")?,
|
||||
ClientMessage::SetBarFont { font } => self.handle_set_bar_font(font),
|
||||
ClientMessage::SetTitleFont { font } => self.handle_set_title_font(font),
|
||||
ClientMessage::SetClientMatcherCapabilities { matcher, caps } => self
|
||||
.handle_set_client_matcher_capabilities(matcher, caps)
|
||||
.wrn("set_client_matcher_capabilities")?,
|
||||
ClientMessage::SetClientMatcherBoundingCapabilities { matcher, caps } => self
|
||||
.handle_set_client_matcher_bounding_capabilities(matcher, caps)
|
||||
.wrn("set_client_matcher_bounding_capabilities")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -3180,6 +3224,42 @@ impl ConfigProxyHandler {
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn update_capabilities(
|
||||
&self,
|
||||
data: &Rc<Client>,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps: bool,
|
||||
) {
|
||||
let mut have_caps = false;
|
||||
let mut have_bounding_caps = false;
|
||||
let mut caps = ClientCaps::none();
|
||||
let mut new_bounding_caps = ClientCaps::none();
|
||||
for (matcher, state) in self.client_matcher_capabilities.lock().values() {
|
||||
if matcher.node.pull(data) {
|
||||
have_caps = true;
|
||||
caps |= *state;
|
||||
}
|
||||
}
|
||||
for (matcher, state) in self.client_matcher_bounding_capabilities.lock().values() {
|
||||
if matcher.node.pull(data) {
|
||||
have_bounding_caps = true;
|
||||
new_bounding_caps |= *state;
|
||||
}
|
||||
}
|
||||
if have_caps {
|
||||
caps &= bounding_caps;
|
||||
data.effective_caps.set(caps);
|
||||
}
|
||||
if !have_bounding_caps && set_bounding_caps {
|
||||
have_bounding_caps = true;
|
||||
new_bounding_caps = data.effective_caps.get();
|
||||
}
|
||||
if have_bounding_caps {
|
||||
new_bounding_caps &= bounding_caps;
|
||||
data.bounding_caps_for_children.set(new_bounding_caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
@ -3281,3 +3361,13 @@ impl WithRequestName for Result<(), CphError> {
|
|||
self.map_err(move |e| CphError::FailedRequest(request, Box::new(e)))
|
||||
}
|
||||
}
|
||||
|
||||
trait ClientCapabilitiesExt {
|
||||
fn to_client_caps(self) -> ClientCaps;
|
||||
}
|
||||
|
||||
impl ClientCapabilitiesExt for ClientCapabilities {
|
||||
fn to_client_caps(self) -> ClientCaps {
|
||||
ClientCaps(self.0 as u32) & !CAP_JAY_COMPOSITOR & ClientCaps::all()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ impl Globals {
|
|||
}
|
||||
|
||||
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
|
||||
let caps = registry.client.effective_caps;
|
||||
let caps = registry.client.effective_caps.get();
|
||||
let xwayland = registry.client.is_xwayland;
|
||||
let globals = self.registry.lock();
|
||||
macro_rules! emit {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,11 @@ 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.effective_caps, self.client.is_xwayland)?;
|
||||
let global = globals.get(
|
||||
name,
|
||||
self.client.effective_caps.get(),
|
||||
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::{CAPS_DEFAULT_SANDBOXED, Client, ClientError},
|
||||
client::{Client, ClientError},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{WpSecurityContextV1Id, wp_security_context_v1::*},
|
||||
|
|
@ -80,7 +80,6 @@ impl WpSecurityContextV1RequestHandler for WpSecurityContextV1 {
|
|||
fn commit(&self, _req: Commit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.check_committed()?;
|
||||
self.committed.set(true);
|
||||
let caps = CAPS_DEFAULT_SANDBOXED & self.client.bounding_caps;
|
||||
self.client.state.security_context_acceptors.spawn(
|
||||
&self.client.state,
|
||||
self.sandbox_engine.take(),
|
||||
|
|
@ -88,7 +87,7 @@ impl WpSecurityContextV1RequestHandler for WpSecurityContextV1 {
|
|||
self.instance_id.take(),
|
||||
&self.listen_fd,
|
||||
&self.close_fd,
|
||||
caps,
|
||||
self.client.bounding_caps_for_children.get(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ struct Acceptor {
|
|||
metadata: Rc<AcceptorMetadata>,
|
||||
listen_fd: Rc<OwnedFd>,
|
||||
close_fd: Rc<OwnedFd>,
|
||||
caps: ClientCaps,
|
||||
bounding_caps: ClientCaps,
|
||||
listen_future: Cell<Option<SpawnedFuture<()>>>,
|
||||
close_future: Cell<Option<SpawnedFuture<()>>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AcceptorMetadata {
|
||||
pub secure: bool,
|
||||
pub sandboxed: bool,
|
||||
pub sandbox_engine: Option<String>,
|
||||
pub app_id: Option<String>,
|
||||
|
|
@ -55,12 +56,13 @@ impl SecurityContextAcceptors {
|
|||
instance_id: Option<String>,
|
||||
listen_fd: &Rc<OwnedFd>,
|
||||
close_fd: &Rc<OwnedFd>,
|
||||
caps: ClientCaps,
|
||||
bounding_caps: ClientCaps,
|
||||
) {
|
||||
let acceptor = Rc::new(Acceptor {
|
||||
id: self.ids.next(),
|
||||
state: state.clone(),
|
||||
metadata: Rc::new(AcceptorMetadata {
|
||||
secure: false,
|
||||
sandboxed: true,
|
||||
sandbox_engine,
|
||||
app_id,
|
||||
|
|
@ -68,7 +70,7 @@ impl SecurityContextAcceptors {
|
|||
}),
|
||||
listen_fd: listen_fd.clone(),
|
||||
close_fd: close_fd.clone(),
|
||||
caps,
|
||||
bounding_caps,
|
||||
listen_future: Cell::new(None),
|
||||
close_future: Cell::new(None),
|
||||
});
|
||||
|
|
@ -111,7 +113,7 @@ impl Acceptor {
|
|||
let id = s.clients.id();
|
||||
if let Err(e) = s
|
||||
.clients
|
||||
.spawn(id, s, fd, self.caps, self.caps, &self.metadata)
|
||||
.spawn(id, s, fd, self.bounding_caps, true, &self.metadata)
|
||||
{
|
||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||
break;
|
||||
|
|
|
|||
13
src/state.rs
13
src/state.rs
|
|
@ -10,7 +10,7 @@ use {
|
|||
},
|
||||
backends::dummy::DummyBackend,
|
||||
cli::RunArgs,
|
||||
client::{Client, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
|
||||
client::{Client, ClientCaps, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
|
||||
clientmem::ClientMemOffset,
|
||||
cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager},
|
||||
compositor::LIBEI_SOCKET,
|
||||
|
|
@ -1541,6 +1541,17 @@ impl State {
|
|||
self.config.get()?.initial_tile_state(data)
|
||||
}
|
||||
|
||||
pub fn update_capabilities(
|
||||
&self,
|
||||
data: &Rc<Client>,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps: bool,
|
||||
) {
|
||||
if let Some(config) = self.config.get() {
|
||||
config.update_capabilities(data, bounding_caps, set_bounding_caps);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_at(&self, x: i32, y: i32) -> FoundNode {
|
||||
let mut found_tree = self.node_at_tree.borrow_mut();
|
||||
found_tree.push(FoundNode {
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ async fn run(
|
|||
uapi::getuid(),
|
||||
pid,
|
||||
ClientCaps::all(),
|
||||
ClientCaps::all(),
|
||||
false,
|
||||
true,
|
||||
&Rc::new(AcceptorMetadata::default()),
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue