Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions client/crashpad_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,14 @@ class CrashpadClient {
//! \param[in] attachment The path to the file to be added.
void AddAttachment(const base::FilePath& attachment);

//! \brief Writes content to an attachment file.
bool WriteAttachment(
const base::FilePath& attachment, const std::string& data);

//! \brief Appends content to an attachment file.
bool AppendAttachment(
const base::FilePath& attachment, const std::string& data);

//! \brief Removes a file from the list of files to be attached to the crash
//! report.
//!
Expand Down
29 changes: 29 additions & 0 deletions client/crashpad_client_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/futex.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/socket.h>
Expand All @@ -38,6 +39,7 @@
#include "third_party/lss/lss.h"
#include "util/file/file_io.h"
#include "util/file/filesystem.h"
#include "util/file/file_writer.h"
#include "util/linux/exception_handler_client.h"
#include "util/linux/exception_information.h"
#include "util/linux/scoped_pr_set_dumpable.h"
Expand Down Expand Up @@ -832,6 +834,33 @@ void CrashpadClient::AddAttachment(const base::FilePath& attachment) {
signal_handler->AddAttachment(attachment);
}

bool CrashpadClient::WriteAttachment(const base::FilePath& attachment,
const std::string& data) {
FileWriter writer;
if (!writer.Open(attachment,
FileWriteMode::kTruncateOrCreate,
FilePermissions::kOwnerOnly) ||
!writer.Write(data.data(), data.size())) {
LOG(ERROR) << "failed to write attachment " << attachment;
return false;
}
return true;
}

bool CrashpadClient::AppendAttachment(const base::FilePath& attachment,
const std::string& data) {
FileWriter writer;
if (!writer.Open(attachment,
FileWriteMode::kReuseOrCreate,
FilePermissions::kOwnerOnly) ||
writer.Seek(0, SEEK_END) < 0 ||
!writer.Write(data.data(), data.size())) {
LOG(ERROR) << "failed to write attachment " << attachment;
return false;
}
return true;
}

void CrashpadClient::RemoveAttachment(const base::FilePath& attachment) {
auto signal_handler = RequestCrashDumpHandler::Get();
signal_handler->RemoveAttachment(attachment);
Expand Down
29 changes: 29 additions & 0 deletions client/crashpad_client_mac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <mach/mach.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>

#include <memory>
Expand All @@ -29,6 +30,7 @@
#include "base/check_op.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "util/file/file_writer.h"
#include "util/mac/mac_util.h"
#include "util/mach/bootstrap.h"
#include "util/mach/child_port_handshake.h"
Expand Down Expand Up @@ -637,6 +639,33 @@ void CrashpadClient::AddAttachment(const base::FilePath& attachment) {
attachment.value());
}

bool CrashpadClient::WriteAttachment(const base::FilePath& attachment,
const std::string& data) {
FileWriter writer;
if (!writer.Open(attachment,
FileWriteMode::kTruncateOrCreate,
FilePermissions::kOwnerOnly) ||
!writer.Write(data.data(), data.size())) {
LOG(ERROR) << "failed to write attachment " << attachment;
return false;
}
return true;
}

bool CrashpadClient::AppendAttachment(const base::FilePath& attachment,
const std::string& data) {
FileWriter writer;
if (!writer.Open(attachment,
FileWriteMode::kReuseOrCreate,
FilePermissions::kOwnerOnly) ||
writer.Seek(0, SEEK_END) < 0 ||
!writer.Write(data.data(), data.size())) {
LOG(ERROR) << "failed to write attachment " << attachment;
return false;
}
return true;
}

void CrashpadClient::RemoveAttachment(const base::FilePath& attachment) {
SendClientToServerMessage(exception_port_.get(),
ClientToServerMessage::kRemoveAttachment,
Expand Down
106 changes: 98 additions & 8 deletions client/crashpad_client_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1216,19 +1216,109 @@
}

void CrashpadClient::AddAttachment(const base::FilePath& attachment) {
const size_t path_length_bytes =
(attachment.value().length() + 1) * sizeof(wchar_t);
if (path_length_bytes > kMaxPathBytes) {
LOG(ERROR) << "Path too long: " << path_length_bytes << " bytes";
return;
}

ClientToServerMessage message = {};
message.type = ClientToServerMessage::kAddAttachmentV2;
message.attachment_v2.path_length_bytes =
static_cast<uint32_t>(path_length_bytes);

ServerToClientMessage response = {};
SendPayloadToCrashHandlerServer(ipc_pipe_,
message,
attachment.value().c_str(),
static_cast<uint32_t>(path_length_bytes),
&response);
}

bool CrashpadClient::WriteAttachment(const base::FilePath& attachment,
const std::string& data) {
const size_t path_length_bytes =
(attachment.value().length() + 1) * sizeof(wchar_t);
if (path_length_bytes > kMaxPathBytes ||
data.size() > kMaxAttachmentPayloadBytes ||
data.size() > UINT32_MAX - path_length_bytes) {
LOG(ERROR) << "attachment content too large";
return false;
}

ClientToServerMessage message = {};
message.type = ClientToServerMessage::kWriteAttachment;
message.attachment_write.path_length_bytes =
static_cast<uint32_t>(path_length_bytes);
message.attachment_write.payload_length_bytes =
static_cast<uint32_t>(data.size());

std::string payload(path_length_bytes + data.size(), '\0');
memcpy(&payload[0], attachment.value().c_str(), path_length_bytes);
if (!data.empty()) {
memcpy(&payload[path_length_bytes], data.data(), data.size());
}

ServerToClientMessage response = {};
SendAttachmentToCrashHandlerServer(ipc_pipe_,
ClientToServerMessage::kAddAttachmentV2,
attachment.value(),
&response);
return SendPayloadToCrashHandlerServer(ipc_pipe_,
message,
payload.data(),
static_cast<uint32_t>(payload.size()),
&response);
Comment thread
jpnurmi marked this conversation as resolved.
}

bool CrashpadClient::AppendAttachment(const base::FilePath& attachment,
const std::string& data) {
const size_t path_length_bytes =
(attachment.value().length() + 1) * sizeof(wchar_t);
if (path_length_bytes > kMaxPathBytes ||
data.size() > kMaxAttachmentPayloadBytes ||
data.size() > UINT32_MAX - path_length_bytes) {
LOG(ERROR) << "attachment content too large";
return false;
}

ClientToServerMessage message = {};
message.type = ClientToServerMessage::kAppendAttachment;
message.attachment_write.path_length_bytes =
static_cast<uint32_t>(path_length_bytes);
message.attachment_write.payload_length_bytes =
Comment thread
jpnurmi marked this conversation as resolved.
static_cast<uint32_t>(data.size());

std::string payload(path_length_bytes + data.size(), '\0');
memcpy(&payload[0], attachment.value().c_str(), path_length_bytes);
if (!data.empty()) {
memcpy(&payload[path_length_bytes], data.data(), data.size());
}

ServerToClientMessage response = {};
return SendPayloadToCrashHandlerServer(ipc_pipe_,
message,
payload.data(),
static_cast<uint32_t>(payload.size()),
&response);
}

Check failure on line 1302 in client/crashpad_client_win.cc

View check run for this annotation

@sentry/warden / warden: security-review

[Y9U-VTK] Arbitrary file write via IPC: no path validation and no caller identity check in prestarted handler mode (additional location)

The new `kWriteAttachment`/`kAppendAttachment` IPC handlers write caller-supplied data to a caller-supplied file path with no restriction on which paths are permitted; when the handler runs in prestarted named-pipe mode (`owner_process_id_ == kNoOwnerProcessId`), `RuntimeMessageOriginIsOwner` always returns `true`, so any process that can connect to the pipe can overwrite arbitrary files accessible to the handler process.
void CrashpadClient::RemoveAttachment(const base::FilePath& attachment) {
const size_t path_length_bytes =
(attachment.value().length() + 1) * sizeof(wchar_t);
if (path_length_bytes > kMaxPathBytes) {
LOG(ERROR) << "Path too long: " << path_length_bytes << " bytes";
return;
}

ClientToServerMessage message = {};
message.type = ClientToServerMessage::kRemoveAttachmentV2;
message.attachment_v2.path_length_bytes =
static_cast<uint32_t>(path_length_bytes);

ServerToClientMessage response = {};
SendAttachmentToCrashHandlerServer(ipc_pipe_,
ClientToServerMessage::kRemoveAttachmentV2,
attachment.value(),
&response);
SendPayloadToCrashHandlerServer(ipc_pipe_,
message,
attachment.value().c_str(),
static_cast<uint32_t>(path_length_bytes),
&response);
}

void CrashpadClient::RequestRetry() {
Expand Down
25 changes: 25 additions & 0 deletions handler/win/crash_report_exception_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,34 @@
attachments_.push_back(attachment);
}

void CrashReportExceptionHandler::ExceptionHandlerServerAttachmentWritten(
const base::FilePath& attachment, const std::string& data) {
FileWriter writer;
if (!writer.Open(attachment,
FileWriteMode::kTruncateOrCreate,
FilePermissions::kOwnerOnly) ||
!writer.Write(data.data(), data.size())) {
LOG(ERROR) << "failed to write attachment " << attachment;
return;
}
}

void CrashReportExceptionHandler::ExceptionHandlerServerAttachmentAppended(
const base::FilePath& attachment, const std::string& data) {
FileWriter writer;
if (!writer.Open(attachment,
FileWriteMode::kReuseOrCreate,
FilePermissions::kOwnerOnly) ||
writer.Seek(0, SEEK_END) < 0 ||
!writer.Write(data.data(), data.size())) {
LOG(ERROR) << "failed to write attachment " << attachment;
return;
}
}

void CrashReportExceptionHandler::ExceptionHandlerServerAttachmentRemoved(
const base::FilePath& attachment) {
auto it = std::find(attachments_.begin(), attachments_.end(), attachment);

Check failure on line 237 in handler/win/crash_report_exception_handler.cc

View check run for this annotation

@sentry/warden / warden: security-review

[Y9U-VTK] Arbitrary file write via IPC: no path validation and no caller identity check in prestarted handler mode (additional location)

The new `kWriteAttachment`/`kAppendAttachment` IPC handlers write caller-supplied data to a caller-supplied file path with no restriction on which paths are permitted; when the handler runs in prestarted named-pipe mode (`owner_process_id_ == kNoOwnerProcessId`), `RuntimeMessageOriginIsOwner` always returns `true`, so any process that can connect to the pipe can overwrite arbitrary files accessible to the handler process.
if (it == attachments_.end()) {
LOG(WARNING) << "ignoring non-existent attachment " << attachment;
return;
Expand Down
4 changes: 4 additions & 0 deletions handler/win/crash_report_exception_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@
WinVMAddress exception_information_address,
WinVMAddress debug_critical_section_address) override;
void ExceptionHandlerServerAttachmentAdded(
const base::FilePath& attachment) override;
void ExceptionHandlerServerAttachmentWritten(
const base::FilePath& attachment, const std::string& data) override;
void ExceptionHandlerServerAttachmentAppended(

Check failure on line 90 in handler/win/crash_report_exception_handler.h

View check run for this annotation

@sentry/warden / warden: security-review

Arbitrary file write via IPC: no path validation and no caller identity check in prestarted handler mode

The new `kWriteAttachment`/`kAppendAttachment` IPC handlers write caller-supplied data to a caller-supplied file path with no restriction on which paths are permitted; when the handler runs in prestarted named-pipe mode (`owner_process_id_ == kNoOwnerProcessId`), `RuntimeMessageOriginIsOwner` always returns `true`, so any process that can connect to the pipe can overwrite arbitrary files accessible to the handler process.
const base::FilePath& attachment, const std::string& data) override;
void ExceptionHandlerServerAttachmentRemoved(
const base::FilePath& attachment) override;
void ExceptionHandlerServerRetryRequested() override;
Expand Down
109 changes: 109 additions & 0 deletions util/win/exception_handler_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,99 @@
LoggingWriteFile(service_context.pipe(), &response, sizeof(response));
}

static bool ReadAttachment(
const internal::PipeServiceContext& service_context,
const ClientToServerMessage& message,
base::FilePath* attachment,
std::string* payload) {
const uint32_t path_length_bytes =
message.attachment_write.path_length_bytes;
const uint32_t payload_length_bytes =
message.attachment_write.payload_length_bytes;

if (path_length_bytes == 0 || path_length_bytes > kMaxPathBytes ||
path_length_bytes % sizeof(wchar_t) != 0) {
LOG(ERROR) << "Invalid path length: " << path_length_bytes;
return false;
}
if (payload_length_bytes > kMaxAttachmentPayloadBytes) {
LOG(ERROR) << "Invalid attachment payload length: "
<< payload_length_bytes;
return false;
}
if (payload_length_bytes > UINT32_MAX - path_length_bytes) {
LOG(ERROR) << "Invalid attachment write length";
return false;
}

const uint32_t request_payload_length_bytes =
path_length_bytes + payload_length_bytes;
std::string request_payload(request_payload_length_bytes, '\0');
if (!LoggingReadFileExactly(
service_context.pipe(),
&request_payload[0],
request_payload_length_bytes)) {
LOG(ERROR) << "Failed to read attachment write";
return false;
}

const size_t path_length = path_length_bytes / sizeof(wchar_t) - 1;
std::wstring path(path_length, L'\0');
if (path_length > 0) {
memcpy(&path[0],
request_payload.data(),
path_length_bytes - sizeof(wchar_t));
}

*attachment = base::FilePath(path);
*payload =
std::string(request_payload.data() + path_length_bytes,
payload_length_bytes);
return true;
}

static void HandleWriteAttachment(
const internal::PipeServiceContext& service_context,
const ClientToServerMessage& message) {
base::FilePath attachment;
std::string payload;
if (!ReadAttachment(
service_context, message, &attachment, &payload)) {
return;
}
Comment thread
jpnurmi marked this conversation as resolved.

// Acknowledge IPC payload acceptance before disk I/O. This message exists to
// offload potentially slow disk I/O from the client; waiting for the file
// write would make the client block on the work this API is meant to avoid.
ServerToClientMessage response = {};
if (!LoggingWriteFile(service_context.pipe(), &response, sizeof(response))) {
return;
}

Check failure on line 598 in util/win/exception_handler_server.cc

View check run for this annotation

@sentry/warden / warden: security-review

[Y9U-VTK] Arbitrary file write via IPC: no path validation and no caller identity check in prestarted handler mode (additional location)

The new `kWriteAttachment`/`kAppendAttachment` IPC handlers write caller-supplied data to a caller-supplied file path with no restriction on which paths are permitted; when the handler runs in prestarted named-pipe mode (`owner_process_id_ == kNoOwnerProcessId`), `RuntimeMessageOriginIsOwner` always returns `true`, so any process that can connect to the pipe can overwrite arbitrary files accessible to the handler process.
service_context.delegate()->ExceptionHandlerServerAttachmentWritten(
attachment, payload);
Comment thread
jpnurmi marked this conversation as resolved.
}

static void HandleAppendAttachment(
const internal::PipeServiceContext& service_context,
const ClientToServerMessage& message) {
base::FilePath attachment;
std::string payload;
if (!ReadAttachment(
service_context, message, &attachment, &payload)) {
return;
}

// Acknowledge IPC payload acceptance before disk I/O. This message exists to
// offload potentially slow disk I/O from the client; waiting for the file
// append would make the client block on the work this API is meant to avoid.
ServerToClientMessage response = {};
if (!LoggingWriteFile(service_context.pipe(), &response, sizeof(response))) {
return;
}
service_context.delegate()->ExceptionHandlerServerAttachmentAppended(
attachment, payload);
}

// This function must be called with service_context.pipe() already connected to
// a client pipe. It exchanges data with the client and adds a ClientData record
// to service_context->clients().
Expand Down Expand Up @@ -611,6 +704,22 @@
return false;
}

case ClientToServerMessage::kWriteAttachment: {
if (!RuntimeMessageOriginIsOwner(service_context)) {
return false;
}
HandleWriteAttachment(service_context, message);
return false;
}

case ClientToServerMessage::kAppendAttachment: {
if (!RuntimeMessageOriginIsOwner(service_context)) {
return false;
}
HandleAppendAttachment(service_context, message);
return false;

Check failure on line 720 in util/win/exception_handler_server.cc

View check run for this annotation

@sentry/warden / warden: security-review

[Y9U-VTK] Arbitrary file write via IPC: no path validation and no caller identity check in prestarted handler mode (additional location)

The new `kWriteAttachment`/`kAppendAttachment` IPC handlers write caller-supplied data to a caller-supplied file path with no restriction on which paths are permitted; when the handler runs in prestarted named-pipe mode (`owner_process_id_ == kNoOwnerProcessId`), `RuntimeMessageOriginIsOwner` always returns `true`, so any process that can connect to the pipe can overwrite arbitrary files accessible to the handler process.
Comment thread
cursor[bot] marked this conversation as resolved.
}

case ClientToServerMessage::kRequestRetry: {
if (!RuntimeMessageOriginIsOwner(service_context)) {
return false;
Expand Down
Loading
Loading