Skip to content

Commit c03c264

Browse files
committed
fix: harden host tool argument handling
1 parent e601ead commit c03c264

9 files changed

Lines changed: 358 additions & 154 deletions

File tree

.github/workflows/build.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
2+
# SPDX-License-Identifier: GPL-3.0-or-later
3+
14
name: Build Amiberry Host Tools
25

36
on:
@@ -17,7 +20,7 @@ permissions:
1720
jobs:
1821
build:
1922
runs-on: ubuntu-latest
20-
container: amigadev/crosstools:m68k-amigaos
23+
container: sacredbanana/amiga-compiler:m68k-amigaos
2124

2225
steps:
2326
- name: Checkout repository

.gitignore

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,75 @@
1-
# Prerequisites
2-
*.d
1+
# SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
2+
# SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
# Host OS metadata
5+
.DS_Store
6+
Thumbs.db
7+
Desktop.ini
8+
9+
# Editor and local workspace state
10+
*~
11+
*.swp
12+
*.swo
13+
.idea/
14+
.vscode/
315

4-
# Object files
16+
# Local build directories and metadata
17+
build/
18+
dist/
19+
release/
20+
tmp/
21+
.cache/
22+
compile_commands.json
23+
24+
# Compiler intermediates
25+
*.d
526
*.o
6-
*.ko
727
*.obj
8-
*.elf
28+
*.lo
29+
*.ko
30+
*.gch
31+
*.pch
32+
*.lst
933

10-
# Linker output
34+
# Linker and debug output
35+
*.elf
36+
*.exp
37+
*.hex
1138
*.ilk
1239
*.map
13-
*.exp
14-
15-
# Precompiled Headers
16-
*.gch
17-
*.pch
40+
*.pdb
41+
*.su
42+
*.sym
43+
*.debug
44+
*.dSYM/
1845

19-
# Libraries
20-
*.lib
46+
# Libraries and host shared objects
2147
*.a
2248
*.la
23-
*.lo
24-
25-
# Shared objects (inc. Windows DLLs)
49+
*.lib
2650
*.dll
51+
*.dylib
2752
*.so
2853
*.so.*
29-
*.dylib
3054

31-
# Executables
55+
# Host executables
56+
*.app
3257
*.exe
3358
*.out
34-
*.app
3559
*.i*86
3660
*.x86_64
37-
*.hex
38-
39-
# Debug files
40-
*.dSYM/
41-
*.su
42-
*.idb
43-
*.pdb
4461

45-
# Kernel Module Compile Results
46-
*.mod*
47-
*.cmd
48-
.tmp_versions/
49-
modules.order
50-
Module.symvers
51-
Mkfile.old
52-
dkms.conf
62+
# Release packages and Amiga archives
63+
*.lha
64+
*.lzh
65+
*.zip
66+
*.tar
67+
*.tar.gz
68+
*.tgz
69+
*.tar.bz2
70+
*.tar.xz
5371

54-
# Amiberry Host Tools
72+
# Amiberry Host Tools binaries
5573
host-run
5674
host-shell
5775
host-multiview

Makefile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
1+
# SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
2+
# SPDX-License-Identifier: GPL-3.0-or-later
3+
14
# m68k-amigaos-gcc -Isrc -noixemul -fomit-frame-pointer -Os -std=c99 -o host-run src/host-run.c
25
all: host-run host-multiview host-shell
36

47
VERSION = 2.0
58
DATE = 2026-04-13
69

10+
ifeq ($(origin CC),default)
711
CC = m68k-amigaos-gcc
12+
endif
813
INCLUDES = -Isrc
914
CFLAGS = -mcpu=68020 -noixemul -Os -fomit-frame-pointer -std=c99 -Wall -Wextra
1015
VERFLAGS = -DVERSION_STR="\"$(VERSION)\"" -DDATE_STR="\"$(DATE)\""
1116

12-
host-run: src/host-run.c
17+
host-run: src/host-run.c src/host_common.h src/uae_pragmas.h
1318
$(CC) $(CFLAGS) $(VERFLAGS) $(INCLUDES) src/host-run.c -o $@
1419

15-
host-multiview: src/host-multiview.c
20+
host-multiview: src/host-multiview.c src/host_common.h src/uae_pragmas.h
1621
$(CC) $(CFLAGS) $(VERFLAGS) $(INCLUDES) src/host-multiview.c -o $@
1722

