-
Notifications
You must be signed in to change notification settings - Fork 311
load package_info when startup #254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
52b0c5c
d6be972
44c4e7d
d5a0b0a
92e8d11
a6b2ef0
353294a
33d1f39
0ec7651
98cfef9
aad6f1e
303e1a4
3a4719a
d0c497b
09fd4a1
14b2925
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| .vscode/* | ||
| .history/ | ||
|
|
||
| .claude | ||
| **/.DS_Store | ||
|
|
||
| build | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,9 @@ | |
| #include <linux/umh.h> | ||
| #include <uapi/scdefs.h> | ||
| #include <uapi/linux/stat.h> | ||
|
|
||
| #include <sucompat.h> | ||
| #include <userd.h> | ||
| #include <uapi/linux/limits.h> | ||
|
|
||
| #define REPLACE_RC_FILE "/dev/user_init.rc" | ||
|
|
||
|
|
@@ -45,6 +47,7 @@ | |
| #define MAGISK_SCTX "u:r:magisk:s0" | ||
| #define APD_PATH "/data/adb/apd" | ||
| #define MAGISK_POLICY_PATH "/data/adb/ap/bin/magiskpolicy" | ||
| #define AP_PACKAGE_CONFIG_PATH "/data/adb/ap/package_config" | ||
|
|
||
|
|
||
|
|
||
|
|
@@ -124,6 +127,244 @@ static loff_t kernel_write_file(const char *path, const void *data, loff_t len, | |
| return off; | ||
| } | ||
|
|
||
| // Simple CSV field parser helper function | ||
| static char *parse_csv_field(char **line_ptr) | ||
| { | ||
| char *start = *line_ptr; | ||
| char *end = start; | ||
|
|
||
| if (!start || *start == '\0') return NULL; | ||
|
|
||
| // Skip leading whitespace | ||
| while (*start == ' ' || *start == '\t') start++; | ||
|
|
||
| // Find comma or end of line | ||
| end = start; | ||
| while (*end && *end != ',' && *end != '\n' && *end != '\r') { | ||
| end++; | ||
| } | ||
|
|
||
| // Preserve delimiter before modifying buffer | ||
| { | ||
| char delim = *end; | ||
|
|
||
| // Remove trailing whitespace only if field is non-empty | ||
| if (end > start) { | ||
| char *trim_end = end - 1; | ||
| while (trim_end > start && (*trim_end == ' ' || *trim_end == '\t')) { | ||
| trim_end--; | ||
| } | ||
| *(trim_end + 1) = '\0'; | ||
| } else { | ||
| // Empty field: terminate at start so caller sees an empty string | ||
| *start = '\0'; | ||
| } | ||
|
|
||
| // Update pointer position based on original delimiter | ||
| if (delim == ',') { | ||
| *line_ptr = end + 1; | ||
| } else { | ||
| *line_ptr = end; | ||
| } | ||
| } | ||
|
|
||
| return start; | ||
| } | ||
|
|
||
| // Load APatch package_config configuration file | ||
| // Returns: number of entries loaded, or negative error code | ||
| int load_ap_package_config() | ||
| { | ||
| loff_t len = 0; | ||
| const char *data = kernel_read_file(AP_PACKAGE_CONFIG_PATH, &len); | ||
|
|
||
| if (!data || len <= 0) { | ||
| log_boot("package_config not found or empty\n"); | ||
| return -ENOENT; | ||
| } | ||
| if (len > 10 * 1024 * 1024){ | ||
| log_boot("package_config too large: %lld\n", len); | ||
| return -EFBIG; | ||
| } | ||
|
|
||
| log_boot("loading package_config, size: %lld\n", len); | ||
|
|
||
| char *content = (char *)data; | ||
| char *line_start = content; | ||
| int line_num = 0; | ||
| int loaded_count = 0; | ||
| int skipped_count = 0; | ||
|
|
||
| // Parse CSV line by line | ||
| while (line_start < content + len) { | ||
| char *line_end = line_start; | ||
| int has_newline = 0; | ||
|
|
||
| // Find end of line | ||
| while (line_end < content + len && *line_end != '\n' && *line_end != '\r') { | ||
| line_end++; | ||
| } | ||
|
|
||
| // Check if we found a newline | ||
| if (line_end < content + len) { | ||
| has_newline = 1; | ||
| *line_end = '\0'; // Safe because line_end < content + len | ||
| } | ||
|
Comment on lines
+203
to
+212
|
||
|
|
||
| line_num++; | ||
|
|
||
| // Skip CSV header | ||
| if (line_num == 1) { | ||
| if (has_newline) { | ||
| line_start = line_end + 1; | ||
| } else { | ||
| break; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| // Process current line | ||
| char *line_ptr = line_start; | ||
| int valid_line = 1; | ||
|
|
||
| // Parse CSV fields: pkg,exclude,allow,uid,to_uid,sctx | ||
| parse_csv_field(&line_ptr); // skip pkg field | ||
| char *exclude_str = parse_csv_field(&line_ptr); | ||
| char *allow_str = parse_csv_field(&line_ptr); | ||
| char *uid_str = parse_csv_field(&line_ptr); | ||
| char *to_uid_str = parse_csv_field(&line_ptr); | ||
| char *sctx = parse_csv_field(&line_ptr); | ||
|
|
||
| // Check required fields | ||
| if (!uid_str || !to_uid_str || !sctx) { | ||
| log_boot("package_config: line %d missing required fields (uid/to_uid/sctx)\n", line_num); | ||
| valid_line = 0; | ||
| goto next_line; | ||
| } | ||
|
|
||
| unsigned long long uid_tmp = 0, to_uid_tmp = 0; | ||
| unsigned long long exclude_tmp = 0, allow_tmp = 0; | ||
| int ret; | ||
|
|
||
| // Convert UID fields - must succeed | ||
| ret = kstrtoull(uid_str, 10, &uid_tmp); | ||
| if (ret) { | ||
| log_boot("package_config: line %d invalid uid '%s': %d\n", line_num, uid_str, ret); | ||
| valid_line = 0; | ||
| goto next_line; | ||
| } | ||
|
|
||
| ret = kstrtoull(to_uid_str, 10, &to_uid_tmp); | ||
| if (ret) { | ||
| log_boot("package_config: line %d invalid to_uid '%s': %d\n", line_num, to_uid_str, ret); | ||
| valid_line = 0; | ||
| goto next_line; | ||
| } | ||
|
|
||
| // Range check for uid_t (typically unsigned int) | ||
| if (uid_tmp > UINT_MAX) { | ||
| log_boot("package_config: line %d uid %llu out of range\n", line_num, uid_tmp); | ||
| valid_line = 0; | ||
| goto next_line; | ||
| } | ||
| if (to_uid_tmp > UINT_MAX) { | ||
| log_boot("package_config: line %d to_uid %llu out of range\n", line_num, to_uid_tmp); | ||
| valid_line = 0; | ||
| goto next_line; | ||
| } | ||
|
|
||
| // Convert optional fields (exclude and allow) | ||
| if (exclude_str && *exclude_str) { | ||
| ret = kstrtoull(exclude_str, 10, &exclude_tmp); | ||
| if (ret) { | ||
| log_boot("package_config: line %d invalid exclude '%s': %d, using default 0\n", | ||
| line_num, exclude_str, ret); | ||
| exclude_tmp = 0; | ||
| } | ||
| if (exclude_tmp > INT_MAX) { | ||
| log_boot("package_config: line %d exclude %llu out of range, clamping\n", | ||
| line_num, exclude_tmp); | ||
| exclude_tmp = INT_MAX; | ||
| } | ||
| } | ||
|
|
||
| if (allow_str && *allow_str) { | ||
| ret = kstrtoull(allow_str, 10, &allow_tmp); | ||
| if (ret) { | ||
| log_boot("package_config: line %d invalid allow '%s': %d, using default 0\n", | ||
| line_num, allow_str, ret); | ||
| allow_tmp = 0; | ||
| } | ||
| if (allow_tmp > INT_MAX) { | ||
| log_boot("package_config: line %d allow %llu out of range, clamping\n", | ||
| line_num, allow_tmp); | ||
| allow_tmp = INT_MAX; | ||
| } | ||
| } | ||
|
|
||
| uid_t uid = (uid_t)uid_tmp; | ||
| uid_t to_uid = (uid_t)to_uid_tmp; | ||
| int exclude = (int)exclude_tmp; | ||
| int allow = (int)allow_tmp; | ||
|
|
||
| // Validate sctx is not empty | ||
| if (!sctx || !*sctx) { | ||
| log_boot("package_config: line %d empty sctx\n", line_num); | ||
| valid_line = 0; | ||
| goto next_line; | ||
| } | ||
|
|
||
| // CRITICAL FIX: Safely copy sctx into a fixed-size buffer with NUL termination | ||
| // This prevents buffer overflow and ensures proper string handling | ||
| char sctx_buf[SUPERCALL_SCONTEXT_LEN]; | ||
| size_t sctx_len = strlen(sctx); | ||
|
|
||
| if (sctx_len >= SUPERCALL_SCONTEXT_LEN) { | ||
| // Truncate and log warning | ||
| log_boot("package_config: line %d sctx too long (%zu bytes), truncating to %d bytes\n", | ||
| line_num, sctx_len, SUPERCALL_SCONTEXT_LEN - 1); | ||
| memcpy(sctx_buf, sctx, SUPERCALL_SCONTEXT_LEN - 1); | ||
| sctx_buf[SUPERCALL_SCONTEXT_LEN - 1] = '\0'; | ||
| } else { | ||
| // Safe copy with NUL termination | ||
| memcpy(sctx_buf, sctx, sctx_len + 1); // +1 includes the NUL terminator | ||
| } | ||
|
|
||
| // Apply configuration with safe sctx buffer | ||
| if (allow) { | ||
| int rc = su_add_allow_uid(uid, to_uid, sctx_buf); | ||
| if (rc == 0) { | ||
| loaded_count++; | ||
| } else { | ||
| log_boot("package_config: line %d failed to add allow rule: %d\n", line_num, rc); | ||
| valid_line = 0; | ||
| } | ||
| } | ||
|
|
||
| // Set exclude flag | ||
| if (exclude) { | ||
| set_ap_mod_exclude(uid, exclude); | ||
| } | ||
|
|
||
| next_line: | ||
| if (!valid_line) { | ||
| skipped_count++; | ||
| } | ||
|
|
||
| // Move to next line | ||
| if (has_newline) { | ||
| line_start = line_end + 1; | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| kvfree(data); | ||
| log_boot("package_config loaded: %d entries, skipped: %d\n", loaded_count, skipped_count); | ||
| return loaded_count; | ||
| } | ||
| KP_EXPORT_SYMBOL(load_ap_package_config); | ||
|
|
||
| static void pre_user_exec_init() | ||
| { | ||
| log_boot("event: %s\n", EXTRA_EVENT_PRE_EXEC_INIT); | ||
|
|
@@ -133,6 +374,7 @@ static void pre_user_exec_init() | |
| static void pre_init_second_stage() | ||
| { | ||
| log_boot("event: %s\n", EXTRA_EVENT_PRE_SECOND_STAGE); | ||
|
|
||
| } | ||
|
|
||
| static void on_first_app_process() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| /* | ||
| * Copyright (C) 2024 bmax121. All Rights Reserved. | ||
| */ | ||
|
|
||
| #ifndef _KP_USERD_H_ | ||
| #define _KP_USERD_H_ | ||
|
|
||
| int load_ap_package_config(void); | ||
|
|
||
| #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
load_ap_package_config()reads the entire/data/adb/ap/package_configinto a singlevmalloc(len)buffer with no upper bound. Since this can be triggered automatically at boot and also via supercall, a large file can cause excessive memory usage/OOM (and is a DoS vector). Consider enforcing a reasonable max size (and failing with a clear error) before allocating/reading.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot apply changes based on this feedback