Validate audio data instead of santinize in binder call.
In binder call, if the data is silently santinized, there may be
unexpected behavior. In that case, it is better to just validate the
data and returned error code if there is any error with the data.
Test: audio smoke test
Bug: 174189330
Change-Id: I2f0534f3013f9127a441306c3ff7d5ca8cc0e223
diff --git a/media/libmediahelper/AudioValidator.cpp b/media/libmediahelper/AudioValidator.cpp
new file mode 100644
index 0000000..e2fd8ae
--- /dev/null
+++ b/media/libmediahelper/AudioValidator.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#include <media/AudioValidator.h>
+
+namespace android {
+
+/** returns true if string is overflow */
+template <size_t size>
+bool checkStringOverflow(const char (&s)[size]) {
+ return strnlen(s, size) >= size;
+}
+
+status_t safetyNetLog(status_t status, std::string_view bugNumber) {
+ if (status != NO_ERROR && !bugNumber.empty()) {
+ android_errorWriteLog(0x534e4554, bugNumber.data()); // SafetyNet logging
+ }
+ return status;
+}
+
+status_t AudioValidator::validateAudioAttributes(
+ const audio_attributes_t& attr, std::string_view bugNumber)
+{
+ status_t status = NO_ERROR;
+ const size_t tagsMaxSize = AUDIO_ATTRIBUTES_TAGS_MAX_SIZE;
+ if (strnlen(attr.tags, tagsMaxSize) >= tagsMaxSize) {
+ status = BAD_VALUE;
+ }
+ return safetyNetLog(status, bugNumber);
+}
+
+status_t AudioValidator::validateEffectDescriptor(
+ const effect_descriptor_t& desc, std::string_view bugNumber)
+{
+ status_t status = NO_ERROR;
+ if (checkStringOverflow(desc.name)
+ | /* always */ checkStringOverflow(desc.implementor)) {
+ status = BAD_VALUE;
+ }
+ return safetyNetLog(status, bugNumber);
+}
+
+status_t AudioValidator::validateAudioPortConfig(
+ const struct audio_port_config& config, std::string_view bugNumber)
+{
+ status_t status = NO_ERROR;
+ if (config.type == AUDIO_PORT_TYPE_DEVICE &&
+ checkStringOverflow(config.ext.device.address)) {
+ status = BAD_VALUE;
+ }
+ return safetyNetLog(status, bugNumber);
+}
+
+namespace {
+
+template <typename T, std::enable_if_t<std::is_same<T, struct audio_port>::value
+ || std::is_same<T, struct audio_port_v7>::value, int> = 0>
+static status_t validateAudioPortInternal(const T& port, std::string_view bugNumber = {}) {
+ status_t status = NO_ERROR;
+ if (checkStringOverflow(port.name)) {
+ status = BAD_VALUE;
+ }
+ if (AudioValidator::validateAudioPortConfig(port.active_config) != NO_ERROR) {
+ status = BAD_VALUE;
+ }
+ if (port.type == AUDIO_PORT_TYPE_DEVICE &&
+ checkStringOverflow(port.ext.device.address)) {
+ status = BAD_VALUE;
+ }
+ return safetyNetLog(status, bugNumber);
+}
+
+} // namespace
+
+status_t AudioValidator::validateAudioPort(
+ const struct audio_port& port, std::string_view bugNumber)
+{
+ return validateAudioPortInternal(port, bugNumber);
+}
+
+status_t AudioValidator::validateAudioPort(
+ const struct audio_port_v7& port, std::string_view bugNumber)
+{
+ return validateAudioPortInternal(port, bugNumber);
+}
+
+/** returns BAD_VALUE if sanitization was required. */
+status_t AudioValidator::validateAudioPatch(
+ const struct audio_patch& patch, std::string_view bugNumber)
+{
+ status_t status = NO_ERROR;
+ if (patch.num_sources > AUDIO_PATCH_PORTS_MAX) {
+ status = BAD_VALUE;
+ }
+ if (patch.num_sinks > AUDIO_PATCH_PORTS_MAX) {
+ status = BAD_VALUE;
+ }
+ for (size_t i = 0; i < patch.num_sources; i++) {
+ if (validateAudioPortConfig(patch.sources[i]) != NO_ERROR) {
+ status = BAD_VALUE;
+ }
+ }
+ for (size_t i = 0; i < patch.num_sinks; i++) {
+ if (validateAudioPortConfig(patch.sinks[i]) != NO_ERROR) {
+ status = BAD_VALUE;
+ }
+ }
+ return safetyNetLog(status, bugNumber);
+}
+
+}; // namespace android