mirror of
https://github.com/google/pebble.git
synced 2025-04-30 15:21:41 -04:00
171 lines
5.7 KiB
C
171 lines
5.7 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 "persist.h"
|
|
|
|
#include "kernel/memory_layout.h"
|
|
#include "process_management/process_manager.h"
|
|
#include "services/normal/persist.h"
|
|
#include "services/normal/settings/settings_file.h"
|
|
#include "syscall/syscall.h"
|
|
#include "syscall/syscall_internal.h"
|
|
#include "util/math.h"
|
|
|
|
|
|
_Static_assert(PERSIST_DATA_MAX_LENGTH <= SETTINGS_VAL_MAX_LEN,
|
|
"PERSIST_DATA_MAX_LENGTH is larger than the max length that "
|
|
"settings_file supports.");
|
|
|
|
|
|
static SettingsFile * prv_lock_and_get_store(void) {
|
|
return persist_service_lock_and_get_store(
|
|
&sys_process_manager_get_current_process_md()->uuid);
|
|
}
|
|
|
|
static void prv_unlock(SettingsFile **store) {
|
|
persist_service_unlock_store(*store);
|
|
}
|
|
|
|
#define LOCK_AND_GET_STORE(name) \
|
|
SettingsFile *name __attribute__((cleanup(prv_unlock))) \
|
|
= prv_lock_and_get_store()
|
|
|
|
|
|
DEFINE_SYSCALL(bool, persist_exists, const uint32_t key) {
|
|
LOCK_AND_GET_STORE(store);
|
|
return settings_file_exists(store, &key, sizeof(key));
|
|
}
|
|
|
|
DEFINE_SYSCALL(int, persist_get_size, const uint32_t key) {
|
|
LOCK_AND_GET_STORE(store);
|
|
int result = settings_file_get_len(store, &key, sizeof(key));
|
|
return result ?: E_DOES_NOT_EXIST;
|
|
}
|
|
|
|
DEFINE_SYSCALL(bool, persist_read_bool, const uint32_t key) {
|
|
bool value = false;
|
|
LOCK_AND_GET_STORE(store);
|
|
settings_file_get(store, &key, sizeof(key), &value, sizeof(value));
|
|
return value;
|
|
}
|
|
|
|
DEFINE_SYSCALL(int32_t, persist_read_int, const uint32_t key) {
|
|
int32_t value = 0;
|
|
LOCK_AND_GET_STORE(store);
|
|
settings_file_get(store, &key, sizeof(key), &value, sizeof(value));
|
|
return value;
|
|
}
|
|
|
|
DEFINE_SYSCALL(int, persist_read_data, const uint32_t key,
|
|
void *buffer, const size_t buffer_size) {
|
|
if (PRIVILEGE_WAS_ELEVATED) {
|
|
syscall_assert_userspace_buffer(buffer, buffer_size);
|
|
}
|
|
|
|
LOCK_AND_GET_STORE(store);
|
|
const int len = settings_file_get_len(store, &key, sizeof(key));
|
|
if (len == 0) {
|
|
return E_DOES_NOT_EXIST;
|
|
} else if (FAILED(len)) {
|
|
RETURN_STATUS_UP(len);
|
|
}
|
|
|
|
const size_t restricted_size = MIN(buffer_size, (size_t)len);
|
|
const status_t read_result = settings_file_get(
|
|
store, &key, sizeof(key), buffer, restricted_size);
|
|
if (FAILED(read_result)) {
|
|
RETURN_STATUS_UP(read_result);
|
|
}
|
|
return restricted_size;
|
|
}
|
|
|
|
// Legacy version to prevent previous app breakage, __deprecated preserves order
|
|
int persist_read_data__deprecated(const uint32_t key,
|
|
const size_t buffer_size, void *buffer) {
|
|
return persist_read_data(key, buffer, buffer_size);
|
|
}
|
|
|
|
int persist_read_string(const uint32_t key,
|
|
char *buffer, const size_t buffer_size) {
|
|
const int read_result = persist_read_data(key, buffer, buffer_size);
|
|
if (PASSED(read_result)) {
|
|
buffer[read_result - 1] = '\0';
|
|
}
|
|
return read_result;
|
|
}
|
|
|
|
// Legacy version to prevent previous app breakage, __deprecated preserves order
|
|
int persist_read_string__deprecated(const uint32_t key,
|
|
const size_t buffer_size, char *buffer) {
|
|
return persist_read_string(key, buffer, buffer_size);
|
|
}
|
|
|
|
DEFINE_SYSCALL(status_t, persist_write_bool, const uint32_t key, const bool value) {
|
|
LOCK_AND_GET_STORE(store);
|
|
status_t result = settings_file_set(store, &key, sizeof(key),
|
|
&value, sizeof(value));
|
|
return PASSED(result) ? (status_t)sizeof(value) : result;
|
|
}
|
|
|
|
DEFINE_SYSCALL(status_t, persist_write_int, const uint32_t key, const int32_t value) {
|
|
LOCK_AND_GET_STORE(store);
|
|
status_t result = settings_file_set(store, &key, sizeof(key),
|
|
&value, sizeof(value));
|
|
return PASSED(result) ? (status_t)sizeof(value) : result;
|
|
}
|
|
|
|
// FIXME: PBL-23877 Disallow and document persist write data of length 0 edge case
|
|
DEFINE_SYSCALL(int, persist_write_data, const uint32_t key,
|
|
const void *buffer, const size_t buffer_size) {
|
|
if (PRIVILEGE_WAS_ELEVATED) {
|
|
syscall_assert_userspace_buffer(buffer, buffer_size);
|
|
}
|
|
const size_t restricted_size = MIN(buffer_size, PERSIST_DATA_MAX_LENGTH);
|
|
LOCK_AND_GET_STORE(store);
|
|
int result = settings_file_set(store, &key, sizeof(key),
|
|
buffer, restricted_size);
|
|
return PASSED(result) ? (int)restricted_size : result;
|
|
}
|
|
|
|
// Legacy version to prevent previous app breakage, __deprecated preserves order
|
|
int persist_write_data__deprecated(const uint32_t key, const size_t buffer_size, const void *buffer) {
|
|
return persist_write_data(key, buffer, buffer_size);
|
|
}
|
|
|
|
DEFINE_SYSCALL(int, persist_write_string, const uint32_t key, const char *cstring) {
|
|
if (PRIVILEGE_WAS_ELEVATED) {
|
|
if (!memory_layout_is_cstring_in_region(
|
|
memory_layout_get_app_region(), cstring, -1)) {
|
|
syscall_failed();
|
|
}
|
|
}
|
|
const size_t cstring_length = strlen(cstring) + 1;
|
|
return persist_write_data(key, cstring, cstring_length);
|
|
}
|
|
|
|
DEFINE_SYSCALL(status_t, persist_delete, const uint32_t key) {
|
|
LOCK_AND_GET_STORE(store);
|
|
status_t result;
|
|
if (settings_file_exists(store, &key, sizeof(key))) {
|
|
result = settings_file_delete(store, &key, sizeof(key));
|
|
if (PASSED(result)) {
|
|
result = S_TRUE;
|
|
}
|
|
} else {
|
|
result = E_DOES_NOT_EXIST;
|
|
}
|
|
return result;
|
|
}
|