Skip to content

Commit

Permalink
Support not passing metadata to socket-based services
Browse files Browse the repository at this point in the history
This makes it easier to implement socket-based services that do not
require the metadata.  This avoids having to use a slow executable-based
service or write a custom wrapper.

Fixes: QubesOS/qubes-issues#9036
  • Loading branch information
DemiMarie committed Mar 30, 2024
1 parent 76197e7 commit 88073e5
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 8 deletions.
12 changes: 8 additions & 4 deletions libqrexec/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand Down
6 changes: 4 additions & 2 deletions libqrexec/libqrexec-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -97,8 +100,7 @@ void destroy_qrexec_parsed_command(struct qrexec_parsed_command *cmd);
* Deprecated, use load_service_config_v2() instead.
*/
int load_service_config(struct qrexec_parsed_command *cmd_name,
int *wait_for_session, char **user)
__attribute__((deprecated("use load_service_config_v2() instead")));
int *wait_for_session, char **user);
int load_service_config_v2(struct qrexec_parsed_command *cmd);

typedef void (do_exec_t)(const char *cmdline, const char *user);
Expand Down
2 changes: 1 addition & 1 deletion libqrexec/private.h
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#include <stdbool.h>
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);
8 changes: 7 additions & 1 deletion libqrexec/toml.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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); \
Expand Down Expand Up @@ -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");
Expand Down
35 changes: 35 additions & 0 deletions qrexec/tests/socket/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,41 @@ def test_exec_service_with_arg(self):
],
)

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 = 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"),
],
)

def test_connect_socket(self):
socket_path = os.path.join(
self.tempdir, "rpc", "qubes.SocketService+arg"
Expand Down

0 comments on commit 88073e5

Please sign in to comment.