Commit message: None
CVE: CVE-2016-0828
CWE: CWE-254
Vulnerability description: The BnGraphicBufferConsumer::onTransact function in libs/gui/IGraphicBufferConsumer.cpp in mediaserver in Android 5.x before 5.1.1 LMY49H and 6.x before 2016-03-01 does not initialize a certain slot variable, which allows attackers to obtain sensitive information, and consequently bypass an unspecified protection mechanism, by triggering an ATTACH_BUFFER action, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 26338113.

Project: Android

 virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) {
 Parcel data, reply;
        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
        data.writeStrongBinder(consumer->asBinder());
        data.writeInt32(controlledByApp);
 status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply);
 if (result != NO_ERROR) {
 return result;
 }
 return reply.readInt32();
 }

Project: Android

status_t IGraphicBufferConsumer::BufferItem::flatten(
 void*& buffer, size_t& size, int*& fds, size_t& count) const {

 if (size < BufferItem::getFlattenedSize()) {
 return NO_MEMORY;
 }

 uint32_t& flags = *static_cast<uint32_t*>(buffer);

 FlattenableUtils::advance(buffer, size, sizeof(uint32_t));

    flags = 0;
 if (mGraphicBuffer != 0) {
 status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
 if (err) return err;
        size -= FlattenableUtils::align<4>(buffer);
        flags |= 1;
 }
 if (mFence != 0) {
 status_t err = mFence->flatten(buffer, size, fds, count);
 if (err) return err;
        size -= FlattenableUtils::align<4>(buffer);
        flags |= 2;
 }

 if (size < getPodSize()) {
 return NO_MEMORY;
 }

 FlattenableUtils::write(buffer, size, mCrop);
 FlattenableUtils::write(buffer, size, mTransform);
 FlattenableUtils::write(buffer, size, mScalingMode);
 FlattenableUtils::write(buffer, size, mTimestamp);
    writeBoolAsInt(buffer, size, mIsAutoTimestamp);
 FlattenableUtils::write(buffer, size, mFrameNumber);
 FlattenableUtils::write(buffer, size, mBuf);
    writeBoolAsInt(buffer, size, mIsDroppable);
    writeBoolAsInt(buffer, size, mAcquireCalled);
    writeBoolAsInt(buffer, size, mTransformToDisplayInverse);

 return NO_ERROR;
}

Project: Android

size_t IGraphicBufferConsumer::BufferItem::getFdCount() const {
 size_t c = 0;
 if (mGraphicBuffer != 0) {
        c += mGraphicBuffer->getFdCount();
 }
 if (mFence != 0) {
        c += mFence->getFdCount();
 }
 return c;
}

Project: Android

size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const {
 size_t c = 0;
 if (mGraphicBuffer != 0) {
        c += mGraphicBuffer->getFlattenedSize();
        c = FlattenableUtils::align<4>(c);
 }
 if (mFence != 0) {
        c += mFence->getFlattenedSize();
        c = FlattenableUtils::align<4>(c);
 }
 return sizeof(int32_t) + c + getPodSize();
}

Project: Android

size_t IGraphicBufferConsumer::BufferItem::getPodSize() const {
 size_t c = sizeof(mCrop) +
 sizeof(mTransform) +
 sizeof(mScalingMode) +
 sizeof(mTimestamp) +
 sizeof(mIsAutoTimestamp) +
 sizeof(mFrameNumber) +
 sizeof(mBuf) +
 sizeof(mIsDroppable) +
 sizeof(mAcquireCalled) +
 sizeof(mTransformToDisplayInverse);
 return c;
}

Project: Android

 virtual status_t getReleasedBuffers(uint64_t* slotMask) {
 Parcel data, reply;
 if (slotMask == NULL) {
            ALOGE("getReleasedBuffers: slotMask must not be NULL");
 return BAD_VALUE;
 }
        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
 status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply);
 if (result != NO_ERROR) {
 return result;
 }
 *slotMask = reply.readInt64();
 return reply.readInt32();
 }

Project: Android

static bool readBoolFromInt(void const*& buffer, size_t& size) {
 int32_t i;
 FlattenableUtils::read(buffer, size, i);
 return static_cast<bool>(i);
}

Project: Android

 virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
 EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)),
 const sp<Fence>& releaseFence) {
 Parcel data, reply;
        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
        data.writeInt32(buf);
        data.writeInt64(frameNumber);
        data.write(*releaseFence);
 status_t result = remote()->transact(RELEASE_BUFFER, data, &reply);
 if (result != NO_ERROR) {
 return result;
 }
 return reply.readInt32();
 }

Project: Android

 virtual status_t setConsumerUsageBits(uint32_t usage) {
 Parcel data, reply;
        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
        data.writeInt32(usage);
 status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply);
 if (result != NO_ERROR) {
 return result;
 }
 return reply.readInt32();
 }

Project: Android

 virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) {
 Parcel data, reply;
        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
        data.writeInt32(defaultFormat);
 status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply);
 if (result != NO_ERROR) {
 return result;
 }
 return reply.readInt32();
 }

Project: Android

 virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) {
 Parcel data, reply;
        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
        data.writeInt32(w);
        data.writeInt32(h);
 status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply);
 if (result != NO_ERROR) {
 return result;
 }
 return reply.readInt32();
 }

Project: Android

 virtual status_t setTransformHint(uint32_t hint) {
 Parcel data, reply;
        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
        data.writeInt32(hint);
 status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply);
 if (result != NO_ERROR) {
 return result;
 }
 return reply.readInt32();
 }

Project: Android

status_t IGraphicBufferConsumer::BufferItem::unflatten(
 void const*& buffer, size_t& size, int const*& fds, size_t& count) {

 if (size < sizeof(uint32_t))
 return NO_MEMORY;

 uint32_t flags = 0;
 FlattenableUtils::read(buffer, size, flags);

 if (flags & 1) {
        mGraphicBuffer = new GraphicBuffer();
 status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
 if (err) return err;
        size -= FlattenableUtils::align<4>(buffer);
 }

 if (flags & 2) {
        mFence = new Fence();
 status_t err = mFence->unflatten(buffer, size, fds, count);
 if (err) return err;
        size -= FlattenableUtils::align<4>(buffer);
 }

 if (size < getPodSize()) {
 return NO_MEMORY;
 }

 FlattenableUtils::read(buffer, size, mCrop);
 FlattenableUtils::read(buffer, size, mTransform);
 FlattenableUtils::read(buffer, size, mScalingMode);
 FlattenableUtils::read(buffer, size, mTimestamp);
    mIsAutoTimestamp = readBoolFromInt(buffer, size);
 FlattenableUtils::read(buffer, size, mFrameNumber);
 FlattenableUtils::read(buffer, size, mBuf);
    mIsDroppable = readBoolFromInt(buffer, size);
    mAcquireCalled = readBoolFromInt(buffer, size);
    mTransformToDisplayInverse = readBoolFromInt(buffer, size);

 return NO_ERROR;
}

Project: Android

static void writeBoolAsInt(void*& buffer, size_t& size, bool b) {
 FlattenableUtils::write(buffer, size, static_cast<int32_t>(b));
}