18-
host-shell: src/host-shell.c
23+
host-shell: src/host-shell.c src/host_common.h src/uae_pragmas.h
1924
$(CC) $(CFLAGS) $(VERFLAGS) $(INCLUDES) src/host-shell.c -o $@
2025

2126
debug: CFLAGS += -DDEBUG -g

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
3+
SPDX-License-Identifier: GPL-3.0-or-later
4+
-->
5+
16
# Amiberry Host Tools
27

38
A collection of AmigaOS tools designed to bridge the gap between the Amiberry emulator and the host operating system (Linux, macOS, etc.).
@@ -84,17 +89,24 @@ Make AmigaOS automatically open `.mkv` files on the host:
8489

8590
## Building
8691

87-
This project is built using **GitHub Actions**. Every push to `master` or a version tag triggers a build using the `amigadev/crosstools:m68k-amigaos` Docker image.
92+
This project is built using **GitHub Actions**. Every push to `master` or a version tag triggers a build using the `sacredbanana/amiga-compiler:m68k-amigaos` Docker image.
8893

8994
To build locally (requires the m68k-amigaos cross-compiler):
9095
```shell
9196
make all
9297
```
9398

99+
To build locally with the same Docker image used by CI:
100+
```shell
101+
docker run --rm -v "$PWD":/work -w /work sacredbanana/amiga-compiler:m68k-amigaos make all
102+
```
103+
94104
To build with debug output enabled:
95105
```shell
96106
make debug
97107
```
98108

99109
## License
100-
GPLv3
110+
Copyright (C) 2020-2026 Dimitris Panokostas.
111+
112+
Amiberry Host Tools is licensed under the GNU General Public License version 3 or later. See [LICENSE](LICENSE) for details.

src/host-multiview.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
16
#include <stdio.h>
27
#include <string.h>
38
#include <stdlib.h>
9+
#include "host_common.h"
410
#include "uae_pragmas.h"
511

612
static const char version[] = "$VER: Host-MultiView v" VERSION_STR " (" DATE_STR ")";
@@ -16,7 +22,8 @@ int print_usage()
1622
int main(int argc, char *argv[])
1723
{
1824
BPTR lock;
19-
char filename[1024];
25+
char filename[HOST_MAX_PATH_LEN];
26+
int status = 0;
2027

2128
if (!InitUAEResource())
2229
{
@@ -40,21 +47,37 @@ int main(int argc, char *argv[])
4047
{
4148
char *target = argv[i];
4249

50+
if (argv[i][0] == '\0') {
51+
printf("Empty filename or URL argument\n");
52+
status = HOST_RETURN_ERROR;
53+
continue;
54+
}
55+
4356
/* Try to resolve as a file path first to get the host path (skip URLs) */
44-
if (!strstr(argv[i], "://") && ((lock = Lock(argv[i], ACCESS_READ))))
57+
if (!host_is_uri(argv[i]) && ((lock = Lock((STRPTR)argv[i], ACCESS_READ))))
4558
{
59+
filename[0] = '\0';
60+
filename[sizeof(filename) - 1] = '\0';
4661
if (NativeDosOp(0, (ULONG)lock, (ULONG)filename, sizeof(filename)) == 0) {
4762
UnLock(lock);
63+
if (host_filled_buffer(filename, sizeof(filename))) {
64+
printf("Resolved host path is too long: %s\n", argv[i]);
65+
status = HOST_RETURN_ERROR;
66+
continue;
67+
}
4868
target = filename;
4969
} else {
5070
UnLock(lock);
5171
}
5272
}
5373

5474
/* Send the request to Amiberry */
55-
/* Opcode 94 handles the quoting and OS-specific command (open/xdg-open) */
56-
HostShell_View((UBYTE *)target);
75+
/* Opcode 89 handles the quoting and OS-specific command (open/xdg-open) */
76+
if (!HostShell_View((UBYTE *)target)) {
77+
printf("Failed to open on host: %s\n", argv[i]);
78+
status = HOST_RETURN_ERROR;
79+
}
5780
}
5881

59-
return 0;
60-
}
82+
return status;
83+
}

src/host-run.c

Lines changed: 25 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
16
#include <stdio.h>
27
#include <string.h>
38
#include <stdlib.h>
9+
#include "host_common.h"
410
#include "uae_pragmas.h"
511

612
static const char version[] = "$VER: Host-Run v" VERSION_STR " (" DATE_STR ")";
713

