From 7dcf3a68cc8027bfa0d865e8a33566b4ae431618 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 9 Apr 2023 16:06:39 +0200 Subject: Use /usr/bin/gsr-kms-server constant path for pkexec --- include/capture/kms_vaapi.h | 1 - kms/client/kms_client.c | 65 ++++++++++++++++++++++++--------------------- kms/client/kms_client.h | 2 +- src/capture/kms_vaapi.c | 2 +- src/main.cpp | 8 ------ 5 files changed, 37 insertions(+), 41 deletions(-) diff --git a/include/capture/kms_vaapi.h b/include/capture/kms_vaapi.h index 5cf8606..ba5763b 100644 --- a/include/capture/kms_vaapi.h +++ b/include/capture/kms_vaapi.h @@ -10,7 +10,6 @@ typedef struct _XDisplay Display; typedef struct { Display *dpy; const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */ - const char *program_dir; /* ref */ } gsr_capture_kms_vaapi_params; gsr_capture* gsr_capture_kms_vaapi_create(const gsr_capture_kms_vaapi_params *params); diff --git a/kms/client/kms_client.c b/kms/client/kms_client.c index 2b59836..6730318 100644 --- a/kms/client/kms_client.c +++ b/kms/client/kms_client.c @@ -63,7 +63,7 @@ static int recv_msg_from_server(int server_fd, gsr_kms_response *response) { return res; } -int gsr_kms_client_init(gsr_kms_client *self, const char *card_path, const char *program_dir) { +int gsr_kms_client_init(gsr_kms_client *self, const char *card_path) { self->kms_server_pid = -1; self->card_path = NULL; self->socket_fd = -1; @@ -72,37 +72,42 @@ int gsr_kms_client_init(gsr_kms_client *self, const char *card_path, const char struct sockaddr_un local_addr = {0}; struct sockaddr_un remote_addr = {0}; + // This doesn't work on nixos, but we dont want to use $PATH because we want to make this as safe as possible by running pkexec + // on a path that only root can modify. If we use "gsr-kms-server" instead then $PATH can be modified in ~/.bashrc for example + // which will overwrite the path to gsr-kms-server and the user can end up running a malicious program that pretends to be gsr-kms-server. + // If there is a safe way to do this on nixos, then please tell me; or use gpu-screen-recorder flatpak instead. + const char *server_filepath = "/usr/bin/gsr-kms-server"; + bool has_perm = 0; bool inside_flatpak = is_inside_flatpak(); - char server_filepath[PATH_MAX]; - snprintf(server_filepath, sizeof(server_filepath), "%s/%s", program_dir, "gsr-kms-server"); - if(access(server_filepath, F_OK) != 0 || inside_flatpak) - snprintf(server_filepath, sizeof(server_filepath), "gsr-kms-server"); // Assume gsr-kms-server is in $PATH + if(!inside_flatpak) { + if(access("/usr/bin/gsr-kms-server", F_OK) != 0) { + fprintf(stderr, "gsr error: gsr_kms_client_init: /usr/bin/gsr-kms-server not found, please install gpu-screen-recorder first\n"); + return -1; + } - bool has_perm = 0; - if(geteuid() == 0) { - has_perm = true; - } else { - cap_t kms_server_cap = cap_get_file(server_filepath); - if(kms_server_cap) { - cap_flag_value_t res = 0; - cap_get_flag(kms_server_cap, CAP_SYS_ADMIN, CAP_PERMITTED, &res); - if(res == CAP_SET) { - //fprintf(stderr, "has permission!\n"); - has_perm = true; + if(geteuid() == 0) { + has_perm = true; + } else { + cap_t kms_server_cap = cap_get_file(server_filepath); + if(kms_server_cap) { + cap_flag_value_t res = 0; + cap_get_flag(kms_server_cap, CAP_SYS_ADMIN, CAP_PERMITTED, &res); + if(res == CAP_SET) { + //fprintf(stderr, "has permission!\n"); + has_perm = true; + } else { + //fprintf(stderr, "No permission:(\n"); + } + cap_free(kms_server_cap); } else { - //fprintf(stderr, "No permission:(\n"); + if(errno == ENODATA) + fprintf(stderr, "gsr info: gsr_kms_client_init: gsr-kms-server is missing sys_admin cap and will require root authentication. To bypass this automatically, run: sudo setcap cap_sys_admin+ep '%s'\n", server_filepath); + else + fprintf(stderr, "gsr info: gsr_kms_client_init: failed to get cap\n"); } - cap_free(kms_server_cap); - } else { - if(errno == ENODATA) - fprintf(stderr, "gsr info: gsr_kms_client_init: gsr-kms-server is missing sys_admin cap and will require root authentication. To bypass this automatically, run: sudo setcap cap_sys_admin+ep '%s'\n", server_filepath); - else - fprintf(stderr, "gsr info: gsr_kms_client_init: failed to get cap\n"); } } - fprintf(stderr, "gsr info: gsr server path: %s, exists: %s\n", server_filepath, access(server_filepath, F_OK) == 0 ? "yes" : "no"); - self->card_path = strdup(card_path); if(!self->card_path) { fprintf(stderr, "gsr error: gsr_kms_client_init: failed to duplicate card_path\n"); @@ -138,17 +143,17 @@ int gsr_kms_client_init(gsr_kms_client *self, const char *card_path, const char fprintf(stderr, "gsr error: gsr_kms_client_init: fork failed, error: %s\n", strerror(errno)); goto err; } else if(pid == 0) { /* child */ - if(has_perm) { - const char *args[] = { server_filepath, self->socket_path, NULL }; + if(inside_flatpak) { + const char *args[] = { "flatpak-spawn", "--host", "pkexec", "flatpak", "run", "--command=gsr-kms-server", "com.dec05eba.gpu_screen_recorder", self->socket_path, NULL }; execvp(args[0], (char *const*)args); - } else if(inside_flatpak) { - const char *args[] = { "flatpak-spawn", "--host", "pkexec", server_filepath, self->socket_path, NULL }; + } else if(has_perm) { + const char *args[] = { server_filepath, self->socket_path, NULL }; execvp(args[0], (char *const*)args); } else { const char *args[] = { "pkexec", server_filepath, self->socket_path, NULL }; execvp(args[0], (char *const*)args); } - perror("execvp"); + fprintf(stderr, "gsr error: gsr_kms_client_init: execvp failed, error: %s\n", strerror(errno)); _exit(127); } else { /* parent */ self->kms_server_pid = pid; diff --git a/kms/client/kms_client.h b/kms/client/kms_client.h index 59d3cb3..a15d869 100644 --- a/kms/client/kms_client.h +++ b/kms/client/kms_client.h @@ -13,7 +13,7 @@ typedef struct { } gsr_kms_client; /* |card_path| should be a path to card, for example /dev/dri/card0 */ -int gsr_kms_client_init(gsr_kms_client *self, const char *card_path, const char *program_dir); +int gsr_kms_client_init(gsr_kms_client *self, const char *card_path); void gsr_kms_client_deinit(gsr_kms_client *self); int gsr_kms_client_get_kms(gsr_kms_client *self, gsr_kms_response *response); diff --git a/src/capture/kms_vaapi.c b/src/capture/kms_vaapi.c index 2e970a3..a369765 100644 --- a/src/capture/kms_vaapi.c +++ b/src/capture/kms_vaapi.c @@ -98,7 +98,7 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c gsr_capture_kms_vaapi *cap_kms = cap->priv; // TODO: Allow specifying another card, and in other places (TODO: Use /dev/dri/renderD128?) - if(gsr_kms_client_init(&cap_kms->kms_client, "/dev/dri/card0", cap_kms->params.program_dir) != 0) { + if(gsr_kms_client_init(&cap_kms->kms_client, "/dev/dri/card0") != 0) { return -1; } diff --git a/src/main.cpp b/src/main.cpp index 9e4ae4e..489f800 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,8 +19,6 @@ extern "C" { #include #include -#include - #include "../include/sound.hpp" extern "C" { @@ -1111,11 +1109,6 @@ int main(int argc, char **argv) { if(argc == 0) usage(); - char *program_dir = dirname(argv[0]); - char program_dir_full[PATH_MAX]; - program_dir_full[0] = '\0'; - realpath(program_dir, program_dir_full); - //av_log_set_level(AV_LOG_TRACE); std::map args = { @@ -1397,7 +1390,6 @@ int main(int argc, char **argv) { gsr_capture_kms_vaapi_params kms_params; kms_params.dpy = dpy; kms_params.display_to_capture = capture_target; - kms_params.program_dir = program_dir_full; capture = gsr_capture_kms_vaapi_create(&kms_params); if(!capture) return 1; -- cgit v1.2.3