CVE-2022-26530 (C, published 2022-04-03T23:15Z)
Description: value: swaylock before 1.6 allows attackers to trigger a crash and achieve unlocked access to a Wayland compositor.
Severity: MEDIUM (CVSS v3 base score: 9.1)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/swaywm/swaylock
Files changed:
include/swaylock.h
main.c
meson.build
Commit message: Add support for ext-session-lock-v1

This is a new protocol to lock the session [1]. It should be more
reliable than layer-shell + input-inhibitor.

[1]: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/131


Vulnerable code:
static void create_layer_surface(struct swaylock_surface *surface) {
	surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
			state->layer_shell, surface->surface, surface->output,
			ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
	assert(surface->layer_surface);

	zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
	zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
			ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
			ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
			ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
			ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
	zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1);
	zwlr_layer_surface_v1_set_keyboard_interactivity(
			surface->layer_surface, true);
	zwlr_layer_surface_v1_add_listener(surface->layer_surface,
			&layer_surface_listener, surface);
	wl_surface_commit(surface->surface);
			create_layer_surface(surface);
	assert(state.compositor && state.layer_shell && state.shm);
	if (!state.input_inhibit_manager) {
		free(state.args.font);
		swaylock_log(LOG_ERROR, "Compositor does not support the input "
				"inhibitor protocol, refusing to run insecurely");
	zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
		swaylock_log(LOG_ERROR, "Exiting - failed to inhibit input:"
				" is another lockscreen already running?");
		return 2;
		create_layer_surface(surface);
wayland_protos = dependency('wayland-protocols', version: '>=1.14', fallback: 'wayland-protocols')

Fixed code:
	struct ext_session_lock_manager_v1 *ext_session_lock_manager_v1;
	struct ext_session_lock_v1 *ext_session_lock_v1;
	struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1;
#include "ext-session-lock-v1-client-protocol.h"
	if (surface->ext_session_lock_surface_v1 != NULL) {
		ext_session_lock_surface_v1_destroy(surface->ext_session_lock_surface_v1);
	}
static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener;
static void create_surface(struct swaylock_surface *surface) {
	if (state->ext_session_lock_v1) {
		surface->ext_session_lock_surface_v1 = ext_session_lock_v1_get_lock_surface(
				state->ext_session_lock_v1, surface->surface, surface->output);
		ext_session_lock_surface_v1_add_listener(surface->ext_session_lock_surface_v1,
				&ext_session_lock_surface_v1_listener, surface);
	} else {
		surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
				state->layer_shell, surface->surface, surface->output,
				ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");

		zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
		zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
				ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
				ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
		zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1);
		zwlr_layer_surface_v1_set_keyboard_interactivity(
				surface->layer_surface, true);
		zwlr_layer_surface_v1_add_listener(surface->layer_surface,
				&layer_surface_listener, surface);
	}
	if (!state->ext_session_lock_v1) {
		wl_surface_commit(surface->surface);
	}
static void ext_session_lock_surface_v1_handle_configure(void *data,
		struct ext_session_lock_surface_v1 *lock_surface, uint32_t serial,
		uint32_t width, uint32_t height) {
	struct swaylock_surface *surface = data;
	surface->width = width;
	surface->height = height;
	surface->indicator_width = 0;
	surface->indicator_height = 0;
	ext_session_lock_surface_v1_ack_configure(lock_surface, serial);
	render_frame_background(surface);
	render_frame(surface);
}

static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener = {
	.configure = ext_session_lock_surface_v1_handle_configure,
};

static void ext_session_lock_v1_handle_locked(void *data, struct ext_session_lock_v1 *lock) {
	// Who cares
}

static void ext_session_lock_v1_handle_finished(void *data, struct ext_session_lock_v1 *lock) {
	swaylock_log(LOG_ERROR, "Failed to lock session -- "
			"is another lockscreen running?");
	exit(2);
}

static const struct ext_session_lock_v1_listener ext_session_lock_v1_listener = {
	.locked = ext_session_lock_v1_handle_locked,
	.finished = ext_session_lock_v1_handle_finished,
};

			create_surface(surface);
	} else if (strcmp(interface, ext_session_lock_manager_v1_interface.name) == 0) {
		state->ext_session_lock_manager_v1 = wl_registry_bind(registry, name,
				&ext_session_lock_manager_v1_interface, 1);

	if (!state.compositor || !state.shm) {
		swaylock_log(LOG_ERROR, "Missing wl_compositor or wl_shm");
		return 1;
	}

	if (state.ext_session_lock_manager_v1) {
		swaylock_log(LOG_DEBUG, "Using ext-session-lock-v1");
		state.ext_session_lock_v1 = ext_session_lock_manager_v1_lock(state.ext_session_lock_manager_v1);
		ext_session_lock_v1_add_listener(state.ext_session_lock_v1,
				&ext_session_lock_v1_listener, &state);
	} else if (state.layer_shell && state.input_inhibit_manager) {
		swaylock_log(LOG_DEBUG, "Using wlr-layer-shell + wlr-input-inhibitor");
		zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
	} else {
		swaylock_log(LOG_ERROR, "Missing ext-session-lock-v1, wlr-layer-shell "
				"and wlr-input-inhibitor");
		if (state.input_inhibit_manager) {
			swaylock_log(LOG_ERROR, "Exiting - failed to inhibit input:"
					" is another lockscreen already running?");
			return 2;
		}
		return 1;
		create_surface(surface);
	if (state.ext_session_lock_v1) {
		ext_session_lock_v1_unlock_and_destroy(state.ext_session_lock_v1);
		wl_display_flush(state.display);
	}

wayland_protos = dependency('wayland-protocols', version: '>=1.25', fallback: 'wayland-protocols')
	[wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'],