1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <bpf_helpers.h>
18 #include <linux/bpf.h>
19 #include <stdbool.h>
20 #include <stdint.h>
21
22 // TODO: import this struct from generic header, access registers via generic
23 // function
24 struct pt_regs {
25 unsigned long regs[31];
26 unsigned long sp;
27 unsigned long pc;
28 unsigned long pr;
29 unsigned long sr;
30 unsigned long gbr;
31 unsigned long mach;
32 unsigned long macl;
33 long tra;
34 };
35
36 struct SetUidTempAllowlistStateRecord {
37 __u64 uid;
38 bool onAllowlist;
39 };
40
41 DEFINE_BPF_RINGBUF_EXT(output_buf, struct SetUidTempAllowlistStateRecord, 4096,
42 AID_UPROBESTATS, AID_UPROBESTATS, 0600, "", "", PRIVATE,
43 BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG,
44 LOAD_ON_USER, LOAD_ON_USERDEBUG);
45
46 DEFINE_BPF_PROG("uprobe/set_uid_temp_allowlist_state", AID_UPROBESTATS,
47 AID_UPROBESTATS, BPF_KPROBE2)
48 (struct pt_regs *ctx) {
49 struct SetUidTempAllowlistStateRecord *output = bpf_output_buf_reserve();
50 if (output == NULL)
51 return 1;
52 output->uid = ctx->regs[2];
53 output->onAllowlist = ctx->regs[3];
54 bpf_output_buf_submit(output);
55 return 0;
56 }
57
58 struct jstring {
59 __u64 dummy;
60 __u32 count;
61 __u32 hash_code;
62 };
63
64 struct UpdateDeviceIdleTempAllowlistRecord {
65 int changing_uid;
66 bool adding;
67 long duration_ms;
68 int type;
69 int reason_code;
70 char reason[256];
71 int calling_uid;
72 };
73
74 DEFINE_BPF_RINGBUF_EXT(update_device_idle_temp_allowlist_records,
75 struct UpdateDeviceIdleTempAllowlistRecord, 4096,
76 AID_UPROBESTATS, AID_UPROBESTATS, 0600, "", "", PRIVATE,
77 BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG,
78 LOAD_ON_USER, LOAD_ON_USERDEBUG);
79
80 // Copies the string content of a Java String object located at <jstring> to
81 // <dest>.
recordString(void * jstring,unsigned int max_length,char * dest)82 void recordString(void *jstring, unsigned int max_length, char *dest) {
83 // Assumes the following memory layout of a Java String object:
84 // byte offset 8-11: count (this is the length of the string * 2)
85 // byte offset 12-15: hash_code
86 // byte offset 16 and beyond: string content
87 __u32 count;
88 bpf_probe_read_user(&count, sizeof(count), jstring + 8);
89 count /= 2;
90 bpf_probe_read_user_str(dest, max_length < count + 1 ? max_length : count + 1,
91 jstring + 16);
92 }
93
94 // Copies the content of a Java String object to <dest>, where the Java String
95 // is located at <position> in the method invocation argument list (0-based).
96 // This only works for the 0th - the 5th arguments. Rest of the arguments need
97 // to be accessed via stack pointer using the recordStringArgFromSp() function.
recordStringArg(struct pt_regs * ctx,unsigned int max_length,int position,char * dest)98 void recordStringArg(struct pt_regs *ctx, unsigned int max_length, int position,
99 char *dest) {
100 recordString((void *)ctx->regs[2 + position], max_length, dest);
101 }
102
103 // Copies the content of a Java String object to <dest>, where the Java String
104 // address is located in stack frame.
recordStringArgFromSp(struct pt_regs * ctx,unsigned int max_length,int sp_offset,char * dest)105 void recordStringArgFromSp(struct pt_regs *ctx, unsigned int max_length,
106 int sp_offset, char *dest) {
107 void *jstring = NULL;
108 bpf_probe_read_user(&jstring, 4, (void *)ctx->sp + sp_offset);
109 recordString(jstring, max_length, dest);
110 }
111
112 DEFINE_BPF_PROG("uprobe/update_device_idle_temp_allowlist", AID_UPROBESTATS,
113 AID_UPROBESTATS, BPF_KPROBE3)
114 (struct pt_regs *ctx) {
115 struct UpdateDeviceIdleTempAllowlistRecord *output =
116 bpf_update_device_idle_temp_allowlist_records_reserve();
117 if (output == NULL)
118 return 1;
119
120 // changing_uid is the 2nd argument, which is located in regs[3].
121 output->changing_uid = ctx->regs[3];
122 output->adding = ctx->regs[4];
123 output->duration_ms = ctx->regs[5];
124 output->type = ctx->regs[6];
125 output->reason_code = ctx->regs[7];
126
127 // The <reason> argument is located at offset=40 in stack frame. This is
128 // calculated as 12 + sizeof(previous arguments). There are 6 preceding
129 // arguments all of which is 4 bytes each except for <long durationMs> which
130 // is 8 bytes. Therefore the offset is 12 + 5 * 4 + 8 = 40
131 recordStringArgFromSp(ctx, 256, 40, output->reason);
132
133 // The <calling_uid> argument follows <reason> immediately and therefore has
134 // an offset that's 4 more bytes larger.
135 bpf_probe_read_user(&output->calling_uid, 4, (void *)ctx->sp + 44);
136
137 bpf_update_device_idle_temp_allowlist_records_submit(output);
138 return 0;
139 }
140
141 LICENSE("GPL");
142