pebble/src/fw/process_management/process_heap.c
2025-01-27 11:38:16 -08:00

91 lines
4 KiB
C

/*
* Copyright 2024 Google LLC
*
* 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 "process_heap.h"
#include "applib/app_logging.h"
#include "process_management/pebble_process_info.h"
#include "process_management/pebble_process_md.h"
#include "system/passert.h"
#include <util/heap.h>
static void prv_warn_on_double_free(void *ptr) {
APP_LOG(APP_LOG_LEVEL_ERROR, "Double free detected on pointer <%p>", ptr);
}
static void prv_croak_on_double_free(void *ptr) {
// Always log regardless of CROAKing on unprivileged apps. We don't send the
// croak message out over APP_LOG correctly so if we didn't do this developers
// wouldn't see the croak reason.
APP_LOG(APP_LOG_LEVEL_ERROR, "Double free detected on pointer <%p>", ptr);
PBL_CROAK("Double free detected on pointer <%p>", ptr);
}
static void prv_warn_on_heap_corruption(void *ptr) {
// They're using 3.2 SDK or older, just let them off with a log message.
APP_LOG(APP_LOG_LEVEL_ERROR, "Error: Heap corrupt around <%p>", ptr);
}
static void prv_croak_on_heap_corruption(void *ptr) {
APP_LOG(APP_LOG_LEVEL_ERROR, "Error: Heap corrupt around <%p>", ptr);
PBL_CROAK("Error: Heap corrupt around <%p>", ptr);
}
void process_heap_set_exception_handlers(Heap *heap,
const PebbleProcessMd *app_md) {
// prior to version 2.1 of the firmware (app sdk version 5.2), we never had
// double free detection in our heap and we would just silently ignore someone
// trying to free an invalid pointer. going forward we want to let our
// developers know that this happened as firmly as possible. if an app is
// compiled with the old sdk, yell at them through a log message so we don't
// break any existing apps. if the app is compiled with a new sdk after we
// made this change, just crash their app.
static const Version old_style_double_free_handling_version = { 5, 1 };
const Version app_sdk_version = process_metadata_get_sdk_version(app_md);
if (version_compare(app_sdk_version,
old_style_double_free_handling_version) <= 0) {
heap_set_double_free_handler(heap, prv_warn_on_double_free);
} else {
heap_set_double_free_handler(heap, prv_croak_on_double_free);
}
// We try to detect heap corruption by looking at segment headers and
// comparing the sizes of and prevSizes of consecutive blocks.
//
// This isn't bulletproof, but it's better than nothing. It's possible that
// corruption is happening that doesn't affect the block headers (eg. use of a
// dangling pointer), or that the overflow data simply matches what we wanted
// to check anyways.
//
// There is no risk of this producing false positives, as any header
// inconsistency is invalid.
//
// For some strange reason, some apps seem to be able to withstand heap
// corruption. An example of this is overwriting the prevSize heap member with
// a 0. An app will survive fine like this as long as we don't need to
// traverse the heap in reverse.
//
// Since some apps can continue to run without issue, rather than tearing
// everything down and create a bad user experience, let's hope that
// developers read the logs and fix their apps.
static const Version old_style_heap_corruption_version = { 5, 0x38 };
if (version_compare(app_sdk_version, old_style_heap_corruption_version) < 0) {
// They're using 3.2 SDK or older, just let them off with a log message.
heap_set_corruption_handler(heap, prv_warn_on_heap_corruption);
} else {
heap_set_corruption_handler(heap, prv_croak_on_heap_corruption);
}
}