The brei_demarshal() function parses incoming protocol messages based on
a type signature. While the 's' (string) type had proper bounds checking
against the remaining buffer, the other types didn't.
A malicious client could send a message with a truncated payload (small
msglen in the header) but targeting an opcode whose signature expects
more data than provided. This would cause buffer over-reads past the
allocated buffer, potentially leaking sensitive memory contents or
causing a crash.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/389>
We really rely on assert all over the place, removing that is likely
going to result in interesting outcomes when unexpected failures happen.
Putting this into brei because it's a header used by both libei/libeis.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
Add a 1MiB maximum and make sure our message length
is at least the header size - without that we get an underflow, causing
iobuf_pop to remove a huge number of bytes, crashing the other end.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
Depending on the umask our socket may be group/world-accessible, let's
not do that because if the current state of the world tells us anything
it is that we can't trust it.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
Repeatedly using strcat means we rescan the string, making it O(n^2).
Use memcpy and an offset instead because we can't affort to waste
nanoseconds here.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
Unceremoneously close any fds that the client gives us that exceed our
expectations (which right now is a max of 32 for a protocol-valid max
of... 1).
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
Our current maximum of fds per the protocol is exactly 1 so this has
no effect but might save us in the future from some naughty client.
Meanwhile, this prevents us from having a variable-length array on the
stack that is caller-controller.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
The check `(long)v < 0` only catches values >= LONG_MAX when cast to
signed long. On 64-bit systems where sizeof(long) == 8, values between
UINT_MAX+1 and LONG_MAX pass this check but silently truncate when
assigned to the unsigned int output parameter. Use `v > UINT_MAX` for
a correct range check.
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
Might as well blow up when allocation fails, not that this ever happens.
And in the case of cmdline_as_str() this now also means we definitely
have to free the result (we did before but well, there was the
theoretical case of it failling).
Assisted-by: Claude:claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
The protocol test we had was broken, it would assume that any interface
we send was present instead of only taking the ones the server replied
with. Fix this so this triggers next time.
Fixes: 1f9be0fd0a ("Add a new text interface for sending keysyms and utf8 text")
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/387>
On the protocol level these are implemented as three separate interfaces
for swipe, pinch and hold, each interface has the begin/update/end
sequence and effectively matches the wayland pointer-gestures protocol.
Notably, only one of each gesture may be active at any time though the
protocol allows for separate gestures to be active (i.e. swipe while
pinching).
On the library side the gestures match the touch interface so the
sequence for a sender is:
swipe = ei_device_new_swipe(device, finger_count);
ei_swipe_begin(swipe);
ei_swipe_update(swipe, dx, dy);
ei_swipe_end(swipe);
with the corresponding APIs for pinch and hold.
On the receiver side the event types are separated for BEGIN/UPDATE/END
for all three gestures and thus match the libinput interface.
The notable difference however: there is only one CAP_GESTURES (similar
to libinput) and it is set if any gesture is available on the caller.
Creating a swipe gesture if the remote end does not support it will
return NULL though.
Co-Authored-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/309>
The text capability allows for two types of events on that interface:
- XKB keysym events, e.g. XK_ssharp (0x00df) with a press/release state
- UTF8 strings
Keysym events are useful for scenarious where the hardware keycode is
unsuitable due to potentially different key mappings on the client and
server side and/or the client just not wanting to worry about those
mappings. For example a client may want to send Ctrl+C instead of
what effectively is now keycodes for what may or may not be a C key.
UTF8 strings take this a step further and provide a full string (with
implementation-defined size limits to avoid OOM). Unlike e.g. the
wayland text input protocols the assumption is here that the
interaction required to generate that string has already been
performed before the final string is sent over the wire.
Closes#73
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/355>
clang-format taken from libinput, except for
ColumnLimit: 100
and some macro definitions (which don't all have an effect anyway...)
It's not perfect but good enough and at least consistent.
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/383>
For both ei/eis a missing return after the scroll capability check could
cause a potential NULL pointer dereference on device->scroll.
Co-Authored-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/382>
This situation cannot happen in a normal protocol conversation, the only
message that transports an fd (ei_keyboard.keymap) has one single fd and
(32 + 1 * sizeof(int)) is large enough on the platforms that matters.
fd transport is always EIS to ei, so a long as EIS is trusted enough,
this is not a security issue that matters.
Found-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/380>
This should've been specified from day one but better late than never.
Since stop_emulating is supposed to signal termination of a client
emulating input, a logical assumption is that the device is set back to
neutral. Let's point it out that the real behavior is within EIS but
clients should behave predictably.
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/368>
Even if the client is no longer emulating (and we're not queuing an
event) our local touch must be ended. Otherwise our touch will live on
forever, despite the client thinking it has ended properly.
This can't be triggered with libei because we can't send touch events
while not emulating and the only way to get into this state is pausing
the device - which already resets the state. But let's add a test case
anyway, in the hope that one day it picks up a bug.
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/368>
A client sending duplicate touch IDs will be disconnected but
motion or end events for touches that no longer exist will be silently
ignored.
The tracking state uses a uint64_t to store currently valid touch ids -
since the whole range of touch ids are uint32_t (including zero) this is
the simple way of using an out-of-range marker value (UINT64_MAX)
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/368>
This is a behavior break if we're looking at the documentation only but
the protocol has required the logical reset of the device since libei
0.5 - this here is just stale documentation that didn't get updated.
And keeping the state across paused/resume is too hard to get right
anyway.
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/368>
Add support for a client to request the creation of a new device
from the EIS implementation. This is necessary in situations where the
devices created by the EIS implementation are not (or no longer)
suitable for the client to function correctly.
The primary use-case of this is the upcoming tablet tool support where a
client may need to create multiple tablet tools in response to a new
physical tool brought into proximity locally.
Other use-cases include a client closing a device but requiring that
device (or one with similar capabilities) later.
The implementation in libei is straightforward
- on the client side we have a new function to request the new device:
ei_seat_request_device_with_capabilities()
- on the server side we have a new event EIS_EVENT_SEAT_DEVICE_REQUESTED
that can make use of the existing eis_event_seat_has_capability() API
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/345>