Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 78 additions & 11 deletions src/sendkeys/sendkeys.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,99 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>

#include "utils/log.h"

static void usage(void)
{
printf("Usage: sendkeys [--sdl] [[CODE] [VALUE], ...]\n"
"Values: 0 - released, 1 - pressed, 2 - repeating\n");
}

static int parse_integer(const char *text, int minimum, int maximum, int *value)
{
if (text == NULL || *text == '\0' || value == NULL)
return -1;
char *end = NULL;
long parsed = strtol(text, &end, 10);
if (*end != '\0' || parsed < minimum || parsed > maximum)
return -1;
*value = (int)parsed;
return 0;
}

static int developer_mode_enabled(void)
{
struct stat metadata;
return lstat("/mnt/SDCARD/.bloom-dev", &metadata) == 0 &&
S_ISREG(metadata.st_mode) && !S_ISLNK(metadata.st_mode);
}

static int inject_sdl_console(const struct input_event *events, int num_events)
{
if (!developer_mode_enabled())
return 1;
struct stat metadata;
if (lstat("/dev/tty2", &metadata) != 0 || !S_ISCHR(metadata.st_mode) ||
S_ISLNK(metadata.st_mode))
return 1;
int input_fd =
open("/dev/tty2", O_WRONLY | O_NOCTTY | O_CLOEXEC | O_NOFOLLOW);
if (input_fd < 0)
return 1;
for (int index = 0; index < num_events; ++index) {
if (events[index].code > 127 || events[index].value > 1) {
close(input_fd);
return 1;
}
unsigned char scan_code = (unsigned char)events[index].code;
if (events[index].value == 0)
scan_code |= 0x80;
if (ioctl(input_fd, TIOCSTI, &scan_code) != 0) {
close(input_fd);
return 1;
}
}
return close(input_fd) == 0 ? 0 : 1;
}