8-
#define MAX_CMD_LEN 4096
9-
1014
int print_usage()
1115
{
1216
printf("Host-Run v%s\n", VERSION_STR);
@@ -15,58 +19,11 @@ int print_usage()
1519
return 0;
1620
}
1721

18-
// Check if a character is safe for shell (no quoting needed)
19-
int is_safe_char(char c) {
20-
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') ||
21-
c == '.' || c == '_' || c == '-' || c == '/' || c == ':' || c == '+' || c == '=' || c == ',' || c == '@';
22-
}
23-
24-
// Append a string to the buffer, quoting it if necessary
25-
void append_quoted(char *dest, const char *src, size_t max_len) {
26-
size_t current_len = strlen(dest);
27-
if (current_len >= max_len - 1) return;
28-
29-
int needs_quote = 0;
30-
for (const char *p = src; *p; p++) {
31-
if (!is_safe_char(*p)) {
32-
needs_quote = 1;
33-
break;
34-
}
35-
}
36-
37-
// Ensure we have space for opening quote
38-
if (needs_quote) {
39-
if (current_len < max_len - 1) dest[current_len++] = '\'';
40-
dest[current_len] = '\0';
41-
}
42-
43-
for (const char *p = src; *p; p++) {
44-
if (*p == '\'') {
45-
// Escape single quote: ' -> '\''
46-
if (current_len + 4 >= max_len) break;
47-
dest[current_len++] = '\'';
48-
dest[current_len++] = '\\';
49-
dest[current_len++] = '\'';
50-
dest[current_len++] = '\'';
51-
} else {
52-
if (current_len + 1 >= max_len - 1) break; // Reserve space for close quote + null
53-
dest[current_len++] = *p;
54-
}
55-
}
56-
dest[current_len] = '\0';
57-
58-
// Closing quote
59-
if (needs_quote) {
60-
if (current_len < max_len - 1) dest[current_len++] = '\'';
61-
dest[current_len] = '\0';
62-
}
63-
}
64-
6522
int main(int argc, char *argv[])
6623
{
6724
BPTR lock;
68-
char command[MAX_CMD_LEN] = "";
69-
char filename[1024];
25+
char command[HOST_MAX_COMMAND_LEN] = "";
26+
char filename[HOST_MAX_PATH_LEN];
7027

7128
if (!InitUAEResource())
7229
{
@@ -89,30 +46,35 @@ int main(int argc, char *argv[])
8946
{
9047
// Try to resolve as a file path first (skip URLs to avoid volume requester)
9148
int is_resolved_file = 0;
92-
if (!strstr(argv[i], "://") && ((lock = Lock(argv[i], ACCESS_READ))))
49+
if (argv[i][0] != '\0' && !host_is_uri(argv[i]) && ((lock = Lock((STRPTR)argv[i], ACCESS_READ))))
9350
{
51+
filename[0] = '\0';
52+
filename[sizeof(filename) - 1] = '\0';
9453
if (NativeDosOp(0, (ULONG)lock, (ULONG)filename, sizeof(filename)) == 0) {
9554
UnLock(lock);
55+
if (host_filled_buffer(filename, sizeof(filename))) {
56+
printf("Resolved host path is too long\n");
57+
return HOST_RETURN_ERROR;
58+
}
9659
is_resolved_file = 1;
9760
} else {
9861
UnLock(lock);
9962
}
10063
}
10164

102-
// Separate arguments with space
103-
if (i > 1) {
104-
strncat(command, " ", MAX_CMD_LEN - strlen(command) - 1);
105-
}
106-
107-
if (is_resolved_file) {
108-
append_quoted(command, filename, MAX_CMD_LEN);
109-
} else {
110-
append_quoted(command, argv[i], MAX_CMD_LEN);
65+
if (!host_append_shell_arg(command, sizeof(command),
66+
is_resolved_file ? filename : argv[i], i > 1)) {
67+
printf("Command is too long\n");
68+
return HOST_RETURN_ERROR;
11169
}
11270
}
11371

11472
#ifdef DEBUG
11573
printf("DEBUG: argc=%d, command=%s\n", argc, command);
11674
#endif
117-
return ExecuteOnHost((UBYTE *)command);
118-
}
75+
if (!ExecuteOnHost((UBYTE *)command)) {
76+
printf("Failed to execute command on host\n");
77+
return HOST_RETURN_ERROR;
78+
}
79+
return 0;
80+
}

0 commit comments

Comments
 (0)