From 8a25a1756b5600ea65134fe8f7729228ad8c535f Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 19 Nov 2018 12:58:18 -0800 Subject: [PATCH] Preserve x18 while calling aptX encoder libraries. Shadow call stack (SCS) is a security mitigation that uses a separate stack (the SCS) for return addresses. In versions of Android newer than P, the compiler normally cooperates with the system to ensure that the SCS address is always stored in register x18. This requires that everything in a process that uses SCS is built with -ffixed-x18. However, two libraries (libaptX_encoder.so and libaptXHD_encoder.so) are supplied in binary format and were not compiled with -ffixed-x18. We are working with the vendor to get these libraries rebuilt with -ffixed-x18, but until then, we need to prevent this library from clobbering x18 so that we can turn on SCS in the Bluetooth process. Bug: 112907825 Bug: 120621517 Change-Id: Id27829ed5696903c42b4aeb75c3b3880c97a3a36 --- common/scoped_scs_exit.h | 39 +++++++++++++++++++++++++++++++ stack/a2dp/a2dp_vendor_aptx_encoder.cc | 28 ++++++++++++++++++---- stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc | 26 ++++++++++++++++++--- 3 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 common/scoped_scs_exit.h diff --git a/common/scoped_scs_exit.h b/common/scoped_scs_exit.h new file mode 100644 index 000000000..ad4a8d678 --- /dev/null +++ b/common/scoped_scs_exit.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +// Prevent x18 (shadow call stack address) from being clobbered by functions +// called by a function that declares a variable of this type by temporarily +// storing the value on the stack. This is used only when calling out to certain +// vendor libraries. +struct ScopedSCSExit { +#ifdef __aarch64__ + void* scs; + + __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ScopedSCSExit() { + __asm__ __volatile__("str x18, [%0]" ::"r"(&scs)); + } + + __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() { + __asm__ __volatile__("ldr x18, [%0]; str xzr, [%0]" ::"r"(&scs)); + } +#else + // Silence unused variable warnings in non-SCS builds. + __attribute__((no_sanitize("shadow-call-stack"))) ScopedSCSExit() {} + __attribute__((no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() {} +#endif +}; diff --git a/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_encoder.cc index 0d605c057..e7d0145e5 100644 --- a/stack/a2dp/a2dp_vendor_aptx_encoder.cc +++ b/stack/a2dp/a2dp_vendor_aptx_encoder.cc @@ -26,6 +26,7 @@ #include "a2dp_vendor.h" #include "a2dp_vendor_aptx.h" #include "bt_common.h" +#include "common/scoped_scs_exit.h" #include "common/time_util.h" #include "osi/include/log.h" #include "osi/include/osi.h" @@ -54,6 +55,25 @@ static tAPTX_ENCODER_INIT aptx_encoder_init_func; static tAPTX_ENCODER_ENCODE_STEREO aptx_encoder_encode_stereo_func; static tAPTX_ENCODER_SIZEOF_PARAMS aptx_encoder_sizeof_params_func; +__attribute__((no_sanitize("shadow-call-stack"))) +static int aptx_encoder_init(void* state, short endian) { + ScopedSCSExit x; + return aptx_encoder_init_func(state, endian); +} + +__attribute__((no_sanitize("shadow-call-stack"))) +static int aptx_encoder_encode_stereo(void* state, void* pcmL, void* pcmR, + void* buffer) { + ScopedSCSExit x; + return aptx_encoder_encode_stereo_func(state, pcmL, pcmR, buffer); +} + +__attribute__((no_sanitize("shadow-call-stack"))) +static int aptx_encoder_sizeof_params() { + ScopedSCSExit x; + return aptx_encoder_sizeof_params_func(); +} + // offset #if (BTA_AV_CO_CP_SCMS_T == TRUE) #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1) @@ -192,9 +212,9 @@ void a2dp_vendor_aptx_encoder_init( #endif a2dp_aptx_encoder_cb.aptx_encoder_state = - osi_malloc(aptx_encoder_sizeof_params_func()); + osi_malloc(aptx_encoder_sizeof_params()); if (a2dp_aptx_encoder_cb.aptx_encoder_state != NULL) { - aptx_encoder_init_func(a2dp_aptx_encoder_cb.aptx_encoder_state, 0); + aptx_encoder_init(a2dp_aptx_encoder_cb.aptx_encoder_state, 0); } else { LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX encoder state", __func__); // TODO: Return an error? @@ -466,8 +486,8 @@ static size_t aptx_encode_16bit(tAPTX_FRAMING_PARAMS* framing_params, pcmR[i] = (uint16_t) * (data16_in + ((2 * j) + 1)); } - aptx_encoder_encode_stereo_func(a2dp_aptx_encoder_cb.aptx_encoder_state, - &pcmL, &pcmR, &encoded_sample); + aptx_encoder_encode_stereo(a2dp_aptx_encoder_cb.aptx_encoder_state, &pcmL, + &pcmR, &encoded_sample); data_out[*data_out_index + 0] = (uint8_t)((encoded_sample[0] >> 8) & 0xff); data_out[*data_out_index + 1] = (uint8_t)((encoded_sample[0] >> 0) & 0xff); diff --git a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc index fb782dd8d..d271e0dde 100644 --- a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc +++ b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc @@ -26,6 +26,7 @@ #include "a2dp_vendor.h" #include "a2dp_vendor_aptx_hd.h" #include "bt_common.h" +#include "common/scoped_scs_exit.h" #include "common/time_util.h" #include "osi/include/log.h" #include "osi/include/osi.h" @@ -55,6 +56,25 @@ static tAPTX_HD_ENCODER_INIT aptx_hd_encoder_init_func; static tAPTX_HD_ENCODER_ENCODE_STEREO aptx_hd_encoder_encode_stereo_func; static tAPTX_HD_ENCODER_SIZEOF_PARAMS aptx_hd_encoder_sizeof_params_func; +__attribute__((no_sanitize("shadow-call-stack"))) +static int aptx_hd_encoder_init(void* state, short endian) { + ScopedSCSExit x; + return aptx_hd_encoder_init_func(state, endian); +} + +__attribute__((no_sanitize("shadow-call-stack"))) +static int aptx_hd_encoder_encode_stereo(void* state, void* pcmL, void* pcmR, + void* buffer) { + ScopedSCSExit x; + return aptx_hd_encoder_encode_stereo_func(state, pcmL, pcmR, buffer); +} + +__attribute__((no_sanitize("shadow-call-stack"))) +static int aptx_hd_encoder_sizeof_params() { + ScopedSCSExit x; + return aptx_hd_encoder_sizeof_params_func(); +} + // offset #if (BTA_AV_CO_CP_SCMS_T == TRUE) #define A2DP_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET + 1) @@ -193,9 +213,9 @@ void a2dp_vendor_aptx_hd_encoder_init( #endif a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state = - osi_malloc(aptx_hd_encoder_sizeof_params_func()); + osi_malloc(aptx_hd_encoder_sizeof_params()); if (a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state != NULL) { - aptx_hd_encoder_init_func(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0); + aptx_hd_encoder_init(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0); } else { LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX-HD encoder state", __func__); // TODO: Return an error? @@ -460,7 +480,7 @@ static size_t aptx_hd_encode_24bit(tAPTX_HD_FRAMING_PARAMS* framing_params, p += 3; } - aptx_hd_encoder_encode_stereo_func( + aptx_hd_encoder_encode_stereo( a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, &pcmL, &pcmR, &encoded_sample); -- 2.11.0