int main(int argc, char *argv[])
{
struct input_event events[100];

if (argc < 3 || argc % 2 == 0 || argc > 201) {
printf("Usage: sendkeys [[CODE] [VALUE], ...]\nValues: 0 - released, 1 "
"- pressed, 2 - repeating\n");
int first_argument = 1;
int sdl_console = argc > 1 && strcmp(argv[1], "--sdl") == 0;
if (sdl_console)
first_argument++;
int argument_count = argc - first_argument;
if (argument_count < 2 || argument_count % 2 != 0 || argument_count > 200) {
usage();
return 1;
}

int num_events = (argc - 1) / 2;
int num_events = argument_count / 2;
memset(events, 0, sizeof(events));

for (int i = 1; i < argc; i += 2) {
int ev_idx = (i - 1) / 2;
for (int i = first_argument; i < argc; i += 2) {
int ev_idx = (i - first_argument) / 2;
events[ev_idx].type = EV_KEY;
events[ev_idx].code = atoi(argv[i]);
events[ev_idx].value = atoi(argv[i + 1]);
int code = 0;
int value = 0;
if (parse_integer(argv[i], 0, sdl_console ? 127 : KEY_MAX, &code) != 0 ||
parse_integer(argv[i + 1], 0, sdl_console ? 1 : 2, &value) != 0) {
usage();
return 1;
}
events[ev_idx].code = (__u16)code;
events[ev_idx].value = value;
}

int input_fd;
input_fd = open("/dev/input/event0", O_WRONLY);
if (sdl_console)
return inject_sdl_console(events, num_events);

int input_fd = open("/dev/input/event0", O_WRONLY | O_CLOEXEC);
if (input_fd < 0)
return 1;

Expand Down
22 changes: 22 additions & 0 deletions test/shell/sendkeys_contract.bats
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,25 @@
grep -F 'write(input_fd, &sync_event, sizeof(sync_event)) != sizeof(sync_event)' "$source_file"
grep -F 'if (input_fd < 0)' "$source_file"
}

@test "developer SDL injection is explicit bounded and console-scoped" {
source_file=/workspace/src/sendkeys/sendkeys.c

grep -F 'strcmp(argv[1], "--sdl") == 0' "$source_file"
grep -F 'lstat("/mnt/SDCARD/.bloom-dev", &metadata)' "$source_file"
grep -F 'S_ISREG(metadata.st_mode) && !S_ISLNK(metadata.st_mode)' "$source_file"
grep -F 'lstat("/dev/tty2", &metadata) != 0 || !S_ISCHR(metadata.st_mode)' "$source_file"
grep -F 'open("/dev/tty2", O_WRONLY | O_NOCTTY | O_CLOEXEC | O_NOFOLLOW)' "$source_file"
grep -F 'events[index].code > 127 || events[index].value > 1' "$source_file"
grep -F 'scan_code |= 0x80;' "$source_file"
grep -F 'ioctl(input_fd, TIOCSTI, &scan_code) != 0' "$source_file"
}

@test "hardware input helper rejects nonnumeric and out of range values" {
source_file=/workspace/src/sendkeys/sendkeys.c

grep -F 'strtol(text, &end, 10)' "$source_file"
grep -F "*end != '\\0' || parsed < minimum || parsed > maximum" "$source_file"
grep -F 'parse_integer(argv[i], 0, sdl_console ? 127 : KEY_MAX, &code)' "$source_file"
grep -F 'parse_integer(argv[i + 1], 0, sdl_console ? 1 : 2, &value)' "$source_file"
}
5 changes: 5 additions & 0 deletions test/test_ci_scope.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ expect "src/common/utils/sdl_direct_fb.h src/bootScreen src/gameSwitcher src/inf
expect "src/common/theme src/bootScreen src/gameSwitcher src/infoPanel src/keymon src/mainUiBatPerc src/prompt src/themeSwitcher src/tweaks" static-analysis "src/common/theme/config.h"
expect "src/bootScreen src/chargingState" static-analysis "src/bootScreen/bootScreen.c
src/chargingState/chargingState.c"
expect "sendkeys" build "src/sendkeys/sendkeys.c"
expect "src/sendkeys" static-analysis "src/sendkeys/sendkeys.c"
expect "full" build "src/common/system/display.h"
expect "full" static-analysis "src/common/system/display.h"
expect "bloomShell gameSwitcher" build "src/bloomShell/bloom_shell_settings.h"
Expand Down Expand Up @@ -151,6 +153,9 @@ expect "2" risk "build/libretro-artwork-policy.json
tools/validate_libretro_artwork_policy.py"
expect "full" native-tests "src/common/system/display.h"
expect "none" native-tests "docs/ARCHITECTURE.md"
expect "2" risk "src/sendkeys/sendkeys.c"
expect "none" native-tests "src/sendkeys/sendkeys.c"
expect "/workspace/test/shell/sendkeys_contract.bats" shell-tests "src/sendkeys/sendkeys.c"
expect "BloomUiRenderer*" visual-tests "src/bloomUi/bloom_ui_renderer.c"
expect "BloomUi*" native-tests "test/test_bloom_ui_components.cpp"
expect "BloomUiRenderer*" visual-tests "test/test_bloom_ui_components.cpp"
Expand Down
7 changes: 6 additions & 1 deletion tools/ci-scope.sh
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ while IFS= read -r path; do
fi
;;
src/bootScreen/*|src/chargingState/*|src/installUI/*|src/mainUiBatPerc/*|src/prompt/*|\
src/themeSwitcher/*|src/tweaks/*)
src/sendkeys/*|src/themeSwitcher/*|src/tweaks/*)
component=$(printf '%s\n' "$path" | cut -d/ -f2)
if [ "$mode" = build ]; then
add_target "$component"
Expand Down Expand Up @@ -537,6 +537,11 @@ while IFS= read -r path; do
add_native_filter 'GameSwitcher*'
add_native_filter 'test_infoPanel*'
;;
src/sendkeys/*)
raise_risk 2
native_none=1
add_shell_target /workspace/test/shell/sendkeys_contract.bats
;;
tools/bloom-device|tools/dev-deploy-manifest.py)
raise_risk 2
add_shell_target /workspace/test/shell/bloom_device.bats
Expand Down
Loading