Skip to content

Commit e0407d8

Browse files
committed
Strip "QUBESRPC " prefix from service call commands
It carries no information, and various parts of the code must strip it. Just omit it from the command entirely. Whether a command is an RPC command should be determined by the service descriptor being non-NULL. Review with "git diff --ignore-space-change".
1 parent 29a764f commit e0407d8

File tree

6 files changed

+103
-105
lines changed

6 files changed

+103
-105
lines changed

agent/qrexec-agent.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ _Noreturn void do_exec(const char *prog, const char *cmd, const char *user)
172172
exit(1);
173173
}
174174
/* call QUBESRPC if requested */
175-
exec_qubes_rpc_if_requested(prog, cmd, environ);
175+
if (prog)
176+
exec_qubes_rpc(prog, cmd, environ);
176177

177178
/* otherwise exec shell */
178179
execl("/bin/sh", "sh", "-c", cmd, NULL);
@@ -279,7 +280,8 @@ _Noreturn void do_exec(const char *prog, const char *cmd, const char *user)
279280
warn("chdir(%s)", pw->pw_dir);
280281

281282
/* call QUBESRPC if requested */
282-
exec_qubes_rpc_if_requested(prog, cmd, env);
283+
if (prog)
284+
exec_qubes_rpc(prog, cmd, env);
283285

284286
/* otherwise exec shell */
285287
execle(pw->pw_shell, arg0, "-c", cmd, (char*)NULL, env);
@@ -317,7 +319,8 @@ _Noreturn void do_exec(const char *prog, const char *cmd, const char *user)
317319
exit(1);
318320
#else
319321
/* call QUBESRPC if requested */
320-
exec_qubes_rpc_if_requested(prog, cmd, environ);
322+
if (prog)
323+
exec_qubes_rpc(prog, cmd, environ);
321324

322325
/* otherwise exec shell */
323326
execl("/bin/su", "su", "-", user, "-c", cmd, NULL);

