Implement BufferHubProducer::attachBuffer
1/ Introduce new kOpProducerQueueInsertBuffer operation to insert a
standalone ProducerChannel into a ProducerQueueChannel.
2/ Introduce some PDX security check against channel_id spoofing.
Bug: 69981968
Bug: 79224574
Test: buffer_hub_queue-test, libgui_test
Change-Id: I3c13e2897476c34e6e939756b079fe3440937236
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
index a5cf68d..3061805 100644
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ b/services/vr/bufferhubd/detached_buffer_channel.cpp
@@ -109,6 +109,7 @@
return BufferDescription<BorrowedHandle>{buffer_,
metadata_buffer_,
buffer_id(),
+ channel_id(),
/*buffer_state_bit=*/0,
BorrowedHandle{},
BorrowedHandle{}};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b6977aa..97af660 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -236,9 +236,13 @@
BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
uint64_t buffer_state_bit) {
- return {
- buffer_, metadata_buffer_, buffer_id(),
- buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
+ return {buffer_,
+ metadata_buffer_,
+ buffer_id(),
+ channel_id(),
+ buffer_state_bit,
+ acquire_fence_fd_.Borrow(),
+ release_fence_fd_.Borrow()};
}
Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index 67fdf15..10a4ce7 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -43,6 +43,8 @@
~ProducerChannel() override;
+ uint64_t buffer_state() const { return buffer_state_->load(); }
+
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index c0c48c2..88f5508 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -76,6 +76,11 @@
message);
return true;
+ case BufferHubRPC::ProducerQueueInsertBuffer::Opcode:
+ DispatchRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
+ *this, &ProducerQueueChannel::OnProducerQueueInsertBuffer, message);
+ return true;
+
case BufferHubRPC::ProducerQueueRemoveBuffer::Opcode:
DispatchRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(
*this, &ProducerQueueChannel::OnProducerQueueRemoveBuffer, message);
@@ -278,6 +283,81 @@
return {{std::move(buffer_handle), slot}};
}
+Status<size_t> ProducerQueueChannel::OnProducerQueueInsertBuffer(
+ pdx::Message& message, int buffer_cid) {
+ ATRACE_NAME("ProducerQueueChannel::InsertBuffer");
+ ALOGD_IF(TRACE,
+ "ProducerQueueChannel::InsertBuffer: channel_id=%d, buffer_cid=%d",
+ channel_id(), buffer_cid);
+
+ if (capacity_ >= BufferHubRPC::kMaxQueueCapacity) {
+ ALOGE("ProducerQueueChannel::InsertBuffer: reaches kMaxQueueCapacity.");
+ return ErrorStatus(E2BIG);
+ }
+ auto producer_channel = std::static_pointer_cast<ProducerChannel>(
+ service()->GetChannel(buffer_cid));
+ if (producer_channel == nullptr ||
+ producer_channel->channel_type() != BufferHubChannel::kProducerType) {
+ // Rejects the request if the requested buffer channel is invalid and/or
+ // it's not a ProducerChannel.
+ ALOGE(
+ "ProducerQueueChannel::InsertBuffer: Invalid buffer_cid=%d, "
+ "producer_buffer=0x%p, channel_type=%d.",
+ buffer_cid, producer_channel.get(),
+ producer_channel == nullptr ? -1 : producer_channel->channel_type());
+ return ErrorStatus(EINVAL);
+ }
+ if (producer_channel->GetActiveProcessId() != message.GetProcessId()) {
+ // Rejects the request if the requested buffer channel is not currently
+ // connected to the caller this is IPC request. This effectively prevents
+ // fake buffer_cid from being injected.
+ ALOGE(
+ "ProducerQueueChannel::InsertBuffer: Requested buffer channel "
+ "(buffer_cid=%d) is not connected to the calling process (pid=%d). "
+ "It's connected to a different process (pid=%d).",
+ buffer_cid, message.GetProcessId(),
+ producer_channel->GetActiveProcessId());
+ return ErrorStatus(EINVAL);
+ }
+ uint64_t buffer_state = producer_channel->buffer_state();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ // Rejects the request if the requested buffer is not in Gained state.
+ ALOGE(
+ "ProducerQueueChannel::InsertBuffer: The buffer (cid=%d, "
+ "state=0x%" PRIx64 ") is not in gained state.",
+ buffer_cid, buffer_state);
+ return ErrorStatus(EINVAL);
+ }
+
+ // Register the to-be-inserted buffer's channel_id into the first empty
+ // buffer slot.
+ size_t slot = 0;
+ for (; slot < BufferHubRPC::kMaxQueueCapacity; slot++) {
+ if (buffers_[slot].expired())
+ break;
+ }
+ if (slot == BufferHubRPC::kMaxQueueCapacity) {
+ ALOGE(
+ "ProducerQueueChannel::AllocateBuffer: Cannot find empty slot for new "
+ "buffer allocation.");
+ return ErrorStatus(E2BIG);
+ }
+
+ buffers_[slot] = producer_channel;
+ capacity_++;
+
+ // Notify each consumer channel about the new buffer.
+ for (auto* consumer_channel : consumer_channels_) {
+ ALOGD(
+ "ProducerQueueChannel::AllocateBuffer: Notified consumer with new "
+ "buffer, buffer_cid=%d",
+ buffer_cid);
+ consumer_channel->RegisterNewBuffer(producer_channel, slot);
+ }
+
+ return {slot};
+}
+
Status<void> ProducerQueueChannel::OnProducerQueueRemoveBuffer(
Message& /*message*/, size_t slot) {
if (buffers_[slot].expired()) {
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index e825f47..e4fa243 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -38,8 +38,12 @@
uint32_t format, uint64_t usage,
size_t buffer_count);
- // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must
- // be in Gain'ed state for the producer queue to detach.
+ // Inserts a BufferProducer into the queue. Note that the buffer must be in
+ // Gain'ed state for the operation to succeed.
+ pdx::Status<size_t> OnProducerQueueInsertBuffer(pdx::Message& message, int buffer_cid);
+
+ // Removes a BufferProducer indicated by |slot|. Note that the buffer must be
+ // in Gain'ed state for the operation to succeed.
pdx::Status<void> OnProducerQueueRemoveBuffer(pdx::Message& message,
size_t slot);