diff --git a/include/intercept.pb-c.h b/include/intercept.pb-c.h index 2748aa709..9401f5d27 100644 --- a/include/intercept.pb-c.h +++ b/include/intercept.pb-c.h @@ -94,6 +94,7 @@ struct _PolicyCheckRequest { ProtobufCMessage base; char *command; + char *cwd; size_t n_argv; char **argv; size_t n_envp; @@ -103,7 +104,7 @@ struct _PolicyCheckRequest }; #define POLICY_CHECK_REQUEST__INIT \ { PROTOBUF_C_MESSAGE_INIT (&policy_check_request__descriptor) \ - , (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, 0, 0 } + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, 0, 0 } struct _PolicyAcceptMessage diff --git a/src/exec_intercept.c b/src/exec_intercept.c index 1dc460ff3..f6ecf23ca 100644 --- a/src/exec_intercept.c +++ b/src/exec_intercept.c @@ -203,45 +203,76 @@ bad: } /* - * Allocate a new command_info[] and update the command in it. - * Only allocates new space for command_info[] itseld and the new command. - * Stores a pointer to the new command in the tofree parameter. + * Allocate a new command_info[] and update command and runcwd in it. + * Fills in cmnd_out with a copy of the command if not NULL. + * Returns the new command_info[] which the caller must free. */ static char ** update_command_info(char * const *old_command_info, const char *cmnd, - char **tofree) + const char *runcwd, char **cmnd_out) { char **command_info; - char *tmp_command = NULL; + char * const *oci; size_t n; debug_decl(update_command_info, SUDO_DEBUG_EXEC); - /* Rebuild command_info[] with new command. */ + /* Rebuild command_info[] with new command and add a runcwd. */ for (n = 0; old_command_info[n] != NULL; n++) continue; - command_info = reallocarray(NULL, n + 1, sizeof(char *)); + command_info = reallocarray(NULL, n + 2, sizeof(char *)); if (command_info == NULL) { goto bad; } - for (n = 0; old_command_info[n] != NULL; n++) { - const char *cp = old_command_info[n]; - if (strncmp(cp, "command=", sizeof("command=") - 1) == 0) { - if (tmp_command != NULL) - continue; - tmp_command = sudo_new_key_val("command", cmnd); - if (tmp_command == NULL) { - goto bad; + for (oci = old_command_info, n = 0; *oci != NULL; oci++) { + const char *cp = *oci; + switch (*cp) { + case 'c': + if (strncmp(cp, "command=", sizeof("command=") - 1) == 0) { + if (cmnd != NULL) { + command_info[n] = sudo_new_key_val("command", cmnd); + if (command_info[n] == NULL) { + goto bad; + } + n++; + continue; + } else if (cmnd_out != NULL) { + *cmnd_out = strdup(cp + sizeof("command=") - 1); + if (*cmnd_out == NULL) { + goto bad; + } + } } - cp = tmp_command; + break; + case 'r': + if (strncmp(cp, "runcwd=", sizeof("runcwd=") - 1) == 0) { + /* Filled in at the end. */ + continue; + } + break; } - command_info[n] = (char *)cp; + command_info[n] = strdup(cp); + if (command_info[n] == NULL) { + goto bad; + } + n++; } + /* Append actual runcwd. */ + command_info[n] = sudo_new_key_val("runcwd", runcwd); + if (command_info[n] == NULL) { + goto bad; + } + n++; + command_info[n] = NULL; - *tofree = tmp_command; debug_return_ptr(command_info); bad: - free(command_info); + if (command_info != NULL) { + for (n = 0; command_info[n] != NULL; n++) { + free(command_info[n]); + } + free(command_info); + } debug_return_ptr(NULL); } @@ -252,7 +283,6 @@ intercept_check_policy(PolicyCheckRequest *req, char **command_info = NULL; char **user_env_out = NULL; char **argv = NULL, **run_argv = NULL; - char *tofree = NULL; bool ret = false; int result; size_t n; @@ -302,17 +332,12 @@ intercept_check_policy(PolicyCheckRequest *req, switch (result) { case 1: - /* Extract command path from command_info[] */ - for (n = 0; command_info[n] != NULL; n++) { - const char *cp = command_info[n]; - if (strncmp(cp, "command=", sizeof("command=") - 1) == 0) { - closure->command = strdup(cp + sizeof("command=") - 1); - if (closure->command == NULL) { - closure->errstr = N_("unable to allocate memory"); - goto done; - } - break; - } + /* Rebuild command_info[] with runcwd and extract command. */ + command_info = update_command_info(command_info, NULL, + req->cwd ? req->cwd : "unknown", &closure->command); + if (command_info == NULL) { + closure->errstr = N_("unable to allocate memory"); + goto done; } closure->state = POLICY_ACCEPT; break; @@ -336,9 +361,9 @@ intercept_check_policy(PolicyCheckRequest *req, goto done; } - /* Rebuild command_info[] with new command. */ + /* Rebuild command_info[] with new command and runcwd. */ command_info = update_command_info(closure->details->info, - req->command, &tofree); + req->command, req->cwd ? req->cwd : "unknown", NULL); if (command_info == NULL) { closure->errstr = N_("unable to allocate memory"); goto done; @@ -415,8 +440,10 @@ done: command_info ? command_info : closure->details->info); closure->state = POLICY_ERROR; } - if (!ISSET(closure->details->flags, CD_INTERCEPT)) { - free(tofree); + if (command_info != NULL) { + for (n = 0; command_info[n] != NULL; n++) { + free(command_info[n]); + } free(command_info); } free(argv); diff --git a/src/intercept.pb-c.c b/src/intercept.pb-c.c index 9e8df76db..9866807c0 100644 --- a/src/intercept.pb-c.c +++ b/src/intercept.pb-c.c @@ -507,7 +507,7 @@ const ProtobufCMessageDescriptor hello_response__descriptor = (ProtobufCMessageInit) hello_response__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[5] = +static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[6] = { { "command", @@ -522,8 +522,20 @@ static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[5] 0,NULL,NULL /* reserved1,reserved2, etc */ }, { - "argv", + "cwd", 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PolicyCheckRequest, cwd), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "argv", + 3, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_STRING, offsetof(PolicyCheckRequest, n_argv), @@ -535,7 +547,7 @@ static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[5] }, { "envp", - 3, + 4, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_STRING, offsetof(PolicyCheckRequest, n_envp), @@ -547,7 +559,7 @@ static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[5] }, { "intercept_fd", - 4, + 5, PROTOBUF_C_LABEL_NONE, PROTOBUF_C_TYPE_INT32, 0, /* quantifier_offset */ @@ -559,7 +571,7 @@ static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[5] }, { "secret", - 5, + 6, PROTOBUF_C_LABEL_NONE, PROTOBUF_C_TYPE_FIXED64, 0, /* quantifier_offset */ @@ -571,16 +583,17 @@ static const ProtobufCFieldDescriptor policy_check_request__field_descriptors[5] }, }; static const unsigned policy_check_request__field_indices_by_name[] = { - 1, /* field[1] = argv */ + 2, /* field[2] = argv */ 0, /* field[0] = command */ - 2, /* field[2] = envp */ - 3, /* field[3] = intercept_fd */ - 4, /* field[4] = secret */ + 1, /* field[1] = cwd */ + 3, /* field[3] = envp */ + 4, /* field[4] = intercept_fd */ + 5, /* field[5] = secret */ }; static const ProtobufCIntRange policy_check_request__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 5 } + { 0, 6 } }; const ProtobufCMessageDescriptor policy_check_request__descriptor = { @@ -590,7 +603,7 @@ const ProtobufCMessageDescriptor policy_check_request__descriptor = "PolicyCheckRequest", "", sizeof(PolicyCheckRequest), - 5, + 6, policy_check_request__field_descriptors, policy_check_request__field_indices_by_name, 1, policy_check_request__number_ranges, diff --git a/src/intercept.proto b/src/intercept.proto index 7d7ef1c53..10e6ff09d 100644 --- a/src/intercept.proto +++ b/src/intercept.proto @@ -36,10 +36,11 @@ message HelloResponse { */ message PolicyCheckRequest { string command = 1; - repeated string argv = 2; - repeated string envp = 3; - int32 intercept_fd = 4; - fixed64 secret = 5; + string cwd = 2; + repeated string argv = 3; + repeated string envp = 4; + int32 intercept_fd = 5; + fixed64 secret = 6; } message PolicyAcceptMessage { diff --git a/src/sudo_intercept_common.c b/src/sudo_intercept_common.c index 8c8ddfad2..f91021954 100644 --- a/src/sudo_intercept_common.c +++ b/src/sudo_intercept_common.c @@ -253,6 +253,7 @@ send_policy_check_req(int sock, const char *cmnd, char * const argv[], { InterceptRequest msg = INTERCEPT_REQUEST__INIT; PolicyCheckRequest req = POLICY_CHECK_REQUEST__INIT; + char cwdbuf[PATH_MAX]; uint8_t *buf = NULL; bool ret = false; uint32_t msg_len; @@ -271,6 +272,9 @@ send_policy_check_req(int sock, const char *cmnd, char * const argv[], for (len = 0; envp[len] != NULL; len++) continue; req.n_envp = len; + if (getcwd(cwdbuf, sizeof(cwdbuf)) != NULL) { + req.cwd = cwdbuf; + } msg.type_case = INTERCEPT_REQUEST__TYPE_POLICY_CHECK_REQ; msg.u.policy_check_req = &req;