- commit
- 345a7f2a5ef179d85f3e6b96a3b1fade58910e90
- parent
- 7735fb5cb73c477e663ef6a43e37cde4e2a62f1c
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2026-03-08 10:34
[OpenURI] only allow to open files that exist under the same path on the host
Diffstat
| M | OpenURI/README.md | 3 | ++- |
| M | OpenURI/open-uri.c | 94 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 96 insertions, 1 deletions
diff --git a/OpenURI/README.md b/OpenURI/README.md
@@ -26,7 +26,8 @@ $ printf "https://example.com" | nc -U "$XDG_RUNTIME_DIR/xi.portal.OpenURI"` 26 26 - How to pass [activation tokens](https://wayland.app/protocols/xdg-activation-v1)? 27 27 - It is not clear how support for `file://` URIs should be implemented. The 28 28 namespace is available at `/proc/{pid}/root/`, but that will go away when29 -1 the calling process exits.-1 29 the calling process exits. The reference implementation currently only -1 30 allows to open files that also exist on the same location on the host. 30 31 31 32 ## Compatibility Considerations 32 33
diff --git a/OpenURI/open-uri.c b/OpenURI/open-uri.c
@@ -1,10 +1,94 @@ -1 1 #define _GNU_SOURCE -1 2 #include <linux/openat2.h> 1 3 #include <stdio.h> -1 4 #include <stdlib.h> -1 5 #include <string.h> -1 6 #include <sys/pidfd.h> -1 7 #include <sys/select.h> 2 8 #include <sys/socket.h> -1 9 #include <sys/stat.h> -1 10 #include <sys/syscall.h> -1 11 #include <unistd.h> -1 12 3 13 #include <gio/gio.h> 4 14 5 15 #define MAX_URI_LENGTH 1024 6 16 #define SOCK 3 7 17 -1 18 int get_pidfd(int sock) { -1 19 int pidfd; -1 20 socklen_t pidfd_len = sizeof(pidfd); -1 21 if (getsockopt(sock, SOL_SOCKET, SO_PEERPIDFD, &pidfd, &pidfd_len) < 0) { -1 22 perror("getsockopt"); -1 23 return -1; -1 24 } -1 25 return pidfd; -1 26 } -1 27 -1 28 int is_readable(int fd) { -1 29 fd_set fds; -1 30 struct timeval timeout; -1 31 -1 32 FD_ZERO(&fds); -1 33 FD_SET(fd, &fds); -1 34 -1 35 timeout.tv_sec = 0; -1 36 timeout.tv_usec = 0; -1 37 -1 38 return select(fd + 1, &fds, NULL, NULL, &timeout); -1 39 } -1 40 -1 41 int stat_at_root(const char *path, const char *root, struct stat *statbuf) { -1 42 struct open_how how = {0}; -1 43 how.flags = O_RDONLY; -1 44 how.resolve = RESOLVE_IN_ROOT; -1 45 -1 46 int root_fd = open(root, O_RDONLY | O_DIRECTORY); -1 47 if (root_fd < 0) { -1 48 perror("open root"); -1 49 return -1; -1 50 } -1 51 -1 52 int fd = syscall(SYS_openat2, root_fd, path, &how, sizeof(how)); -1 53 close(root_fd); -1 54 if (fd < 0) { -1 55 perror("openat"); -1 56 return -1; -1 57 } -1 58 -1 59 if (fstat(fd, statbuf) != 0) { -1 60 perror("fstat"); -1 61 close(fd); -1 62 return -1; -1 63 } -1 64 -1 65 close(fd); -1 66 return 0; -1 67 } -1 68 -1 69 int same_on_host(char *uri, int pidfd) { -1 70 char root_sender[32]; -1 71 struct stat s_sender, s_host; -1 72 -1 73 snprintf( -1 74 root_sender, sizeof(root_sender), "/proc/%i/root/", pidfd_getpid(pidfd) -1 75 ); -1 76 if (stat_at_root(uri + 7, root_sender, &s_sender) != 0) { -1 77 return -1; -1 78 } -1 79 if (stat_at_root(uri + 7, "/", &s_host) != 0) { -1 80 return -1; -1 81 } -1 82 if (s_sender.st_dev != s_host.st_dev || s_sender.st_ino != s_host.st_ino) { -1 83 return -1; -1 84 } -1 85 if (is_readable(pidfd) != 0) { -1 86 return -1; -1 87 } -1 88 -1 89 return 0; -1 90 } -1 91 8 92 int main() { 9 93 char uri[MAX_URI_LENGTH]; 10 94 @@ -16,6 +100,16 @@ int main() { 16 100 uri[n] = '\0'; 17 101 g_strchomp(uri); 18 102 -1 103 if (strncmp(uri, "file://", 7) == 0) { -1 104 int pidfd = get_pidfd(SOCK); -1 105 if (pidfd < 0) { -1 106 return EXIT_FAILURE; -1 107 } -1 108 if (same_on_host(uri, pidfd) != 0) { -1 109 return EXIT_FAILURE; -1 110 } -1 111 } -1 112 19 113 GError *error = NULL; 20 114 if (!g_app_info_launch_default_for_uri(uri, NULL, &error)) { 21 115 send(SOCK, error->message, strlen(error->message), 0);