In this article, I will talk about the research I did by spending about 1.5 months on the S22 device. The primary purpose of my research was to fuzz the device by compiling the kernel with KCOV, but unfortunately, I could not succeed as a result of my many attempts. In the rest of our article, I will explain the experiments I made respectively.
First I downloaded the firmware of the device from SAMFW
, then I downloaded the kernel code of the device from Samsung Opensource
and started working.
Enable KCOV
After downloading the code to my local, I first bought a clean build and flashed it to the device. Everything worked as it should. Then I enabled KCOV
on the kernel config and flashed it to the device and I got bootloop. At that point, I started thinking about what was holding me back.
Setting props
The first thing that came to my mind afterwards was of course to think that it was the security features inside the device. From this point of view, the first thing I tried to do was to change the device’s props. For this I unpacked vendor_boot.img
with Magisk
, then I changed ro.selinux
and all the other props that I thought were related to the security features but unfortunately it didn’t help me.
Trying to debug the device
We had a kernel image that did not boot when flashed. Then I thought about getting a log file and started looking for the log files on the system one by one, scrutinizing them to make sure I didn’t miss a single log.
But what I was ignoring is this: Since the device was not booting, naturally it was not creating a log file anywhere. Because the problem was the PKM
of RKP
feature. I will talk about this in the future.
At this step, I started to think to myself that I should come up with a solution. In this step, I wrote a code to log to /data/tmp/local
in a function that runs when the kernel first boots and is called again at certain intervals. Here, too, I incurred the wrath of SELinux…
Even though I turned off SELinux through its props, it remained enforced during boot. Even though SELinux was permissive after boot, it didn’t work.
(NOTE: The function was called even when SELinux was permissive but SELinux prevented the write with a warning).
In this strange situation, I had to write a custom SELinux policy. I wrote this policy too, but even though it created the file, the write operation never happened.
RKP
I mentioned that I couldn’t get any logs from the device so far, and I didn’t have a chance to open the phone and connect it to the UART. In this context, I started to analyze the device by trial and error.
First of all, to debug KCOV
, I found all the code fragments that were added and removed when KCOV
was opened in the kernel code. Then I deleted and compiled all the code fragments of KCOV
. What I wanted to understand here was to understand whether the security feature on the device read the .config
file and blocked us. Of course, it was not blocking us by reading the .config
.
After that, I started to enable the code pieces step by step and I realized the following:
Every time I added or removed an element to the struct named task_struct
, the kernel would bootloop. KCOV
was a config that added elements to this task_struct
. When I realized this, the first thing that came to my mind was that some code was hardcoded according to the size of the task_struct
and therefore there was a shift in some casting operations. This slippage was crashing us.
But of course, this was not the case, there were two reasons for this: 1) We were also crashing when we added an element at the bottom of the task_struct
. 2) Inside the task_struct
, variables were pointing to a struct. I defined variables under these structs read the code that used this struct and made sure that I would not cause any crash (we examined it in detail to make sure that we would not cause any kernel BUGs), but it still did not boot.
At this stage, I realized that there was a security feature that prevented the following; adding elements to task_struct
, Adding elements to structs under task_struct
.
But this seemed ridiculous to me. Yes, I couldn’t define a variable inside a task_struct
, but why can’t I define a variable inside a struct pointed to by a variable inside a task_struct
!!!!
So I made one last attempt and tried to find all the structs that have pointers under task_struct
and add elements to the bottom of each one.
pi_state_cache, rcu_node, futex_pi_state ------> I was successful with these three structs.
In other words, I could add variables to these structs as I wanted. In this way, instead of defining the elements that KCOV
uses directly under task_struct
, I would define them in one of these structs. Then, with some minor changes to the kcov file, I would have successfully compiled kcov.
Custom KCOV
As I mentioned in the previous section, I adapted the struct named futex_pi_state
to kcov.
When I ran the file compiled with this kcov.c
, I got bootloop again. The reason for this was symbols as far as I researched. RKP
was somehow examining the symbols in the kernel image and blocking us. But I couldn’t find any conclusive evidence for this.
And at this step, I thought the only solution was to try to turn off RKP
.
Trying to turn off security features (e.g. RKP, selinux…) via kernel code
To make SELinux permissive permanently in the kernel code, we need to edit the kernel_platform/common/security/selinux/selinuxfs.c
file, where we need to make the following changes:
Lines 152-178 below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//CUT
/* No partial writes. */
if (*ppos != 0)
return -EINVAL;
page = memdup_user_nul(buf, count);
if (IS_ERR(page))
return PTR_ERR(page);
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
goto out;
new_value = !!new_value;
old_value = enforcing_enabled(state);
new_value = 0; //ADD FOR PERMANENT PERMESSIVE
if (new_value != old_value) {
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY,
//CUT
This link is useful for turning off Knox and RKP
security features:
I made all these changes normally and the device booted without KCOV. Then I enabled KCOV and failed. I believe that the reason for this is the PKM
, which is a security feature under the RKP. It blocks to change kernel code.
Turning off RKP in Config does not mean turning off the RKP on the CPU.