diff --git a/libqrexec/exec.c b/libqrexec/exec.c index d03fae21..0825f49d 100644 --- a/libqrexec/exec.c +++ b/libqrexec/exec.c @@ -269,7 +269,8 @@ static int load_service_config_raw(struct qrexec_parsed_command *cmd, config_full_path, sizeof(config_full_path), NULL); if (ret < 0) return 0; - return qubes_toml_config_parse(config_full_path, &cmd->wait_for_session, user); + return qubes_toml_config_parse(config_full_path, &cmd->wait_for_session, user, + &cmd->send_service_descriptor); } int load_service_config_v2(struct qrexec_parsed_command *cmd) { @@ -304,6 +305,7 @@ struct qrexec_parsed_command *parse_qubes_rpc_command( } memset(cmd, 0, sizeof(*cmd)); + cmd->send_service_descriptor = true; cmd->cmdline = cmdline; if (strip_username) { @@ -489,9 +491,11 @@ static int execute_qrexec_service( *pid = 0; set_nonblock(s); - /* send part after "QUBESRPC ", including trailing NUL */ - const char *desc = cmd->command + RPC_REQUEST_COMMAND_LEN + 1; - buffer_append(stdin_buffer, desc, strlen(desc) + 1); + if (cmd->send_service_descriptor) { + /* send part after "QUBESRPC ", including trailing NUL */ + const char *desc = cmd->command + RPC_REQUEST_COMMAND_LEN + 1; + buffer_append(stdin_buffer, desc, strlen(desc) + 1); + } return 0; } diff --git a/libqrexec/libqrexec-utils.h b/libqrexec/libqrexec-utils.h index 20346f63..a74b3c31 100644 --- a/libqrexec/libqrexec-utils.h +++ b/libqrexec/libqrexec-utils.h @@ -79,6 +79,9 @@ struct qrexec_parsed_command { /* Should a session be waited for? */ bool wait_for_session; + + /* For socket-based services: Should the service descriptor be sent? */ + bool send_service_descriptor; }; /* Parse a command, return NULL on failure. Uses cmd->cmdline diff --git a/libqrexec/private.h b/libqrexec/private.h index 3ef05cbf..73a3ffba 100644 --- a/libqrexec/private.h +++ b/libqrexec/private.h @@ -1,2 +1,2 @@ #include -int qubes_toml_config_parse(const char *config_full_path, bool *wait_for_session, char **user); +int qubes_toml_config_parse(const char *config_full_path, bool *wait_for_session, char **user, bool *skip_service_descriptor); diff --git a/libqrexec/toml.c b/libqrexec/toml.c index c60acb87..500941d7 100644 --- a/libqrexec/toml.c +++ b/libqrexec/toml.c @@ -171,7 +171,7 @@ static void toml_value_free(union toml_data *value, enum toml_type ty) { } } -int qubes_toml_config_parse(const char *config_full_path, bool *wait_for_session, char **user) +int qubes_toml_config_parse(const char *config_full_path, bool *wait_for_session, char **user, bool *send_service_descriptor) { int result = -1; /* assume problem */ FILE *config_file = fopen(config_full_path, "re"); @@ -186,7 +186,9 @@ int qubes_toml_config_parse(const char *config_full_path, bool *wait_for_session ssize_t signed_linelen; bool seen_wait_for_session = false; bool seen_user = false; + bool seen_skip_service_descriptor = false; *wait_for_session = 0; + *send_service_descriptor = true; #define CHECK_DUP_KEY(v) do { \ if (toml_check_dup_key(&(v), config_full_path, lineno, current_line)) { \ toml_value_free(&value, ty); \ @@ -288,6 +290,10 @@ int qubes_toml_config_parse(const char *config_full_path, bool *wait_for_session CHECK_TYPE(TOML_TYPE_BOOL, "wait-for-session"); *wait_for_session = value.boolean; } + } else if (strcmp(current_line, "skip-service-descriptor") == 0) { + CHECK_DUP_KEY(seen_skip_service_descriptor); + CHECK_TYPE(TOML_TYPE_BOOL, "skip-service-descriptor"); + *send_service_descriptor = !value.boolean; } else if (strcmp(current_line, "force-user") == 0) { CHECK_DUP_KEY(seen_user); CHECK_TYPE(TOML_TYPE_STRING, "user name or user ID"); diff --git a/qrexec/tests/socket/agent.py b/qrexec/tests/socket/agent.py index 7219bd57..07cef783 100644 --- a/qrexec/tests/socket/agent.py +++ b/qrexec/tests/socket/agent.py @@ -525,6 +525,42 @@ def test_exec_service_with_arg(self): ) self.check_dom0(dom0) + def test_connect_socket_no_metadata(self): + socket_path = os.path.join( + self.tempdir, "rpc", "qubes.SocketService+arg2" + ) + with open( + os.path.join(self.tempdir, "rpc-config", "qubes.SocketService+arg2"), "w" + ) as f: + f.write("""\ +skip-service-descriptor = true +""") + server = qrexec.socket_server(socket_path) + self.addCleanup(server.close) + + target, dom0 = self.execute_qubesrpc("qubes.SocketService+arg2", "domX") + + server.accept() + + message = b"stdin data" + target.send_message(qrexec.MSG_DATA_STDIN, message) + target.send_message(qrexec.MSG_DATA_STDIN, b"") + self.assertEqual(server.recvall(len(message)), message) + + server.sendall(b"stdout data") + server.close() + messages = target.recv_all_messages() + # No stderr + self.assertListEqual( + util.sort_messages(messages), + [ + (qrexec.MSG_DATA_STDOUT, b"stdout data"), + (qrexec.MSG_DATA_STDOUT, b""), + (qrexec.MSG_DATA_EXIT_CODE, b"\0\0\0\0"), + ], + ) + self.check_dom0(dom0) + def test_connect_socket(self): socket_path = os.path.join( self.tempdir, "rpc", "qubes.SocketService+arg"