agent/qrexec-fork-server.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ void do_exec(const char *prog, const char *cmd, const char *user __attribute__((
4545
signal(SIGPIPE, SIG_DFL);
4646

4747
/* call QUBESRPC if requested */
48-
exec_qubes_rpc_if_requested(prog, cmd, environ);
48+
if (prog != NULL)
49+
exec_qubes_rpc(prog, cmd, environ);
4950

5051
/* otherwise, pass it to shell */
5152
shell = getenv("SHELL");

daemon/qrexec-client.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@ static _Noreturn void do_exec(const char *prog,
6666
const char *cmdline,
6767
const char *username __attribute__((unused)))
6868
{
69-
/* avoid calling RPC command through shell */
70-
exec_qubes_rpc_if_requested(prog, cmdline, environ);
69+
/* avoid calling RPC service through shell */
70+
if (prog)
71+
exec_qubes_rpc(prog, cmdline, environ);
7172

72-
/* if above haven't executed RPC command, pass it to shell */
73+
/* if above haven't executed RPC service, pass it to shell */
7374
execl("/bin/bash", "bash", "-c", cmdline, NULL);
7475
PERROR("exec bash");
7576
exit(1);

daemon/qrexec-daemon.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1106,7 +1106,8 @@ static enum policy_response connect_daemon_socket(
11061106
static _Noreturn void do_exec(const char *prog, const char *cmd, const char *username __attribute__((unused)))
11071107
{
11081108
/* avoid calling RPC command through shell */
1109-
exec_qubes_rpc_if_requested(prog, cmd, environ);
1109+
if (prog)
1110+
exec_qubes_rpc(prog, cmd, environ);
11101111

11111112
/* if above haven't executed RPC command, pass it to shell */
11121113
execl("/bin/bash", "bash", "-c", cmd, NULL);

libqrexec/exec.c

Lines changed: 86 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <netdb.h>
3737
#include <unistd.h>
3838
#include <fcntl.h>
39+
3940
#include "qrexec.h"
4041
#include "libqrexec-utils.h"
4142
#include "private.h"
@@ -54,110 +55,98 @@ static bool should_strip_env_var(const char *var)
5455
return strncmp(var + (sizeof "QREXEC" - 1), "_SERVICE_PATH=", sizeof "_SERVICE_PATH") != 0;
5556
}
5657

57-
void exec_qubes_rpc_if_requested(const char *program, const char *cmd, char *const envp[]) {
58+
void exec_qubes_rpc(const char *program, const char *cmd, char *const envp[]) {
5859
/* avoid calling RPC service through shell */
59-
if (program) {
60-
assert(program);
61-
char *prog_copy;
62-
char *tok, *savetok;
63-
const char *argv[6];
64-
size_t i = 0;
60+
char *prog_copy;
61+
char *tok, *savetok;
62+
const char *argv[6];
63+
size_t i = 0;
6564
#define MAX_ADDED_ENV_VARS 5
66-
size_t const extra_env_vars = MAX_ADDED_ENV_VARS;
67-
size_t env_amount = extra_env_vars;
68-
69-
if (strncmp(cmd, RPC_REQUEST_COMMAND " ", RPC_REQUEST_COMMAND_LEN + 1) != 0) {
70-
LOG(ERROR, "program != NULL, but '%s' does not start with '%s '",
71-
cmd, RPC_REQUEST_COMMAND " ");
72-
assert(!"Invalid command");
73-
_exit(QREXEC_EXIT_PROBLEM);
74-
}
75-
76-
for (char *const *env = envp; *env; ++env) {
77-
// Set this 0 to 1 if adding new variable settings below,
78-
// to ensure that MAX_ADDED_ENV_VARS is correct.
79-
if (0 && should_strip_env_var(*env))
80-
continue;
81-
env_amount++;
82-
}
65+
size_t const extra_env_vars = MAX_ADDED_ENV_VARS;
66+
size_t env_amount = extra_env_vars;
67+
68+
for (char *const *env = envp; *env; ++env) {
69+
// Set this 0 to 1 if adding new variable settings below,
70+
// to ensure that MAX_ADDED_ENV_VARS is correct.
71+
if (0 && should_strip_env_var(*env))
72+
continue;
73+
env_amount++;
74+
}
8375
#define EXTEND(...) \
84-
do { \
85-
if (iterator >= env_amount) \
86-
abort(); \
87-
if (asprintf(&buf[iterator++], __VA_ARGS__) < 0) \
88-
goto bad_asprintf; \
89-
} while (0)
76+
do { \
77+
if (iterator >= env_amount) \
78+
abort(); \
79+
if (asprintf(&buf[iterator++], __VA_ARGS__) < 0) \
80+
goto bad_asprintf; \
81+
} while (0)
9082
#define EXTEND_RAW(arg) \
91-
do { \
92-
if (iterator >= env_amount) \
93-
abort(); \
94-
buf[iterator++] = (arg); \
95-
} while (0)
83+
do { \
84+
if (iterator >= env_amount) \
85+
abort(); \
86+
buf[iterator++] = (arg); \
87+
} while (0)
9688

97-
char **buf = calloc(env_amount + 1, sizeof(char *));
98-
if (buf == NULL) {
99-
LOG(ERROR, "calloc(%zu, %zu) failed: %m", env_amount, sizeof(char *));
100-
_exit(QREXEC_EXIT_PROBLEM);
101-
}
102-
size_t iterator = 0;
103-
for (char *const *env = envp; *env; ++env) {
104-
if (!should_strip_env_var(*env)) {
105-
EXTEND_RAW(*env);
106-
}
89+
char **buf = calloc(env_amount + 1, sizeof(char *));
90+
if (buf == NULL) {
91+
LOG(ERROR, "calloc(%zu, %zu) failed: %m", env_amount, sizeof(char *));
92+
_exit(QREXEC_EXIT_PROBLEM);
93+
}
94+
size_t iterator = 0;
95+
for (char *const *env = envp; *env; ++env) {
96+
if (!should_strip_env_var(*env)) {
97+
EXTEND_RAW(*env);
10798
}
99+
}
108100

109-
prog_copy = strdup(cmd + RPC_REQUEST_COMMAND_LEN + 1);
110-
if (!prog_copy) {
111-
PERROR("strdup");
112-
_exit(QREXEC_EXIT_PROBLEM);
113-
}
101+
prog_copy = strdup(cmd);
102+
if (!prog_copy) {
103+
PERROR("strdup");
104+
_exit(QREXEC_EXIT_PROBLEM);
105+
}
114106

115-
argv[i++] = (char *)program;
116-
tok=strtok_r(prog_copy, " ", &savetok);
117-
while (tok != NULL) {
118-
if (i >= sizeof(argv)/sizeof(argv[0])-1) {
119-
LOG(ERROR, "Too many arguments to %s", RPC_REQUEST_COMMAND);
120-
_exit(QREXEC_EXIT_PROBLEM);
121-
}
122-
argv[i++] = tok;
123-
tok = strtok_r(NULL, " ", &savetok);
124-
}
125-
argv[i] = NULL;
126-
if (i == 5) {
127-
EXTEND("QREXEC_REQUESTED_TARGET_TYPE=%s", argv[3]);
128-
if (strcmp(argv[3], "name") == 0) {
129-
EXTEND("QREXEC_REQUESTED_TARGET=%s", argv[4]);
130-
} else if (strcmp(argv[3], "keyword") == 0) {
131-
EXTEND("QREXEC_REQUESTED_TARGET_KEYWORD=%s", argv[4]);
132-
} else {
133-
// requested target type unknown, ignore
134-
}
135-
} else if (i == 3) {
136-
EXTEND_RAW("QREXEC_REQUESTED_TARGET_TYPE=");
137-
} else {
138-
LOG(ERROR, "invalid number of arguments: %zu", i);
107+
argv[i++] = (char *)program;
108+
tok=strtok_r(prog_copy, " ", &savetok);
109+
while (tok != NULL) {
110+
if (i >= sizeof(argv)/sizeof(argv[0])-1) {
111+
LOG(ERROR, "Too many arguments to %s", RPC_REQUEST_COMMAND);
139112
_exit(QREXEC_EXIT_PROBLEM);
140113
}
141-
EXTEND("QREXEC_SERVICE_FULL_NAME=%s", argv[1]);
142-
EXTEND("QREXEC_REMOTE_DOMAIN=%s", argv[2]);
143-
const char *p = strchr(argv[1], '+');
144-
argv[1] = NULL;
145-
argv[2] = NULL;
146-
if (p != NULL) {
147-
EXTEND("QREXEC_SERVICE_ARGUMENT=%s", p + 1);
148-
if (p[1])
149-
argv[1] = p + 1;
114+
argv[i++] = tok;
115+
tok = strtok_r(NULL, " ", &savetok);
116+
}
117+
argv[i] = NULL;
118+
if (i == 5) {
119+
EXTEND("QREXEC_REQUESTED_TARGET_TYPE=%s", argv[3]);
120+
if (strcmp(argv[3], "name") == 0) {
121+
EXTEND("QREXEC_REQUESTED_TARGET=%s", argv[4]);
122+
} else if (strcmp(argv[3], "keyword") == 0) {
123+
EXTEND("QREXEC_REQUESTED_TARGET_KEYWORD=%s", argv[4]);
124+
} else {
125+
// requested target type unknown or not given, ignore
150126
}
151-
assert(iterator <= env_amount);
152-
buf[iterator] = NULL;
153-
execve(argv[0], (char *const *)argv, buf);
154-
_exit(errno == ENOENT ? QREXEC_EXIT_SERVICE_NOT_FOUND : QREXEC_EXIT_PROBLEM);
155-
bad_asprintf:
156-
PERROR("asprintf");
157-
_exit(QREXEC_EXIT_PROBLEM);
127+
} else if (i == 3) {
128+
EXTEND_RAW("QREXEC_REQUESTED_TARGET_TYPE=");
158129
} else {
159-
assert(strncmp(cmd, RPC_REQUEST_COMMAND, RPC_REQUEST_COMMAND_LEN) != 0);
130+
LOG(ERROR, "invalid number of arguments: %zu", i);
131+
_exit(QREXEC_EXIT_PROBLEM);
160132
}
133+
EXTEND("QREXEC_SERVICE_FULL_NAME=%s", argv[1]);
134+
EXTEND("QREXEC_REMOTE_DOMAIN=%s", argv[2]);
135+
const char *p = strchr(argv[1], '+');
136+
argv[1] = NULL;
137+
argv[2] = NULL;
138+
if (p != NULL) {
139+
EXTEND("QREXEC_SERVICE_ARGUMENT=%s", p + 1);
140+
if (p[1])
141+
argv[1] = p + 1;
142+
}
143+
assert(iterator <= env_amount);
144+
buf[iterator] = NULL;
145+
execve(argv[0], (char *const *)argv, buf);
146+
_exit(errno == ENOENT ? QREXEC_EXIT_SERVICE_NOT_FOUND : QREXEC_EXIT_PROBLEM);
147+
bad_asprintf:
148+
PERROR("asprintf");
149+
_exit(QREXEC_EXIT_PROBLEM);
161150
}
162151

163152
void fix_fds(int fdin, int fdout, int fderr)
@@ -493,7 +482,9 @@ struct qrexec_parsed_command *parse_qubes_rpc_command(
493482
}
494483

495484
/* Parse service descriptor ("qubes.Service+arg") */
496-
start = cmd->command + RPC_REQUEST_COMMAND_LEN + 1;
485+
cmd->command += RPC_REQUEST_COMMAND_LEN + 1;
486+
487+
start = cmd->command;
497488
end = strchr(start, ' ');
498489
if (!end) {
499490
LOG(ERROR, "No space found after service descriptor");
@@ -608,7 +599,7 @@ int execute_parsed_qubes_rpc_command(
608599
return 0;
609600
}
610601
return do_fork_exec(buf.data, cmd->username, cmd->command,
611-
pid, stdin_fd, stdout_fd, stderr_fd);
602+
pid, stdin_fd, stdout_fd, stderr_fd);
612603
} else {
613604
// Legacy qrexec behavior: spawn shell directly
614605
return do_fork_exec(NULL, cmd->username, cmd->command,
@@ -732,7 +723,7 @@ int find_qrexec_service(
732723

733724
if (cmd->send_service_descriptor) {
734725
/* send part after "QUBESRPC ", including trailing NUL */
735-
const char *desc = cmd->command + RPC_REQUEST_COMMAND_LEN + 1;
726+
const char *desc = cmd->command;
736727
buffer_append(stdin_buffer, desc, strlen(desc) + 1);
737728
}
738729

@@ -792,7 +783,7 @@ int find_qrexec_service(
792783

793784
if (cmd->send_service_descriptor) {
794785
/* send part after "QUBESRPC ", including trailing NUL */
795-
const char *desc = cmd->command + RPC_REQUEST_COMMAND_LEN + 1;
786+
const char *desc = cmd->command;
796787
buffer_append(stdin_buffer, desc, strlen(desc) + 1);
797788
}
798789

libqrexec/libqrexec-utils.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ struct qrexec_parsed_command {
6262
/* Override to disable "wait for session" */
6363
bool nogui;
6464

65-
/* Command (the part after "user:") */
65+
/* Command (the part after "user:"). If this is an RPC command
66+
* then the "QUBESRPC " prefix is not included. */
6667
const char *command;
6768

6869
/* The below parameters are NULL for legacy (non-"QUBESRPC") commands. */
@@ -145,7 +146,7 @@ void register_exec_func(do_exec_t *func);
145146
* returns without doing anything.
146147
*/
147148
__attribute__((visibility("default")))
148-
void exec_qubes_rpc_if_requested(const char *program, const char *cmd, char *const envp[]);
149+
_Noreturn void exec_qubes_rpc(const char *program, const char *cmd, char *const envp[]);
149150

150151
__attribute__((visibility("default")))
151152
int exec_wait_for_session(const char *source_domain);

0 commit comments

Comments
 (0)