You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
13 KiB

/******************************************************************************
*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*****************************************************************************
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
#include <fuzzer/FuzzedDataProvider.h>
#include <stdio.h>
#include <AAudioService.h>
#include <aaudio/AAudio.h>
#include "aaudio/BnAAudioClient.h"
#include <android/content/AttributionSourceState.h>
#define UNUSED_PARAM __attribute__((unused))
using namespace android;
using namespace aaudio;
aaudio_format_t kAAudioFormats[] = {
AAUDIO_FORMAT_UNSPECIFIED,
AAUDIO_FORMAT_PCM_I16,
AAUDIO_FORMAT_PCM_FLOAT,
};
aaudio_usage_t kAAudioUsages[] = {
AAUDIO_USAGE_MEDIA,
AAUDIO_USAGE_VOICE_COMMUNICATION,
AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
AAUDIO_USAGE_ALARM,
AAUDIO_USAGE_NOTIFICATION,
AAUDIO_USAGE_NOTIFICATION_RINGTONE,
AAUDIO_USAGE_NOTIFICATION_EVENT,
AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
AAUDIO_USAGE_ASSISTANCE_SONIFICATION,
AAUDIO_USAGE_GAME,
AAUDIO_USAGE_ASSISTANT,
AAUDIO_SYSTEM_USAGE_EMERGENCY,
AAUDIO_SYSTEM_USAGE_SAFETY,
AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS,
AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT,
};
aaudio_content_type_t kAAudioContentTypes[] = {
AAUDIO_CONTENT_TYPE_SPEECH,
AAUDIO_CONTENT_TYPE_MUSIC,
AAUDIO_CONTENT_TYPE_MOVIE,
AAUDIO_CONTENT_TYPE_SONIFICATION,
};
aaudio_input_preset_t kAAudioInputPresets[] = {
AAUDIO_INPUT_PRESET_GENERIC, AAUDIO_INPUT_PRESET_CAMCORDER,
AAUDIO_INPUT_PRESET_VOICE_RECOGNITION, AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION,
AAUDIO_INPUT_PRESET_UNPROCESSED, AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE,
};
const size_t kNumAAudioFormats = std::size(kAAudioFormats);
const size_t kNumAAudioUsages = std::size(kAAudioUsages);
const size_t kNumAAudioContentTypes = std::size(kAAudioContentTypes);
const size_t kNumAAudioInputPresets = std::size(kAAudioInputPresets);
class FuzzAAudioClient : public virtual RefBase, public AAudioServiceInterface {
public:
FuzzAAudioClient(sp<AAudioService> service);
virtual ~FuzzAAudioClient();
AAudioServiceInterface *getAAudioService();
void dropAAudioService();
void registerClient(const sp<IAAudioClient> &client UNUSED_PARAM) override {}
aaudio_handle_t openStream(const AAudioStreamRequest &request,
AAudioStreamConfiguration &configurationOutput) override;
aaudio_result_t closeStream(aaudio_handle_t streamHandle) override;
aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
AudioEndpointParcelable &parcelable) override;
aaudio_result_t startStream(aaudio_handle_t streamHandle) override;
aaudio_result_t pauseStream(aaudio_handle_t streamHandle) override;
aaudio_result_t stopStream(aaudio_handle_t streamHandle) override;
aaudio_result_t flushStream(aaudio_handle_t streamHandle) override;
aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId,
int64_t periodNanoseconds) override;
aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) override;
aaudio_result_t startClient(aaudio_handle_t streamHandle UNUSED_PARAM,
const AudioClient &client UNUSED_PARAM,
const audio_attributes_t *attr UNUSED_PARAM,
audio_port_handle_t *clientHandle UNUSED_PARAM) override {
return AAUDIO_ERROR_UNAVAILABLE;
}
aaudio_result_t stopClient(aaudio_handle_t streamHandle UNUSED_PARAM,
audio_port_handle_t clientHandle UNUSED_PARAM) override {
return AAUDIO_ERROR_UNAVAILABLE;
}
void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {}
int getDeathCount() { return mDeathCount; }
void incDeathCount() { ++mDeathCount; }
class AAudioClient : public IBinder::DeathRecipient, public BnAAudioClient {
public:
AAudioClient(wp<FuzzAAudioClient> fuzzAAudioClient) : mBinderClient(fuzzAAudioClient) {}
virtual void binderDied(const wp<IBinder> &who UNUSED_PARAM) {
sp<FuzzAAudioClient> client = mBinderClient.promote();
if (client.get()) {
client->dropAAudioService();
client->incDeathCount();
}
}
android::binder::Status onStreamChange(int32_t handle, int32_t opcode, int32_t value) {
static_assert(std::is_same_v<aaudio_handle_t, int32_t>);
android::sp<FuzzAAudioClient> client = mBinderClient.promote();
if (client.get() != nullptr) {
client->onStreamChange(handle, opcode, value);
}
return android::binder::Status::ok();
}
private:
wp<FuzzAAudioClient> mBinderClient;
};
private:
sp<AAudioService> mAAudioService;
sp<AAudioClient> mAAudioClient;
AAudioServiceInterface *mAAudioServiceInterface;
int mDeathCount;
};
FuzzAAudioClient::FuzzAAudioClient(sp<AAudioService> service) : AAudioServiceInterface() {
mAAudioService = service;
mAAudioServiceInterface = &service->asAAudioServiceInterface();
mAAudioClient = new AAudioClient(this);
mDeathCount = 0;
if (mAAudioClient.get() && mAAudioService.get()) {
mAAudioService->linkToDeath(mAAudioClient);
mAAudioService->registerClient(mAAudioClient);
}
}
FuzzAAudioClient::~FuzzAAudioClient() { dropAAudioService(); }
AAudioServiceInterface *FuzzAAudioClient::getAAudioService() {
if (!mAAudioServiceInterface && mAAudioService.get()) {
mAAudioServiceInterface = &mAAudioService->asAAudioServiceInterface();
}
return mAAudioServiceInterface;
}
void FuzzAAudioClient::dropAAudioService() {
mAAudioService.clear();
}
aaudio_handle_t FuzzAAudioClient::openStream(const AAudioStreamRequest &request,
AAudioStreamConfiguration &configurationOutput) {
aaudio_handle_t stream;
for (int i = 0; i < 2; ++i) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
stream = service->openStream(request, configurationOutput);
if (stream == AAUDIO_ERROR_NO_SERVICE) {
dropAAudioService();
} else {
break;
}
}
return stream;
}
aaudio_result_t FuzzAAudioClient::closeStream(aaudio_handle_t streamHandle) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->closeStream(streamHandle);
}
aaudio_result_t FuzzAAudioClient::getStreamDescription(aaudio_handle_t streamHandle,
AudioEndpointParcelable &parcelable) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->getStreamDescription(streamHandle, parcelable);
}
aaudio_result_t FuzzAAudioClient::startStream(aaudio_handle_t streamHandle) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->startStream(streamHandle);
}
aaudio_result_t FuzzAAudioClient::pauseStream(aaudio_handle_t streamHandle) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->pauseStream(streamHandle);
}
aaudio_result_t FuzzAAudioClient::stopStream(aaudio_handle_t streamHandle) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->stopStream(streamHandle);
}
aaudio_result_t FuzzAAudioClient::flushStream(aaudio_handle_t streamHandle) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->flushStream(streamHandle);
}
aaudio_result_t FuzzAAudioClient::registerAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId,
int64_t periodNanoseconds) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->registerAudioThread(streamHandle, clientThreadId, periodNanoseconds);
}
aaudio_result_t FuzzAAudioClient::unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) {
AAudioServiceInterface *service = getAAudioService();
if (!service) {
return AAUDIO_ERROR_NO_SERVICE;
}
return service->unregisterAudioThread(streamHandle, clientThreadId);
}
class OboeserviceFuzzer {
public:
OboeserviceFuzzer();
~OboeserviceFuzzer() = default;
void process(const uint8_t *data, size_t size);
private:
sp<FuzzAAudioClient> mClient;
};
OboeserviceFuzzer::OboeserviceFuzzer() {
sp<AAudioService> service = new AAudioService();
mClient = new FuzzAAudioClient(service);
}
void OboeserviceFuzzer::process(const uint8_t *data, size_t size) {
FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
AAudioStreamRequest request;
AAudioStreamConfiguration configurationOutput;
// Initialize stream request
request.getConfiguration().setFormat((audio_format_t)(
fdp.ConsumeBool()
? fdp.ConsumeIntegral<int32_t>()
: kAAudioFormats[fdp.ConsumeIntegralInRange<int32_t>(0, kNumAAudioFormats - 1)]));
// TODO b/182392769: use attribution source util
android::content::AttributionSourceState attributionSource;
attributionSource.uid = getuid();
attributionSource.pid = getpid();
attributionSource.token = sp<BBinder>::make();
request.setAttributionSource(attributionSource);
request.setInService(fdp.ConsumeBool());
request.getConfiguration().setDeviceId(fdp.ConsumeIntegral<int32_t>());
request.getConfiguration().setSampleRate(fdp.ConsumeIntegral<int32_t>());
request.getConfiguration().setSamplesPerFrame(fdp.ConsumeIntegral<int32_t>());
request.getConfiguration().setDirection(
fdp.ConsumeBool() ? fdp.ConsumeIntegral<int32_t>()
: (fdp.ConsumeBool() ? AAUDIO_DIRECTION_OUTPUT : AAUDIO_DIRECTION_INPUT));
request.getConfiguration().setSharingMode(
fdp.ConsumeBool()
? fdp.ConsumeIntegral<int32_t>()
: (fdp.ConsumeBool() ? AAUDIO_SHARING_MODE_EXCLUSIVE : AAUDIO_SHARING_MODE_SHARED));
request.getConfiguration().setUsage(
fdp.ConsumeBool()
? fdp.ConsumeIntegral<int32_t>()
: kAAudioUsages[fdp.ConsumeIntegralInRange<int32_t>(0, kNumAAudioUsages - 1)]);
request.getConfiguration().setContentType(
fdp.ConsumeBool() ? fdp.ConsumeIntegral<int32_t>()
: kAAudioContentTypes[fdp.ConsumeIntegralInRange<int32_t>(
0, kNumAAudioContentTypes - 1)]);
request.getConfiguration().setInputPreset(
fdp.ConsumeBool() ? fdp.ConsumeIntegral<int32_t>()
: kAAudioInputPresets[fdp.ConsumeIntegralInRange<int32_t>(
0, kNumAAudioInputPresets - 1)]);
request.getConfiguration().setPrivacySensitive(fdp.ConsumeBool());
request.getConfiguration().setBufferCapacity(fdp.ConsumeIntegral<int32_t>());
aaudio_handle_t stream = mClient->openStream(request, configurationOutput);
if (stream < 0) {
// invalid request, stream not opened.
return;
}
while (fdp.remaining_bytes()) {
AudioEndpointParcelable audioEndpointParcelable;
int action = fdp.ConsumeIntegralInRange<int32_t>(0, 4);
switch (action) {
case 0:
mClient->getStreamDescription(stream, audioEndpointParcelable);
break;
case 1:
mClient->startStream(stream);
break;
case 2:
mClient->pauseStream(stream);
break;
case 3:
mClient->stopStream(stream);
break;
case 4:
mClient->flushStream(stream);
break;
}
}
mClient->closeStream(stream);
assert(mClient->getDeathCount() == 0);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 1) {
return 0;
}
OboeserviceFuzzer oboeserviceFuzzer;
oboeserviceFuzzer.process(data, size);
return 0;
}