Skip to content

Commit

Permalink
qrexec: add qrexec-client-vm --buffer-size option
Browse files Browse the repository at this point in the history
Add an option for custom vchan buffer size, to override default 64k (for
each direction). This is especially useful when the other side of
connection is MirageOS based, because of limited memory and default
grant table size (128 entries).
  • Loading branch information
marmarek committed Mar 14, 2018
1 parent 0186d1c commit 4a09023
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
8 changes: 7 additions & 1 deletion doc/vm-tools/qrexec-client-vm.rst
Expand Up @@ -8,7 +8,7 @@ qrexec-client-vm - call Qubes RPC service

SYNOPSIS
========
| qrexec-client-vm *target_vmname* *service* [*local_program* [*local program arguments*]]
| qrexec-client-vm [--buffer-size=*BUFFER_SIZE*] *target_vmname* *service* [*local_program* [*local program arguments*]]
DESCRIPTION
===========
Expand All @@ -27,6 +27,12 @@ stdin/stdout is connected to those of ``qrexec-client-vm``.
OPTIONS
=======

--buffer-size=*BUFFER_SIZE*

Optional buffer size for vchan connection. This size is used as minimum
size for a buffer in each connection direction (read and write).
Default: 64KiB.

*target_vmname*

Name of target VM to which service is requested. Qubes RPC policy may
Expand Down
17 changes: 12 additions & 5 deletions qrexec/qrexec-agent-data.c
Expand Up @@ -490,10 +490,14 @@ int process_child_io(libvchan_t *data_vchan,
* MSG_EXEC_CMDLINE - connect to vchan server, fork+exec process given by
* cmdline parameter, pass the data to/from that process, then return local
* process exit code
*
* buffer_size is about vchan buffer allocated (only for vchan server cases),
* use 0 to use built-in default (64k); needs to be power of 2
*/
int handle_new_process_common(int type, int connect_domain, int connect_port,
char *cmdline, int cmdline_len, /* MSG_JUST_EXEC and MSG_EXEC_CMDLINE */
int stdin_fd, int stdout_fd, int stderr_fd /* MSG_SERVICE_CONNECT */)
int stdin_fd, int stdout_fd, int stderr_fd /* MSG_SERVICE_CONNECT */,
int buffer_size)
{
libvchan_t *data_vchan;
int exit_code = 0;
Expand All @@ -504,9 +508,12 @@ int handle_new_process_common(int type, int connect_domain, int connect_port,
cmdline[cmdline_len-1] = 0;
}

if (buffer_size == 0)
buffer_size = VCHAN_BUFFER_SIZE;

if (type == MSG_SERVICE_CONNECT) {
data_vchan = libvchan_server_init(connect_domain, connect_port,
VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE);
buffer_size, buffer_size);
if (data_vchan)
libvchan_wait(data_vchan);
} else {
Expand Down Expand Up @@ -563,7 +570,7 @@ pid_t handle_new_process(int type, int connect_domain, int connect_port,
/* child process */
exit_code = handle_new_process_common(type, connect_domain, connect_port,
cmdline, cmdline_len,
-1, -1, -1);
-1, -1, -1, 0);

exit(exit_code);
/* suppress warning */
Expand All @@ -572,13 +579,13 @@ pid_t handle_new_process(int type, int connect_domain, int connect_port,

/* Returns exit code of remote process */
int handle_data_client(int type, int connect_domain, int connect_port,
int stdin_fd, int stdout_fd, int stderr_fd)
int stdin_fd, int stdout_fd, int stderr_fd, int buffer_size)
{
int exit_code;

assert(type == MSG_SERVICE_CONNECT);

exit_code = handle_new_process_common(type, connect_domain, connect_port,
NULL, 0, stdin_fd, stdout_fd, stderr_fd);
NULL, 0, stdin_fd, stdout_fd, stderr_fd, buffer_size);
return exit_code;
}
3 changes: 2 additions & 1 deletion qrexec/qrexec-agent.h
Expand Up @@ -37,7 +37,8 @@ pid_t handle_new_process(int type,
char *cmdline, int cmdline_len);
int handle_data_client(int type,
int connect_domain, int connect_port,
int stdin_fd, int stdout_fd, int stderr_fd);
int stdin_fd, int stdout_fd, int stderr_fd,
int buffer_size);


struct qrexec_cmd_info {
Expand Down
54 changes: 40 additions & 14 deletions qrexec/qrexec-client-vm.c
Expand Up @@ -27,6 +27,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h>
#include "libqrexec-utils.h"
#include "qrexec.h"
#include "qrexec-agent.h"
Expand Down Expand Up @@ -85,6 +86,19 @@ void convert_target_name_keyword(char *target)
target[i] = '@';
}

struct option longopts[] = {
{ "buffer-size", required_argument, 0, 'b' },
{ NULL, 0, 0, 0},
};

_Noreturn void usage(const char *argv0) {
fprintf(stderr,
"usage: %s [--buffer-size=BUFFER_SIZE] target_vmname program_ident [local_program [local program arguments]]\n",
argv0);
fprintf(stderr, "BUFFER_SIZE is minimum vchan buffer size (default: 64k)\n");
exit(2);
}

int main(int argc, char **argv)
{
int trigger_fd;
Expand All @@ -95,24 +109,36 @@ int main(int argc, char **argv)
char *abs_exec_path;
pid_t child_pid = 0;
int inpipe[2], outpipe[2];
int buffer_size = 0;
int opt;

while (1) {
opt = getopt_long(argc, argv, "", longopts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'b':
buffer_size = atoi(optarg);
break;
case '?':
usage(argv[0]);
}
}

if (argc < 3) {
fprintf(stderr,
"usage: %s target_vmname program_ident [local_program [local program arguments]]\n",
argv[0]);
exit(1);
if (argc - optind < 2) {
usage(argv[0]);
}
if (argc > 3) {
if (argc - optind > 2) {
start_local_process = 1;
}

trigger_fd = connect_unix_socket(QREXEC_AGENT_TRIGGER_PATH);

memset(&params, 0, sizeof(params));
strncpy(params.service_name, argv[2], sizeof(params.service_name));
strncpy(params.service_name, argv[optind + 1], sizeof(params.service_name));

convert_target_name_keyword(argv[1]);
strncpy(params.target_domain, argv[1],
convert_target_name_keyword(argv[optind]);
strncpy(params.target_domain, argv[optind],
sizeof(params.target_domain));

snprintf(params.request_id.ident,
Expand Down Expand Up @@ -164,9 +190,9 @@ int main(int argc, char **argv)
close(inpipe[0]);
close(outpipe[1]);

abs_exec_path = strdup(argv[3]);
argv[3] = get_program_name(argv[3]);
execv(abs_exec_path, argv + 3);
abs_exec_path = strdup(argv[optind + 2]);
argv[optind + 2] = get_program_name(argv[optind + 2]);
execv(abs_exec_path, argv + optind + 2);
perror("execv");
exit(-1);
}
Expand All @@ -175,11 +201,11 @@ int main(int argc, char **argv)

ret = handle_data_client(MSG_SERVICE_CONNECT,
exec_params.connect_domain, exec_params.connect_port,
inpipe[1], outpipe[0], -1);
inpipe[1], outpipe[0], -1, buffer_size);
} else {
ret = handle_data_client(MSG_SERVICE_CONNECT,
exec_params.connect_domain, exec_params.connect_port,
1, 0, -1);
1, 0, -1, buffer_size);
}

close(trigger_fd);
Expand Down

0 comments on commit 4a09023

Please sign in to comment.