Based on Nekogram. Key additions: - Rebrand to FoxiGram (app name, APK name, applicationId com.foxigram.app) - Embedded Xray (VLESS+Reality) proxy client via JNI libxray.so - Bundled hidden one-tap proxies (LTE + WiFi), read-only in UI - Auto-restore proxy on restart, rebind to active network (LTE/WiFi) - Server credentials externalized to git-ignored XrayServers.java (+ template) - libxray Go source included; compiled .so, keystore, google-services.json ignored
194 lines
6.7 KiB
C++
194 lines
6.7 KiB
C++
// Copyright 2020 The BoringSSL Authors
|
|
//
|
|
// 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
|
|
//
|
|
// https://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.
|
|
|
|
#if !defined(_GNU_SOURCE)
|
|
#define _GNU_SOURCE // needed for madvise() and MAP_ANONYMOUS on Linux.
|
|
#endif
|
|
|
|
#include "../bcm_support.h"
|
|
#include "../internal.h"
|
|
#include "internal.h"
|
|
|
|
#if defined(OPENSSL_FORK_DETECTION_MADVISE)
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
#if defined(MADV_WIPEONFORK)
|
|
static_assert(MADV_WIPEONFORK == 18, "MADV_WIPEONFORK is not 18");
|
|
#else
|
|
#define MADV_WIPEONFORK 18
|
|
#endif
|
|
#elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK)
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#endif // OPENSSL_FORK_DETECTION_PTHREAD_ATFORK
|
|
|
|
#if defined(OPENSSL_FORK_DETECTION_MADVISE)
|
|
static int g_force_madv_wipeonfork;
|
|
static int g_force_madv_wipeonfork_enabled;
|
|
static CRYPTO_once_t g_fork_detect_once = CRYPTO_ONCE_INIT;
|
|
static CRYPTO_MUTEX g_fork_detect_lock = CRYPTO_MUTEX_INIT;
|
|
static CRYPTO_atomic_u32 *g_fork_detect_addr;
|
|
static uint64_t g_fork_generation;
|
|
|
|
static void init_fork_detect(void) {
|
|
if (g_force_madv_wipeonfork) {
|
|
return;
|
|
}
|
|
|
|
long page_size = sysconf(_SC_PAGESIZE);
|
|
if (page_size <= 0) {
|
|
return;
|
|
}
|
|
|
|
void *addr = mmap(NULL, (size_t)page_size, PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
if (addr == MAP_FAILED) {
|
|
return;
|
|
}
|
|
|
|
// Some versions of qemu (up to at least 5.0.0-rc4, see linux-user/syscall.c)
|
|
// ignore |madvise| calls and just return zero (i.e. success). But we need to
|
|
// know whether MADV_WIPEONFORK actually took effect. Therefore try an invalid
|
|
// call to check that the implementation of |madvise| is actually rejecting
|
|
// unknown |advice| values.
|
|
if (madvise(addr, (size_t)page_size, -1) == 0 ||
|
|
madvise(addr, (size_t)page_size, MADV_WIPEONFORK) != 0) {
|
|
munmap(addr, (size_t)page_size);
|
|
return;
|
|
}
|
|
|
|
CRYPTO_atomic_u32 *const atomic = reinterpret_cast<CRYPTO_atomic_u32 *>(addr);
|
|
CRYPTO_atomic_store_u32(atomic, 1);
|
|
g_fork_detect_addr = atomic;
|
|
g_fork_generation = 1;
|
|
}
|
|
|
|
uint64_t CRYPTO_get_fork_generation(void) {
|
|
CRYPTO_once(&g_fork_detect_once, init_fork_detect);
|
|
|
|
// In a single-threaded process, there are obviously no races because there's
|
|
// only a single mutator in the address space.
|
|
//
|
|
// In a multi-threaded environment, |CRYPTO_once| ensures that the flag byte
|
|
// is initialised atomically, even if multiple threads enter this function
|
|
// concurrently.
|
|
//
|
|
// Additionally, while the kernel will only clear WIPEONFORK at a point when a
|
|
// child process is single-threaded, the child may become multi-threaded
|
|
// before it observes this. Therefore, we must synchronize the logic below.
|
|
|
|
CRYPTO_atomic_u32 *const flag_ptr = g_fork_detect_addr;
|
|
if (flag_ptr == NULL) {
|
|
// Our kernel is too old to support |MADV_WIPEONFORK| or
|
|
// |g_force_madv_wipeonfork| is set.
|
|
if (g_force_madv_wipeonfork && g_force_madv_wipeonfork_enabled) {
|
|
// A constant generation number to simulate support, even if the kernel
|
|
// doesn't support it.
|
|
return 42;
|
|
}
|
|
// With Linux and clone(), we do not believe that pthread_atfork() is
|
|
// sufficient for detecting all forms of address space duplication. At this
|
|
// point we have a kernel that does not support MADV_WIPEONFORK. We could
|
|
// return the generation number from pthread_atfork() here and it would
|
|
// probably be safe in almost any situation, but to ensure safety we return
|
|
// 0 and force an entropy draw on every call.
|
|
return 0;
|
|
}
|
|
|
|
// In the common case, try to observe the flag without taking a lock. This
|
|
// avoids cacheline contention in the PRNG.
|
|
uint64_t *const generation_ptr = &g_fork_generation;
|
|
if (CRYPTO_atomic_load_u32(flag_ptr) != 0) {
|
|
// If we observe a non-zero flag, it is safe to read |generation_ptr|
|
|
// without a lock. The flag and generation number are fixed for this copy of
|
|
// the address space.
|
|
return *generation_ptr;
|
|
}
|
|
|
|
// The flag was zero. The generation number must be incremented, but other
|
|
// threads may have concurrently observed the zero, so take a lock before
|
|
// incrementing.
|
|
CRYPTO_MUTEX *const lock = &g_fork_detect_lock;
|
|
CRYPTO_MUTEX_lock_write(lock);
|
|
uint64_t current_generation = *generation_ptr;
|
|
if (CRYPTO_atomic_load_u32(flag_ptr) == 0) {
|
|
// A fork has occurred.
|
|
current_generation++;
|
|
if (current_generation == 0) {
|
|
// Zero means fork detection isn't supported, so skip that value.
|
|
current_generation = 1;
|
|
}
|
|
|
|
// We must update |generation_ptr| before |flag_ptr|. Other threads may
|
|
// observe |flag_ptr| without taking a lock.
|
|
*generation_ptr = current_generation;
|
|
CRYPTO_atomic_store_u32(flag_ptr, 1);
|
|
}
|
|
CRYPTO_MUTEX_unlock_write(lock);
|
|
|
|
return current_generation;
|
|
}
|
|
|
|
void CRYPTO_fork_detect_force_madv_wipeonfork_for_testing(int on) {
|
|
g_force_madv_wipeonfork = 1;
|
|
g_force_madv_wipeonfork_enabled = on;
|
|
}
|
|
|
|
#elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK)
|
|
|
|
static CRYPTO_once_t g_pthread_fork_detection_once = CRYPTO_ONCE_INIT;
|
|
static uint64_t g_atfork_fork_generation;
|
|
|
|
static void we_are_forked(void) {
|
|
// Immediately after a fork, the process must be single-threaded.
|
|
uint64_t value = g_atfork_fork_generation + 1;
|
|
if (value == 0) {
|
|
value = 1;
|
|
}
|
|
g_atfork_fork_generation = value;
|
|
}
|
|
|
|
static void init_pthread_fork_detection(void) {
|
|
if (pthread_atfork(NULL, NULL, we_are_forked) != 0) {
|
|
abort();
|
|
}
|
|
g_atfork_fork_generation = 1;
|
|
}
|
|
|
|
uint64_t CRYPTO_get_fork_generation(void) {
|
|
CRYPTO_once(&g_pthread_fork_detection_once, init_pthread_fork_detection);
|
|
|
|
return g_atfork_fork_generation;
|
|
}
|
|
|
|
#elif defined(OPENSSL_DOES_NOT_FORK)
|
|
|
|
// These platforms are guaranteed not to fork, and therefore do not require
|
|
// fork detection support. Returning a constant non zero value makes BoringSSL
|
|
// assume address space duplication is not a concern and adding entropy to
|
|
// every RAND_bytes call is not needed.
|
|
uint64_t CRYPTO_get_fork_generation(void) { return 0xc0ffee; }
|
|
|
|
#else
|
|
|
|
// These platforms may fork, but we do not have a mitigation mechanism in
|
|
// place. Returning a constant zero value makes BoringSSL assume that address
|
|
// space duplication could have occured on any call entropy must be added to
|
|
// every RAND_bytes call.
|
|
uint64_t CRYPTO_get_fork_generation(void) { return 0; }
|
|
|
|
#endif
|