compat: libc: Add pthread_mutex_destroy hack for camera

In Pie, Google added checks to prevent destroying of the same mutexes
consecutively, and aborts the program on fortify fatal call.

Our camera blobs trigger this check when tearing down an ISP session,
destroying the same mutex consecutively by adding a destroy instruction
in a loop. This causes the whole daemon to crash and fail.

(Specifically, the violating instructions were from isp_module_stop_session
and when isp_module_start_session fails to create a thread.)

Workaround the issue by shimming the function; catching destroyed
mutexes and returning -EBUSY without passing on the bad mutexes to libc.

Change-Id: I4f8542a496dc25c53f8208a647cc0d6acc8662eb
This commit is contained in:
Nich 2018-08-20 21:40:21 +08:00 committed by Jan Altensen (Stricted)
parent ae85aa2b64
commit ca8a75680f
2 changed files with 91 additions and 0 deletions

View file

@ -15,6 +15,19 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bionic/pthread_mutex_destroy.cpp
LOCAL_SHARED_LIBRARIES := libc
LOCAL_MODULE := libshim_mutexdestroy
LOCAL_VENDOR_MODULE := true
LOCAL_CXX_STL := none
LOCAL_SANITIZE := never
LOCAL_MODULE_TAGS := optional
LOCAL_32_BIT_ONLY := true
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bionic/pthread_cond_timedwait.cpp

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <pthread.h>
#include <dlfcn.h>
#include <errno.h>
#include <limits.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/mman.h>
#include <unistd.h>
struct pthread_mutex_internal_t {
_Atomic(uint16_t) state;
// padding to align with pthread_mutex_t
// size is 40 bytes in 64 bit
// size is 4 bytes in 32 bit (satisfied)
#if defined(__LP64__)
char __reserved[36];
#endif
} __attribute__((aligned(4)));
static_assert(sizeof(pthread_mutex_t) == sizeof(pthread_mutex_internal_t),
"pthread_mutex_t should actually be pthread_mutex_internal_t in implementation.");
// For binary compatibility with old version of pthread_mutex_t, we can't use more strict alignment
// than 4-byte alignment.
static_assert(alignof(pthread_mutex_t) == 4,
"pthread_mutex_t should fulfill the alignment of pthread_mutex_internal_t.");
static inline pthread_mutex_internal_t* __get_internal_mutex(pthread_mutex_t* mutex_interface) {
return reinterpret_cast<pthread_mutex_internal_t*>(mutex_interface);
}
static inline __always_inline bool IsMutexDestroyed(uint16_t mutex_state) {
return mutex_state == 0xffff;
}
int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
if (__predict_false(IsMutexDestroyed(old_state))) {
// Mutex destroyed? Done! Don't explode.
return EBUSY;
}
int (*real_pthread_mutex_destroy)(pthread_mutex_t*);
*(void **)&real_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy");
return real_pthread_mutex_destroy(mutex_interface);
}