Skip to content

Commit d8298c3

Browse files
committed
Add proper duplicates of stdout/stderr and make it possible to add stdin
1 parent 3641d49 commit d8298c3

File tree

3 files changed

+35
-12
lines changed

3 files changed

+35
-12
lines changed

lib/tinykvm/linux/fds.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ namespace tinykvm
3232
: m_machine(machine),
3333
m_current_working_directory_fd(AT_FDCWD)
3434
{
35-
// XXX: TODO: Create proper redirects for stdout/stderr by
36-
// for example providing a pipe to stdout/stderr.
37-
m_fds[0] = Entry{ .real_fd = 0, .is_writable = false }; // stdin
38-
m_fds[1] = Entry{ .real_fd = 1, .is_writable = true }; // stdout
39-
m_fds[2] = Entry{ .real_fd = 2, .is_writable = true }; // stderr
35+
// Create proper redirects for stdin/stdout/stderr
36+
const int stdout_fd = dup(1);
37+
const int stderr_fd = dup(2);
38+
if (stdout_fd < 0 || stderr_fd < 0) {
39+
throw std::runtime_error("TinyKVM: Failed to duplicate stdout/stderr");
40+
}
41+
m_fds[1] = Entry{ .real_fd = stdout_fd, .is_writable = true }; // stdout
42+
m_fds[2] = Entry{ .real_fd = stderr_fd, .is_writable = true }; // stderr
4043
}
4144

4245
FileDescriptors::~FileDescriptors()
@@ -48,6 +51,16 @@ namespace tinykvm
4851
}
4952
}
5053

54+
void FileDescriptors::duplicate_and_add_stdin()
55+
{
56+
// Create a duplicate of stdin (0) and add it to the list of managed FDs.
57+
const int stdin_fd = dup(0);
58+
if (stdin_fd < 0) {
59+
throw std::runtime_error("TinyKVM: Failed to duplicate stdin");
60+
}
61+
m_fds[0] = Entry{ .real_fd = stdin_fd, .is_writable = false }; // stdin
62+
}
63+
5164
void FileDescriptors::reset_to(const FileDescriptors& other)
5265
{
5366
// Close all current file descriptors, except if forked
@@ -166,7 +179,8 @@ namespace tinykvm
166179

167180
int FileDescriptors::manage(int fd, bool is_socket, bool is_writable)
168181
{
169-
if (fd < 0) {
182+
(void)is_socket; // Unused
183+
if (fd <= 2) {
170184
throw std::runtime_error("TinyKVM: Invalid file descriptor in FileDescriptors::add()");
171185
}
172186
if (this->m_max_total_fds_opened != 0 && this->m_total_fds_opened >= this->m_max_total_fds_opened) {
@@ -213,7 +227,7 @@ namespace tinykvm
213227
FileDescriptors::Entry& FileDescriptors::manage_as(int vfd, int fd, bool is_socket, bool is_writable)
214228
{
215229
(void)is_socket; // Unused
216-
if (fd < 0) {
230+
if (fd <= 2) {
217231
throw std::runtime_error("TinyKVM: Invalid fd in FileDescriptors::manage_as()");
218232
}
219233
if (this->m_max_total_fds_opened != 0 &&

lib/tinykvm/linux/fds.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ namespace tinykvm
4343
~FileDescriptors();
4444
void reset_to(const FileDescriptors& other);
4545

46+
/// @brief Create a duplicate of, and insert stdin (0)
47+
/// @warning stdin is dangerous to add to a sandbox, as it allows
48+
/// interaction with the user (and the possibility of accidentally
49+
/// pasting something into the terminal).
50+
void duplicate_and_add_stdin();
51+
4652
/// @brief Add a file descriptor to the list of managed FDs.
4753
/// @param fd The real file descriptor.
4854
/// @param is_socket True if the file descriptor is a socket.
@@ -183,7 +189,7 @@ namespace tinykvm
183189
/// @brief Get the number of sockets that are currently open.
184190
/// @return The number of sockets that are currently open.
185191
uint16_t get_current_sockets_opened() const noexcept {
186-
return m_fds.size() - m_stdout_redirects.size();
192+
return m_fds.size();
187193
}
188194

189195
/// @brief Set a callback for connecting a socket. This is used to check if a
@@ -295,7 +301,6 @@ namespace tinykvm
295301
Machine& m_machine;
296302
std::map<int, Entry> m_fds;
297303
int m_next_fd = VFD_START;
298-
std::array<int, 3> m_stdout_redirects { 0, 1, 2 };
299304
std::string m_current_working_directory;
300305
int m_current_working_directory_fd = -1;
301306
bool m_verbose = false;

lib/tinykvm/linux/system_calls.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ void Machine::setup_linux_system_calls(bool unsafe_syscalls)
102102
if (UNLIKELY(bytes > 1024*64)) {
103103
regs.rax = -1;
104104
cpu.set_registers(regs);
105-
SYSPRINT("write(fd=%d (%d), data=0x%llX, size=%zu) = %lld\n",
105+
SYSPRINT("write(fd=%d (%d), data=0x%llX, size=%zu) = %lld (overflow)\n",
106106
vfd, vfd, regs.rsi, bytes, regs.rax);
107107
return;
108108
}
@@ -138,6 +138,8 @@ void Machine::setup_linux_system_calls(bool unsafe_syscalls)
138138
cpu.machine().print(buffer.begin(), buffer.size());
139139
});
140140
regs.rax = bytes;
141+
SYSPRINT("write(fd=%d (%d), data=0x%llX, size=%zu) = %lld (stdio)\n",
142+
vfd, vfd, regs.rsi, bytes, regs.rax);
141143
}
142144
cpu.set_registers(regs);
143145
});
@@ -2516,7 +2518,7 @@ void Machine::setup_linux_system_calls(bool unsafe_syscalls)
25162518
const int fd = cpu.machine().fds().translate(vfd);
25172519
const uint64_t g_event = regs.r10;
25182520
struct epoll_event event {};
2519-
if (epollfd > 0 && fd >= 0)
2521+
if (epollfd > 0 && fd >= 0 && epollfd != fd)
25202522
{
25212523
if (g_event != 0x0) {
25222524
cpu.machine().copy_from_guest(&event, g_event, sizeof(event));
@@ -2534,8 +2536,10 @@ void Machine::setup_linux_system_calls(bool unsafe_syscalls)
25342536
}
25352537
regs.rax = 0;
25362538
}
2539+
} else if (epollfd < 0 || fd < 0) {
2540+
regs.rax = -EBADF;
25372541
} else {
2538-
regs.rax = -ENOENT;
2542+
regs.rax = -EINVAL;
25392543
}
25402544
cpu.set_registers(regs);
25412545
if (UNLIKELY(cpu.machine().m_verbose_system_calls))

0 commit comments

Comments
 (0)