You've already forked KernelSU
mirror of
https://github.com/tiann/KernelSU.git
synced 2025-08-27 23:46:34 +00:00
Compare commits
1336 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f341a4e3a | ||
|
|
40d7bc6256 | ||
|
|
56dbc980f4 | ||
|
|
bf71ff133c | ||
|
|
a9b156df43 | ||
|
|
1690e5db02 | ||
|
|
300d9d4cca | ||
|
|
3f12080dfe | ||
|
|
b670db2d22 | ||
|
|
62a31b3dc2 | ||
|
|
a395b1011e | ||
|
|
406070914a | ||
|
|
8685fa1f60 | ||
|
|
c95163b144 | ||
|
|
648d56da39 | ||
|
|
33c0a9eebd | ||
|
|
3f86fb016d | ||
|
|
66316e76f5 | ||
|
|
5591a94f87 | ||
|
|
f855f8148a | ||
|
|
0c52f24612 | ||
|
|
9635a00036 | ||
|
|
cbc04ff6df | ||
|
|
8e448767a5 | ||
|
|
2820779947 | ||
|
|
a99c69f9b4 | ||
|
|
a829707b16 | ||
|
|
77d16ac896 | ||
|
|
d02855a40a | ||
|
|
b904680f13 | ||
|
|
811c68cac0 | ||
|
|
f20ccc1728 | ||
|
|
66e7db2a4e | ||
|
|
e6b05b1d3c | ||
|
|
329010a694 | ||
|
|
9c4d20c0f2 | ||
|
|
355b55a01d | ||
|
|
e85646fad4 | ||
|
|
4969c5f548 | ||
|
|
55f8f2da90 | ||
|
|
65bff7bf03 | ||
|
|
30dfbbdc0e | ||
|
|
fceffc9cfe | ||
|
|
01b685ce58 | ||
|
|
cbd184421c | ||
|
|
b0a42abf4f | ||
|
|
cfc982f2f3 | ||
|
|
e0e7058d14 | ||
|
|
e0802b0d15 | ||
|
|
81f15ef120 | ||
|
|
20c19d7126 | ||
|
|
a360cd87c0 | ||
|
|
ea9b572402 | ||
|
|
6bf9e0478e | ||
|
|
abf0dacb36 | ||
|
|
263b986bcd | ||
|
|
15bdd9f507 | ||
|
|
810a62f795 | ||
|
|
07e475c5dc | ||
|
|
eb02e42bc7 | ||
|
|
5db51b0715 | ||
|
|
60d2685f7e | ||
|
|
a4b9ea04a4 | ||
|
|
f80d0764b5 | ||
|
|
f80769a82a | ||
|
|
64269c8c4f | ||
|
|
9f04482b90 | ||
|
|
aca505c3e6 | ||
|
|
d4826bc97c | ||
|
|
4efc8164f1 | ||
|
|
0fc25cf091 | ||
|
|
ca438291cc | ||
|
|
d6cab60e6d | ||
|
|
4d4bd4793f | ||
|
|
c1a2cbf1e4 | ||
|
|
4b1fb121b4 | ||
|
|
883a3e3407 | ||
|
|
27bd18f60e | ||
|
|
7cb5fb47e1 | ||
|
|
d43b40572d | ||
|
|
c99b5b31c1 | ||
|
|
ca960a2a8f | ||
|
|
cce423a2f6 | ||
|
|
946fb6f999 | ||
|
|
b6ecce4317 | ||
|
|
be70a91f16 | ||
|
|
71c2790f08 | ||
|
|
8733b390ca | ||
|
|
c4e106d6f8 | ||
|
|
b612efcfad | ||
|
|
7f53882007 | ||
|
|
23ba3182cf | ||
|
|
8abd37a35c | ||
|
|
d7bc853bfc | ||
|
|
16c5aba4ff | ||
|
|
3914242457 | ||
|
|
eaa12161d6 | ||
|
|
0f985917f9 | ||
|
|
a569b1c76e | ||
|
|
7f1ea2e178 | ||
|
|
da89a45d56 | ||
|
|
dc2fb20d24 | ||
|
|
d7625722db | ||
|
|
4144f10d9a | ||
|
|
aaddaf1a78 | ||
|
|
2fec279de3 | ||
|
|
1e676e5dc2 | ||
|
|
7b63e099ce | ||
|
|
aef943ebe3 | ||
|
|
1637864636 | ||
|
|
e934bfb648 | ||
|
|
653225bb5b | ||
|
|
decbdeb5d7 | ||
|
|
51ca19f267 | ||
|
|
5b920f8230 | ||
|
|
601ce2120a | ||
|
|
6d79060e4c | ||
|
|
e95e87a7a4 | ||
|
|
144b0cc8e9 | ||
|
|
d9d9066316 | ||
|
|
3af293f991 | ||
|
|
60c9fabb44 | ||
|
|
23ffc2a3b2 | ||
|
|
2bab388bbf | ||
|
|
e9997a07c1 | ||
|
|
757e69b15e | ||
|
|
506385cfad | ||
|
|
4b27a9a324 | ||
|
|
1326fd32c5 | ||
|
|
90d63fe184 | ||
|
|
0f8a1346c7 | ||
|
|
1fad91a4e2 | ||
|
|
ddff9ee701 | ||
|
|
c7a9655ab9 | ||
|
|
fd7681c3ff | ||
|
|
e3e4d2eed4 | ||
|
|
30e00859b9 | ||
|
|
faf7a8e3b1 | ||
|
|
b82fc971dd | ||
|
|
52f5727875 | ||
|
|
01711b4114 | ||
|
|
153ce9a39a | ||
|
|
f37cc16117 | ||
|
|
5f31571cc7 | ||
|
|
92a1267b29 | ||
|
|
b99701d216 | ||
|
|
097e291d93 | ||
|
|
eb3f604ab8 | ||
|
|
3d9ca63bac | ||
|
|
4be7485180 | ||
|
|
afefe20c96 | ||
|
|
76e7d7c60c | ||
|
|
d08f537c89 | ||
|
|
88e20d102d | ||
|
|
32b3ec9844 | ||
|
|
fbeea49318 | ||
|
|
5deecb3b50 | ||
|
|
534ac88195 | ||
|
|
d867c3c5e2 | ||
|
|
aca9ac50f3 | ||
|
|
d6cbda49aa | ||
|
|
fe7f509f9d | ||
|
|
26da7d590e | ||
|
|
706cd1e73e | ||
|
|
6472b14a59 | ||
|
|
c305dca5ab | ||
|
|
94978b7b28 | ||
|
|
161b3280c4 | ||
|
|
e69769d25f | ||
|
|
a1153683e1 | ||
|
|
79341ab501 | ||
|
|
05b33abb79 | ||
|
|
f5095f96fa | ||
|
|
dcd9d65c92 | ||
|
|
fa3dec8852 | ||
|
|
87d10054ae | ||
|
|
1a308afe63 | ||
|
|
f46830f28f | ||
|
|
c560d603e6 | ||
|
|
064de704f2 | ||
|
|
860911c455 | ||
|
|
1d04c5086c | ||
|
|
f4eab986a9 | ||
|
|
701e85d931 | ||
|
|
bf43654725 | ||
|
|
a56a922f96 | ||
|
|
19a697a968 | ||
|
|
c9b540b12c | ||
|
|
cd48f64154 | ||
|
|
acd2c343e2 | ||
|
|
dec7f91182 | ||
|
|
d2684292e8 | ||
|
|
07b940d127 | ||
|
|
845515fa6b | ||
|
|
0db7aa573e | ||
|
|
3783f82b28 | ||
|
|
684973b4bf | ||
|
|
0617c4440b | ||
|
|
9223558197 | ||
|
|
c13040a0ea | ||
|
|
b45c4f57c5 | ||
|
|
8196243478 | ||
|
|
b7f937b7f9 | ||
|
|
8fdff569d6 | ||
|
|
b658d820a1 | ||
|
|
ce56c19ad9 | ||
|
|
d27561c505 | ||
|
|
57898f13c1 | ||
|
|
5da1767ff8 | ||
|
|
aa21385a36 | ||
|
|
697e06125a | ||
|
|
95c383ea18 | ||
|
|
048e94ba69 | ||
|
|
4a9f1de7a0 | ||
|
|
00438a6d6e | ||
|
|
88d4eca8ff | ||
|
|
8a298bb867 | ||
|
|
5526fa2468 | ||
|
|
c26a26b92d | ||
|
|
75e64eafd2 | ||
|
|
961478fa23 | ||
|
|
a903b0fa4e | ||
|
|
0f09b90f5b | ||
|
|
8b81aeaf70 | ||
|
|
b4a52f89cc | ||
|
|
e9df5105b3 | ||
|
|
cd2711395a | ||
|
|
83a8d77018 | ||
|
|
426fde58fd | ||
|
|
59040c3aea | ||
|
|
f4b53daddf | ||
|
|
4c79ad7a81 | ||
|
|
fb6565bd19 | ||
|
|
a3e939ab90 | ||
|
|
80797548b5 | ||
|
|
f86fce6e16 | ||
|
|
318be535a8 | ||
|
|
92d4de3a73 | ||
|
|
3cf5fc4c51 | ||
|
|
4e3cbf627a | ||
|
|
72febb34c0 | ||
|
|
03068f279d | ||
|
|
7371eae382 | ||
|
|
fae1fd9826 | ||
|
|
ec5d9e6368 | ||
|
|
64f849dc10 | ||
|
|
d68fa5aed5 | ||
|
|
1b67c1b153 | ||
|
|
f349507232 | ||
|
|
bf823a29e8 | ||
|
|
55f712d1b2 | ||
|
|
ca10d7bcb9 | ||
|
|
d24813b2c3 | ||
|
|
a6325193cf | ||
|
|
7a1767b4c9 | ||
|
|
2d4d26c68e | ||
|
|
3f98493bb3 | ||
|
|
927f2a26bd | ||
|
|
344c08bb79 | ||
|
|
84f16e4c82 | ||
|
|
4ff9dcaa17 | ||
|
|
34b64b8310 | ||
|
|
8f4e7f8a79 | ||
|
|
75b5fdfb9d | ||
|
|
d4e19bb8fc | ||
|
|
571f89fac3 | ||
|
|
9e058c48a6 | ||
|
|
e828053439 | ||
|
|
8a7d153b02 | ||
|
|
06fdae18d2 | ||
|
|
df8c91b306 | ||
|
|
10b31bd09a | ||
|
|
54a705d8dc | ||
|
|
294caf3deb | ||
|
|
a1f7d474f9 | ||
|
|
1df5fec49b | ||
|
|
fd03626362 | ||
|
|
9b294682b0 | ||
|
|
a4fb9e4031 | ||
|
|
3ebee74efc | ||
|
|
433627c82b | ||
|
|
6cce322107 | ||
|
|
906007a7b3 | ||
|
|
583426ecc5 | ||
|
|
ce892bc439 | ||
|
|
1f1d4d454e | ||
|
|
4695b41f53 | ||
|
|
52f17cde40 | ||
|
|
3408f944e6 | ||
|
|
b1830049f1 | ||
|
|
79951f06ed | ||
|
|
8828939994 | ||
|
|
a3b92d6fee | ||
|
|
a22959beae | ||
|
|
7753dc0987 | ||
|
|
960c40129b | ||
|
|
f371d784ea | ||
|
|
59b45ce822 | ||
|
|
340595276f | ||
|
|
72d756c9f2 | ||
|
|
3d59071571 | ||
|
|
394cfe7516 | ||
|
|
0810db101e | ||
|
|
ab0ae9d196 | ||
|
|
13748300eb | ||
|
|
c4db2bab4f | ||
|
|
e352ccc470 | ||
|
|
7747c0e211 | ||
|
|
2661a36375 | ||
|
|
1bdddb13ce | ||
|
|
7d3c50ef0a | ||
|
|
2ee7696d67 | ||
|
|
54ee400dc5 | ||
|
|
945e2c3209 | ||
|
|
298e42cb42 | ||
|
|
3a657a9dbb | ||
|
|
55aa54ca85 | ||
|
|
0b8359a2e2 | ||
|
|
afb04126f6 | ||
|
|
98fae23864 | ||
|
|
23805d4784 | ||
|
|
01bf24fa7b | ||
|
|
47f05a139d | ||
|
|
3c0c70ba7f | ||
|
|
c19ba7fab0 | ||
|
|
1f42bbac5e | ||
|
|
cbb98a1de9 | ||
|
|
08745664a6 | ||
|
|
eac6fd0484 | ||
|
|
ad1dbf77a1 | ||
|
|
81bbb31098 | ||
|
|
52234d040f | ||
|
|
1fb2aad893 | ||
|
|
64744bb31d | ||
|
|
b9747fbe69 | ||
|
|
85922946b7 | ||
|
|
40fc6d2163 | ||
|
|
da662133ae | ||
|
|
25592a0614 | ||
|
|
2d96aaa28f | ||
|
|
64cf6eb8b9 | ||
|
|
7e44765074 | ||
|
|
d84fdada31 | ||
|
|
71c14d96ab | ||
|
|
5d988002c7 | ||
|
|
15ff9fbf41 | ||
|
|
542d3e40af | ||
|
|
7c4fb51b5c | ||
|
|
5b10d10b82 | ||
|
|
677d3357b9 | ||
|
|
5e893e3d04 | ||
|
|
685cd75c99 | ||
|
|
8354204c32 | ||
|
|
d394fd2e01 | ||
|
|
71799c7aed | ||
|
|
76bdd12f73 | ||
|
|
fb103472c6 | ||
|
|
9f17bafbf0 | ||
|
|
b2f9f3ade9 | ||
|
|
12a095fd1a | ||
|
|
7153336ad1 | ||
|
|
5f2566e478 | ||
|
|
0af25af1be | ||
|
|
ea3b397f34 | ||
|
|
6aeb76a3ef | ||
|
|
ae9519de42 | ||
|
|
8bf33e9aca | ||
|
|
b91a294138 | ||
|
|
d274a315b1 | ||
|
|
b0c3c3a9a2 | ||
|
|
1147eb205d | ||
|
|
f160abf9ce | ||
|
|
61ad99dbe5 | ||
|
|
9a126645e8 | ||
|
|
21f39f6de8 | ||
|
|
0ddb8a4c89 | ||
|
|
c9997b5ca9 | ||
|
|
0b1bab5b01 | ||
|
|
676590be15 | ||
|
|
b52bf53d01 | ||
|
|
7bdb885816 | ||
|
|
cde3e95180 | ||
|
|
7ecb4b03ee | ||
|
|
e8a90aadb2 | ||
|
|
beaa048be3 | ||
|
|
936b650f12 | ||
|
|
747c91d5c8 | ||
|
|
5023d0ab1d | ||
|
|
5b638c876e | ||
|
|
d6a7231fae | ||
|
|
06681a2490 | ||
|
|
278cbef3ec | ||
|
|
a83390b0ec | ||
|
|
907bcad1a7 | ||
|
|
4c0a36785b | ||
|
|
983ad2c1fd | ||
|
|
a3590b767e | ||
|
|
12e00dc717 | ||
|
|
e00a355fa8 | ||
|
|
e95c5a9675 | ||
|
|
d0b8144b96 | ||
|
|
d16d3f87a6 | ||
|
|
76decba8d9 | ||
|
|
d75678fca0 | ||
|
|
abe1fa471d | ||
|
|
07a430aa5b | ||
|
|
df9cf61575 | ||
|
|
bfe8c2eecd | ||
|
|
b732765811 | ||
|
|
a966252fa5 | ||
|
|
3664003260 | ||
|
|
978178afc0 | ||
|
|
16f6f30eae | ||
|
|
63851f8c88 | ||
|
|
34c6765752 | ||
|
|
c23d1bcf58 | ||
|
|
6ae7e1624f | ||
|
|
ba4b014a99 | ||
|
|
f192638943 | ||
|
|
0323ee7958 | ||
|
|
021ef521cb | ||
|
|
34086cd445 | ||
|
|
c306eddee8 | ||
|
|
c72f7d750e | ||
|
|
f9a91848ad | ||
|
|
cd8013a616 | ||
|
|
dc536d652a | ||
|
|
3114f6d7f6 | ||
|
|
e2f5015107 | ||
|
|
884dd606eb | ||
|
|
8d246a6b9d | ||
|
|
2ee3d55c88 | ||
|
|
55b540bf4c | ||
|
|
c0d147dcad | ||
|
|
be413fd147 | ||
|
|
786f3d6441 | ||
|
|
8f50b5f6e5 | ||
|
|
90639fad6c | ||
|
|
2979434e2a | ||
|
|
56d145666c | ||
|
|
db5f77aa96 | ||
|
|
5fbce8ef07 | ||
|
|
4cc3644416 | ||
|
|
01a7678a26 | ||
|
|
95d22d2bb4 | ||
|
|
3efb2be456 | ||
|
|
3b7ca2d7e8 | ||
|
|
7b45bc5aad | ||
|
|
ed1e892600 | ||
|
|
f188802044 | ||
|
|
965c23867f | ||
|
|
b271b2f587 | ||
|
|
0953f50e0c | ||
|
|
77ac974ce8 | ||
|
|
d714ab0c5d | ||
|
|
38eb93d5ca | ||
|
|
080d5bd9e8 | ||
|
|
d05ec41379 | ||
|
|
d07956ead6 | ||
|
|
4e3af6dab3 | ||
|
|
45d96b98c5 | ||
|
|
b554c66b46 | ||
|
|
fb87d0f0f5 | ||
|
|
37abe48702 | ||
|
|
ec9babea76 | ||
|
|
8a464ac7b2 | ||
|
|
eb5a99e4b6 | ||
|
|
047312e0e5 | ||
|
|
45a25eda50 | ||
|
|
120c2f43de | ||
|
|
9deb820923 | ||
|
|
ae21d4c9fd | ||
|
|
5381ceabae | ||
|
|
5d07e1d392 | ||
|
|
d78f24098a | ||
|
|
cd952f5e45 | ||
|
|
156b17f69d | ||
|
|
f4d2b0feab | ||
|
|
2c0a9cd64c | ||
|
|
134507b928 | ||
|
|
2b42d14ef8 | ||
|
|
e6071b5247 | ||
|
|
f288cfccae | ||
|
|
1cc9da5efe | ||
|
|
0aee64f339 | ||
|
|
cbbdc665c8 | ||
|
|
1b2635784f | ||
|
|
ee5d2f8c84 | ||
|
|
dfc2a86e70 | ||
|
|
c0066b68f5 | ||
|
|
6ef5e4ef76 | ||
|
|
e3e77fde78 | ||
|
|
8ea55c7f2f | ||
|
|
d2a976b3cc | ||
|
|
d675662862 | ||
|
|
839b318785 | ||
|
|
971f59c11e | ||
|
|
ab58808b64 | ||
|
|
9cbb7cb10e | ||
|
|
70f2df11d1 | ||
|
|
827a2f2901 | ||
|
|
a9c33f6940 | ||
|
|
2bb73a2a92 | ||
|
|
90407986be | ||
|
|
b85ece440b | ||
|
|
a10d2651c1 | ||
|
|
b308a368d3 | ||
|
|
e6fea652de | ||
|
|
0856b718de | ||
|
|
6f1ccc5b3c | ||
|
|
da959b4e17 | ||
|
|
0bfd6d9e30 | ||
|
|
980f1d09bc | ||
|
|
b644c124e3 | ||
|
|
65005131bd | ||
|
|
18aa7f2a17 | ||
|
|
cd5bc2efa9 | ||
|
|
477361f119 | ||
|
|
d3632e4b3b | ||
|
|
0c2f90123b | ||
|
|
09d90e1a0a | ||
|
|
4fe167c361 | ||
|
|
58ffaeb4e2 | ||
|
|
76499ee629 | ||
|
|
fedfa3e3fd | ||
|
|
2902e42f91 | ||
|
|
37f4045499 | ||
|
|
12761ee167 | ||
|
|
0d254237a4 | ||
|
|
f5bb24676e | ||
|
|
303a3a8482 | ||
|
|
07273b6971 | ||
|
|
c7c9e9c3ed | ||
|
|
c3c990c50a | ||
|
|
6942fe12b5 | ||
|
|
f5cfb32882 | ||
|
|
e17f3eab96 | ||
|
|
08884da423 | ||
|
|
5f1d70dabb | ||
|
|
79bb9813ef | ||
|
|
1cda4ba245 | ||
|
|
1cc678d20b | ||
|
|
cd3e292489 | ||
|
|
40ea27a59c | ||
|
|
e95ca9316c | ||
|
|
9b2f907a48 | ||
|
|
90299ad0bb | ||
|
|
22d084f89b | ||
|
|
99770a7362 | ||
|
|
bbc7ebe5b1 | ||
|
|
d131b7561d | ||
|
|
ff8c614737 | ||
|
|
c12ad9d1c7 | ||
|
|
1703c16948 | ||
|
|
a48d7b112f | ||
|
|
f2d5e57f01 | ||
|
|
4111bbf720 | ||
|
|
cd32ad8751 | ||
|
|
fefb826177 | ||
|
|
e27fc04b5b | ||
|
|
168f412324 | ||
|
|
bd8434f4f4 | ||
|
|
c697398893 | ||
|
|
1e0176242a | ||
|
|
0e5e12b331 | ||
|
|
a2b240121a | ||
|
|
246dadea05 | ||
|
|
b5291077a9 | ||
|
|
ee548d513a | ||
|
|
bdd269ea22 | ||
|
|
e1d7bb91e8 | ||
|
|
593bc06302 | ||
|
|
8b6204a534 | ||
|
|
01ea9c9dce | ||
|
|
12e664b0a4 | ||
|
|
0ca92b9de9 | ||
|
|
2fc9e03d86 | ||
|
|
4218aa488f | ||
|
|
d95ede1f76 | ||
|
|
56f72e8702 | ||
|
|
964bf34325 | ||
|
|
3191165ba2 | ||
|
|
3ad27c5999 | ||
|
|
5b27f6c010 | ||
|
|
be44fad288 | ||
|
|
2a5fb76f95 | ||
|
|
5db7075432 | ||
|
|
1408175a35 | ||
|
|
ab1dc894e1 | ||
|
|
c5bc1c8b15 | ||
|
|
6d1ee60d67 | ||
|
|
a58e929205 | ||
|
|
53be8612c8 | ||
|
|
c7f6a7d11b | ||
|
|
e9011041c5 | ||
|
|
9803371fdb | ||
|
|
710edb72fa | ||
|
|
a4ddf59562 | ||
|
|
37dc9a27a7 | ||
|
|
27ccfa6395 | ||
|
|
116bc56cfe | ||
|
|
9ae0126be5 | ||
|
|
e8755f8ae0 | ||
|
|
6ba2bd3af9 | ||
|
|
4c5e485e76 | ||
|
|
05c6892f43 | ||
|
|
670a20c37f | ||
|
|
75509aba72 | ||
|
|
887f02e742 | ||
|
|
ef8da39d34 | ||
|
|
b7c759ece1 | ||
|
|
019da4a634 | ||
|
|
33aa6de50b | ||
|
|
0b3688c3b1 | ||
|
|
076e5d3655 | ||
|
|
c9608af0c8 | ||
|
|
908fbadaf5 | ||
|
|
ee97fdfc56 | ||
|
|
4ac137313f | ||
|
|
11d0029a4b | ||
|
|
8af5a9038b | ||
|
|
5d449988fb | ||
|
|
e969563df0 | ||
|
|
990626cf7d | ||
|
|
fc77ca989f | ||
|
|
2ce3976023 | ||
|
|
63ec531814 | ||
|
|
a4b55b30ca | ||
|
|
807556f361 | ||
|
|
2d854f2f37 | ||
|
|
5980c113fe | ||
|
|
1491465b55 | ||
|
|
728380222a | ||
|
|
005404f552 | ||
|
|
b55c229038 | ||
|
|
32538c9833 | ||
|
|
b31fc47197 | ||
|
|
5003824fa8 | ||
|
|
eea75b72a4 | ||
|
|
82d5ec3cc1 | ||
|
|
75721be8c0 | ||
|
|
de72eedb46 | ||
|
|
66827ab7de | ||
|
|
2a33433272 | ||
|
|
581dff8a5f | ||
|
|
fc425cbba2 | ||
|
|
87f55c1acb | ||
|
|
68d639e325 | ||
|
|
89f6cd044e | ||
|
|
bd3a1291da | ||
|
|
3abb7e4ca2 | ||
|
|
41265b0203 | ||
|
|
f2cb841b8a | ||
|
|
c69da29081 | ||
|
|
e304ef8cfb | ||
|
|
2ce76351da | ||
|
|
66cbd931a7 | ||
|
|
07bc28e386 | ||
|
|
2ef4ffe5eb | ||
|
|
128e7e394e | ||
|
|
998dc9b94b | ||
|
|
c6dafb1333 | ||
|
|
8ae7299d59 | ||
|
|
8f1b9c579b | ||
|
|
4b6573b521 | ||
|
|
325e843569 | ||
|
|
d014947a54 | ||
|
|
8858cc899e | ||
|
|
8f3e59803f | ||
|
|
95044bb551 | ||
|
|
b56448a929 | ||
|
|
c2b981dbdb | ||
|
|
28fb482720 | ||
|
|
d744a705a8 | ||
|
|
c62b89f02b | ||
|
|
f876b0114e | ||
|
|
9965988f26 | ||
|
|
828bb6fbb4 | ||
|
|
10d8d9efcd | ||
|
|
e59f3333cb | ||
|
|
31a9189d80 | ||
|
|
d162221fac | ||
|
|
0cdca0d053 | ||
|
|
4c934d460b | ||
|
|
76612b9cf7 | ||
|
|
9cf8ac9c51 | ||
|
|
b80e06256d | ||
|
|
08d9e5d6bc | ||
|
|
ed0cfd231e | ||
|
|
538d3f06f4 | ||
|
|
f5d3fb6217 | ||
|
|
ffa3579e6f | ||
|
|
c7adb8e3b1 | ||
|
|
c1427f658a | ||
|
|
eccce7b31f | ||
|
|
f81caf75a9 | ||
|
|
d4680c6de7 | ||
|
|
2716ec58a0 | ||
|
|
f25dbd8fed | ||
|
|
e35180c919 | ||
|
|
2f54ceb7c4 | ||
|
|
6506ef468d | ||
|
|
da46dfbde1 | ||
|
|
09ecc2c9b5 | ||
|
|
0b2899a961 | ||
|
|
c6ed3fa27f | ||
|
|
43cd3b9cad | ||
|
|
294d6fa05e | ||
|
|
009a479c17 | ||
|
|
72ee14e6be | ||
|
|
2b01a1c395 | ||
|
|
f69793d38e | ||
|
|
eda0d6d23b | ||
|
|
abba36d786 | ||
|
|
33ea9a6f33 | ||
|
|
9a0da7270b | ||
|
|
9caf440200 | ||
|
|
c9e53cf355 | ||
|
|
432eb318ac | ||
|
|
cea0db4e0d | ||
|
|
842c0b674f | ||
|
|
36ed99d1f6 | ||
|
|
86d0f37b37 | ||
|
|
5303c9c461 | ||
|
|
67667b6df2 | ||
|
|
d9d27b4229 | ||
|
|
a2a1b19758 | ||
|
|
fb9d39d6d5 | ||
|
|
0f3d425f64 | ||
|
|
08e3580646 | ||
|
|
0fa4a4c6db | ||
|
|
d452e01a3d | ||
|
|
f7da373f8b | ||
|
|
b80cf7ba15 | ||
|
|
fe1cd4b27a | ||
|
|
925206f9c8 | ||
|
|
f24a317e2d | ||
|
|
aeaa3ce982 | ||
|
|
8c6913a9af | ||
|
|
7795232a58 | ||
|
|
057330c68f | ||
|
|
91c80279bd | ||
|
|
5715df0b10 | ||
|
|
9f0c540fba | ||
|
|
f9d19a957a | ||
|
|
76b1165572 | ||
|
|
80c85b3bb9 | ||
|
|
900652a82b | ||
|
|
6cbef7d987 | ||
|
|
01d66834f0 | ||
|
|
a40eae9b8c | ||
|
|
23b46bde2b | ||
|
|
b38ada30e6 | ||
|
|
3452841752 | ||
|
|
3b9cab3432 | ||
|
|
2f6df20085 | ||
|
|
609ea40d1c | ||
|
|
515a309831 | ||
|
|
02c2228ab7 | ||
|
|
ca246ba67d | ||
|
|
f9008b67c4 | ||
|
|
e228197906 | ||
|
|
d98e324618 | ||
|
|
1880fdfda9 | ||
|
|
d86b524558 | ||
|
|
70fa38a589 | ||
|
|
ea93140b8a | ||
|
|
45c229dc9f | ||
|
|
2b5ac95165 | ||
|
|
38c65e7e4b | ||
|
|
f40eaf4499 | ||
|
|
3a667ef389 | ||
|
|
f35e03d816 | ||
|
|
2bfd4d71d8 | ||
|
|
2bc84014c2 | ||
|
|
a3c72c22c1 | ||
|
|
ddf2b7e9ff | ||
|
|
04d1bee7b4 | ||
|
|
0c9ecf3abc | ||
|
|
c8b4798b61 | ||
|
|
550c8ae45d | ||
|
|
0b4f4683b3 | ||
|
|
5504b0dd29 | ||
|
|
f0dcddd391 | ||
|
|
75be1e1bd6 | ||
|
|
c569d803c5 | ||
|
|
48cd6e112b | ||
|
|
d41354e1d7 | ||
|
|
9a5e36c0a4 | ||
|
|
f963e40a5f | ||
|
|
f1e2402316 | ||
|
|
31bb8c75f5 | ||
|
|
fb4ab44aa5 | ||
|
|
71216b1458 | ||
|
|
c969ff4011 | ||
|
|
dc45eb6ed4 | ||
|
|
29aaaae4b4 | ||
|
|
1fe53b9549 | ||
|
|
6274dbebc0 | ||
|
|
a1cd3ab6fa | ||
|
|
c058cb8848 | ||
|
|
029061177b | ||
|
|
9c8e813642 | ||
|
|
7be61b9657 | ||
|
|
2f67d24ec9 | ||
|
|
17d6f1cdf1 | ||
|
|
a0c34b40c6 | ||
|
|
00856f8cb9 | ||
|
|
3df6387ee0 | ||
|
|
fe1c826b1b | ||
|
|
0bda101d4d | ||
|
|
5e738129d9 | ||
|
|
39b5014add | ||
|
|
3c6560ade9 | ||
|
|
183d1a91c1 | ||
|
|
d711ab8b1f | ||
|
|
6c1a48952e | ||
|
|
a343aa5eb0 | ||
|
|
273a0b0b99 | ||
|
|
2f1e64dc1b | ||
|
|
a46d4ecd3e | ||
|
|
5f04954a5c | ||
|
|
d065a7ca22 | ||
|
|
2f8373f9c5 | ||
|
|
2d36e98246 | ||
|
|
f2d8f1ee60 | ||
|
|
e7881c350c | ||
|
|
ffe3e68c35 | ||
|
|
4d6fafd778 | ||
|
|
2bbf77ab4c | ||
|
|
f9df8d3351 | ||
|
|
8f4299ef62 | ||
|
|
fabaa61279 | ||
|
|
f17de87952 | ||
|
|
93a607083a | ||
|
|
7544558173 | ||
|
|
c96b0e8f8b | ||
|
|
b181147922 | ||
|
|
862d12a904 | ||
|
|
ddbc71b273 | ||
|
|
c68ea8abbd | ||
|
|
cd5c7f599a | ||
|
|
1bb3a23bc4 | ||
|
|
b191ec94a5 | ||
|
|
8f910fbb75 | ||
|
|
693d827144 | ||
|
|
effcaf0cde | ||
|
|
5be8fe39d0 | ||
|
|
8d12f96d8b | ||
|
|
c1b30458d6 | ||
|
|
48e76f9096 | ||
|
|
6fc8cc7e8e | ||
|
|
a3874dd089 | ||
|
|
bdd5e31b6f | ||
|
|
ed0e9cff4b | ||
|
|
62bbee56db | ||
|
|
ec4a233e04 | ||
|
|
9efab243ae | ||
|
|
219970bba5 | ||
|
|
dcbd196c02 | ||
|
|
814d65cc28 | ||
|
|
8c222add7c | ||
|
|
ab07557aa5 | ||
|
|
7be405e4e4 | ||
|
|
726f44bc60 | ||
|
|
c4c597da9e | ||
|
|
e5617e236c | ||
|
|
b1af4ada60 | ||
|
|
284b962d64 | ||
|
|
86ff022dc6 | ||
|
|
dcbbbab11e | ||
|
|
14b2afe78d | ||
|
|
ba4ffa7598 | ||
|
|
92ae0e5460 | ||
|
|
1ace028cef | ||
|
|
43ca2b9831 | ||
|
|
ecd5af76ab | ||
|
|
be452a22f0 | ||
|
|
6d6f793c69 | ||
|
|
30abd9e310 | ||
|
|
d0e3b2672d | ||
|
|
3b8a3ca26f | ||
|
|
33a096da22 | ||
|
|
72ba3ba086 | ||
|
|
5dd430e6a6 | ||
|
|
77056a7100 | ||
|
|
76b9790ffb | ||
|
|
54d2962a0d | ||
|
|
7846b2a440 | ||
|
|
8bbfe0c26d | ||
|
|
5c67334889 | ||
|
|
0b1b73a05d | ||
|
|
203dc42e75 | ||
|
|
9f6e9f5db6 | ||
|
|
ee09b9f9f4 | ||
|
|
c534ef672e | ||
|
|
c34a5ae2a6 | ||
|
|
1c65048813 | ||
|
|
3b8d0b83d4 | ||
|
|
b2c39af069 | ||
|
|
5c3df7e7a5 | ||
|
|
ffa5a93c75 | ||
|
|
794b725928 | ||
|
|
ffc06525fb | ||
|
|
3fe99712ba | ||
|
|
765c2b7d1f | ||
|
|
f789bb8c53 | ||
|
|
745f109686 | ||
|
|
8ed3bd53ac | ||
|
|
40d7d62af2 | ||
|
|
09fb118d22 | ||
|
|
0c3731b0bd | ||
|
|
349fd09440 | ||
|
|
bd3773f32a | ||
|
|
572708c283 | ||
|
|
fafdacfc41 | ||
|
|
c3ba483b81 | ||
|
|
e309a03515 | ||
|
|
82a304e054 | ||
|
|
b76d973f3a | ||
|
|
237e477876 | ||
|
|
47bcccdce3 | ||
|
|
ba8ca1f9f2 | ||
|
|
4837f2101c | ||
|
|
37d2914611 | ||
|
|
849164e4de | ||
|
|
683ba112aa | ||
|
|
e743722449 | ||
|
|
a5ee2ef93b | ||
|
|
3e66f5e8cf | ||
|
|
83b0aed52a | ||
|
|
498763505a | ||
|
|
8cc4ad4d80 | ||
|
|
6ec0c25173 | ||
|
|
93bcd78f89 | ||
|
|
ebf6a52237 | ||
|
|
a2906093ec | ||
|
|
a161c318a1 | ||
|
|
3f1ee2f784 | ||
|
|
60de2e4a6e | ||
|
|
d5bb79edd5 | ||
|
|
7264a00813 | ||
|
|
cf21767975 | ||
|
|
8fbdd996de | ||
|
|
2c3dcae117 | ||
|
|
b024b5d006 | ||
|
|
d5bab2317e | ||
|
|
0c8b4a48de | ||
|
|
f9b3218ded | ||
|
|
acc37fb387 | ||
|
|
f50b4dfe34 | ||
|
|
9ce7351aaa | ||
|
|
c691a1adb2 | ||
|
|
9a2a21ec5d | ||
|
|
a9fd0aa132 | ||
|
|
198674d889 | ||
|
|
203a5683ac | ||
|
|
eeb8cda175 | ||
|
|
b268971323 | ||
|
|
051fc53a4f | ||
|
|
55602f1f16 | ||
|
|
42428345ff | ||
|
|
ca950d909b | ||
|
|
20ff530962 | ||
|
|
a5dbbf4881 | ||
|
|
e91b1fc89a | ||
|
|
4e35e4ae86 | ||
|
|
6d15cb7e33 | ||
|
|
095acad8a6 | ||
|
|
c187d1ad8a | ||
|
|
f6967d2cfb | ||
|
|
388d2b0b59 | ||
|
|
d9aecbcbca | ||
|
|
eabdf3e78c | ||
|
|
a1fb7c5fdf | ||
|
|
89394245b1 | ||
|
|
91f1eb2d6a | ||
|
|
ab5f6db54b | ||
|
|
626642af76 | ||
|
|
473f02396f | ||
|
|
aa4b1bf9d8 | ||
|
|
8e5a72fc35 | ||
|
|
7302653879 | ||
|
|
b2b563547c | ||
|
|
cc29ad151a | ||
|
|
a4a93d8945 | ||
|
|
3389cd0aea | ||
|
|
d26956ff72 | ||
|
|
66284bfbe3 | ||
|
|
14be75629b | ||
|
|
d77ab8dbff | ||
|
|
c2ac548ac7 | ||
|
|
ad4d8e939e | ||
|
|
aa7a00b299 | ||
|
|
1ff421365e | ||
|
|
0a12d0139d | ||
|
|
181ab4f545 | ||
|
|
3e29e98f2c | ||
|
|
a66c1de660 | ||
|
|
0c322a33bc | ||
|
|
cd33a6dd07 | ||
|
|
c1dceaf11f | ||
|
|
3181dd17bc | ||
|
|
c93fa1af59 | ||
|
|
9f4a8d3dfc | ||
|
|
4da829792f | ||
|
|
1a073224c3 | ||
|
|
175de861bf | ||
|
|
aa73c34db2 | ||
|
|
ed2176af8c | ||
|
|
49f7d56fdd | ||
|
|
71cc166f72 | ||
|
|
8ee00839dc | ||
|
|
6239662a7f | ||
|
|
216c2aa2cd | ||
|
|
70b8b43b48 | ||
|
|
430c2e709f | ||
|
|
b975950b07 | ||
|
|
ed42cf42d2 | ||
|
|
d80c282644 | ||
|
|
a05edb3872 | ||
|
|
43b8987b4b | ||
|
|
219ea1c458 | ||
|
|
bea93f6ad7 | ||
|
|
e4267848f0 | ||
|
|
bc5953b510 | ||
|
|
e41b7cd117 | ||
|
|
cab78e7893 | ||
|
|
199f5cc223 | ||
|
|
962649f7ca | ||
|
|
7b32c0e37b | ||
|
|
12f353a1ae | ||
|
|
c26e170c87 | ||
|
|
6a706de09e | ||
|
|
2a4675e25b | ||
|
|
0bc36b3299 | ||
|
|
dc902b16d4 | ||
|
|
86998a032e | ||
|
|
1727ec41c4 | ||
|
|
3eb812be5b | ||
|
|
64c2f6ba5c | ||
|
|
2db7da0766 | ||
|
|
d1e7bad18f | ||
|
|
d7cef25665 | ||
|
|
23f41145b0 | ||
|
|
a969af8159 | ||
|
|
001fa00355 | ||
|
|
a6dddd32b3 | ||
|
|
cd825e34da | ||
|
|
2bba088319 | ||
|
|
4905bd9bb8 | ||
|
|
3f625a000b | ||
|
|
3bfee10a0d | ||
|
|
d5a05da5b8 | ||
|
|
d8042a36c3 | ||
|
|
85bf01eb65 | ||
|
|
4f2b8b7077 | ||
|
|
417ff8a6c5 | ||
|
|
681c4a3f0d | ||
|
|
619dd1ace1 | ||
|
|
1cd18a643d | ||
|
|
3519d61636 | ||
|
|
46913671a8 | ||
|
|
b7ff6b1a51 | ||
|
|
62be9eb589 | ||
|
|
ab6d483c32 | ||
|
|
2d77f84736 | ||
|
|
c2f7963a43 | ||
|
|
b9e27621ee | ||
|
|
2766e24007 | ||
|
|
45911ac3c4 | ||
|
|
ad89c5a80f | ||
|
|
3413f4a4fe | ||
|
|
2a88cca50c | ||
|
|
634978c14f | ||
|
|
093f7d9758 | ||
|
|
40960f60f8 | ||
|
|
25a4c2930a | ||
|
|
342344db0c | ||
|
|
7785d2a3f8 | ||
|
|
bd6b0d3d12 | ||
|
|
a871b92dc9 | ||
|
|
47d15c47f3 | ||
|
|
684283c585 | ||
|
|
d2d9b0eaad | ||
|
|
22e6b1eec5 | ||
|
|
f6301c5a7c | ||
|
|
b191415173 | ||
|
|
59542bc99a | ||
|
|
0e4b5b3765 | ||
|
|
a986251773 | ||
|
|
0e651fdc99 | ||
|
|
b1e279bd2a | ||
|
|
e76cf08934 | ||
|
|
4cf930a9dc | ||
|
|
599723515e | ||
|
|
e1e8d53da5 | ||
|
|
20a2c0092e | ||
|
|
a40ad07e2b | ||
|
|
65d80aad03 | ||
|
|
905c041a76 | ||
|
|
0dae6ebaee | ||
|
|
d41954b09c | ||
|
|
6e8771b8d9 | ||
|
|
cf5bcc09e8 | ||
|
|
413a8d0a2f | ||
|
|
1852652029 | ||
|
|
76c88a72c6 | ||
|
|
f6c249bd77 | ||
|
|
ee7065bc12 | ||
|
|
8446f07a91 | ||
|
|
09b9aefed7 | ||
|
|
f810ce2d0d | ||
|
|
ed86635b3c | ||
|
|
080aeee5e3 | ||
|
|
2ebb363350 | ||
|
|
da38815ce0 | ||
|
|
db600d5ea0 | ||
|
|
22b66b6672 | ||
|
|
06aaae1335 | ||
|
|
810087b2a7 | ||
|
|
2f970f7ab8 | ||
|
|
5fb8316e46 | ||
|
|
57806df17e | ||
|
|
0857cf8835 | ||
|
|
64d78c31bc | ||
|
|
47a736f567 | ||
|
|
423f4aaf1f | ||
|
|
1d55c987a6 | ||
|
|
e5044b4b6f | ||
|
|
fbd7d0f90d | ||
|
|
87d05fbbdc | ||
|
|
1475a85c58 | ||
|
|
b4bc2e66e6 | ||
|
|
780a42d823 | ||
|
|
3ca9537d8a | ||
|
|
4c28932c4c | ||
|
|
6bccd757fd | ||
|
|
00630cb4f3 | ||
|
|
254d19f8a3 | ||
|
|
f8583fbef0 | ||
|
|
fe11fcd6c6 | ||
|
|
c27302136c | ||
|
|
fbbe2166e6 | ||
|
|
6e02cbde8a | ||
|
|
aced1088f7 | ||
|
|
ec41eec1a0 | ||
|
|
505b5ea767 | ||
|
|
08165211eb | ||
|
|
ec0158e2e8 | ||
|
|
b7bed72c6d | ||
|
|
553b26c1cb | ||
|
|
58dc00c17c | ||
|
|
e79e4fa05e | ||
|
|
95ea1b2dfb | ||
|
|
a408a46168 | ||
|
|
bc539569e1 | ||
|
|
7a275e8e2a | ||
|
|
87fcfdf9e6 | ||
|
|
664981628a | ||
|
|
a255a5e3c1 | ||
|
|
c252492a42 | ||
|
|
b328fd96bc | ||
|
|
2844df865b | ||
|
|
da377a9fa9 | ||
|
|
deac6163d6 | ||
|
|
448fcc07e7 | ||
|
|
830c27361e | ||
|
|
5b2efd65b1 | ||
|
|
2724c6211a | ||
|
|
9a3451a8ae | ||
|
|
3d5effb678 | ||
|
|
965412377d | ||
|
|
d8009500a4 | ||
|
|
7347ae2301 | ||
|
|
babd6edbc2 | ||
|
|
2a1e91cb34 | ||
|
|
ab36e1fa0c | ||
|
|
2ab60750d4 | ||
|
|
b9dd673518 | ||
|
|
bf3edfd0ef | ||
|
|
710b933b08 | ||
|
|
ece66a3c38 | ||
|
|
ebfa64cc08 | ||
|
|
10000c098d | ||
|
|
7c585905ac | ||
|
|
1ca06e1f1a | ||
|
|
fb73a7f83e | ||
|
|
2362a8d169 | ||
|
|
f98066cb99 | ||
|
|
2222a999b9 | ||
|
|
00b1d7538d | ||
|
|
886c7d97a6 | ||
|
|
ae8a5d047b | ||
|
|
4f99d865cb | ||
|
|
a30aab1da6 | ||
|
|
bff4303dbb | ||
|
|
2359b16526 | ||
|
|
fb4b9d0173 | ||
|
|
aafa24094c | ||
|
|
c3f462d260 | ||
|
|
97de71d09e | ||
|
|
5a8acea84e | ||
|
|
8274f6a1ff | ||
|
|
0b86cd69fc | ||
|
|
5e77d1cd5b | ||
|
|
50f44fff9e | ||
|
|
21b0d6ceaf | ||
|
|
6e483a025d | ||
|
|
a748bed807 | ||
|
|
177d6dba15 | ||
|
|
dd905a1852 | ||
|
|
5bad1d0b53 | ||
|
|
3577b91a3c | ||
|
|
ece1cbe48e | ||
|
|
f75ca3a4f1 | ||
|
|
e173081cae | ||
|
|
954e06bbcc | ||
|
|
bf87b134de | ||
|
|
acd6f44c7e | ||
|
|
e37d97c7c7 | ||
|
|
4f9feeff19 | ||
|
|
761f68b24f | ||
|
|
d9f656031d | ||
|
|
848712e417 | ||
|
|
0e0a812a9c | ||
|
|
26f80b7107 | ||
|
|
a2ec618c49 | ||
|
|
43bea50605 | ||
|
|
94d0d5ac6b | ||
|
|
7c3a78b83f | ||
|
|
0c6de7a1ed | ||
|
|
36aff66835 | ||
|
|
63ebec2f76 | ||
|
|
d9542d6a9c | ||
|
|
09d9e4aa02 | ||
|
|
7140f04243 | ||
|
|
76ff69dedb | ||
|
|
1c4e51aec5 | ||
|
|
7942f4c495 | ||
|
|
bc9daf1583 | ||
|
|
89288a0c59 | ||
|
|
ea3cfbd0ca | ||
|
|
06cc677278 | ||
|
|
edf7c9a8b7 | ||
|
|
977d247ee0 | ||
|
|
3d9fc18149 | ||
|
|
f86c14b672 | ||
|
|
e37d0148e1 | ||
|
|
800f66467c | ||
|
|
df2a9a8a75 | ||
|
|
9e1ee1c513 | ||
|
|
ed2fb62034 | ||
|
|
cb227660c7 | ||
|
|
313862dd07 | ||
|
|
279b591200 | ||
|
|
0a1247b835 | ||
|
|
b4e8371b04 | ||
|
|
a34ac88cbf | ||
|
|
f7b284f774 | ||
|
|
e8048a7bf4 | ||
|
|
e00a09c5b9 | ||
|
|
35d6e27cd5 | ||
|
|
422e87dd97 | ||
|
|
3280c6af2e | ||
|
|
d8f5d74ec3 | ||
|
|
bd93095abb | ||
|
|
d7cfa6b669 | ||
|
|
91ec16310c | ||
|
|
964a79bc76 | ||
|
|
35aae8b0eb | ||
|
|
3f9b1cb74b | ||
|
|
237539ac45 | ||
|
|
d3d6601006 | ||
|
|
b3f7d1f070 | ||
|
|
5229b8158e | ||
|
|
2e8645b50e | ||
|
|
ae18ab2b5e | ||
|
|
6d2762b1e1 | ||
|
|
4fc8a62374 | ||
|
|
bf92185d38 | ||
|
|
5c8606e2fa | ||
|
|
e63da60173 | ||
|
|
06ad0a0509 | ||
|
|
96a3b89afd | ||
|
|
d6dabf7b24 | ||
|
|
00b4025325 | ||
|
|
b427c86ab3 | ||
|
|
342910771b | ||
|
|
7b3f3d4965 | ||
|
|
0661dda164 | ||
|
|
c2d3eaeccd | ||
|
|
48703ed04e | ||
|
|
987602b55b | ||
|
|
c3664f73a9 | ||
|
|
a090412441 | ||
|
|
894b2e99ed | ||
|
|
4c9942dd3f | ||
|
|
aa40a6b749 | ||
|
|
82161dec80 | ||
|
|
2eccc90ccc | ||
|
|
7b60a1e5f8 | ||
|
|
33096754dd | ||
|
|
2a891a478c | ||
|
|
87d1158313 | ||
|
|
fa59434753 | ||
|
|
dcb1d38a37 | ||
|
|
3196731545 | ||
|
|
301406d051 | ||
|
|
a9c7588c27 | ||
|
|
e6d40afe76 | ||
|
|
a921d6da80 | ||
|
|
47b0f7bdeb | ||
|
|
9aacf2a64d | ||
|
|
475262afb7 | ||
|
|
78fc250778 | ||
|
|
06d0430e52 | ||
|
|
e111602784 | ||
|
|
28ce468e73 | ||
|
|
5053e20778 | ||
|
|
92a3be8af9 | ||
|
|
758c8eb845 | ||
|
|
c5da14ae4b | ||
|
|
96139986b3 | ||
|
|
85d4cbd92d | ||
|
|
c19869c1cc | ||
|
|
223f5588df | ||
|
|
be91d4edaf | ||
|
|
04c2febe55 | ||
|
|
745a073455 | ||
|
|
a90c93c97a | ||
|
|
91f3b3ef1c | ||
|
|
c4b32332d2 | ||
|
|
21e2306a50 | ||
|
|
5c2ae65ad8 | ||
|
|
8e89b90b80 |
5
.github/FUNDING.yml
vendored
Normal file
5
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: tiann
|
||||||
|
patreon: weishu
|
||||||
|
custom: https://vxposed.com/donate.html
|
||||||
33
.github/ISSUE_TEMPLATE/add_device.yml
vendored
Normal file
33
.github/ISSUE_TEMPLATE/add_device.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: Contribute to Unofficially Supported Device
|
||||||
|
description: Add your device kernel source to KernelSU's Unofficially Supported Device List
|
||||||
|
title: "[Add Device]: "
|
||||||
|
labels: ["add-device"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for supporting KernelSU!
|
||||||
|
- type: input
|
||||||
|
id: repo-url
|
||||||
|
attributes:
|
||||||
|
label: Repository URL
|
||||||
|
description: Your repository URL
|
||||||
|
placeholder: https://github.com/tiann/KernelSU
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: Device
|
||||||
|
description: Please describe the device maintained by you.
|
||||||
|
placeholder: GKI 2.0 Device
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
id: terms
|
||||||
|
attributes:
|
||||||
|
label: Code of Conduct
|
||||||
|
description: By submitting this issue, you should be the maintainer of the repository.
|
||||||
|
options:
|
||||||
|
- label: I'm the maintainer of this repository
|
||||||
|
required: true
|
||||||
72
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
72
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Create a report to help us improve KernelSU
|
||||||
|
labels: [Bug]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Please check before submitting an issue
|
||||||
|
options:
|
||||||
|
- label: I have searched the issues and haven't found anything relevant
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- label: I will upload bugreport file in KernelSU Manager - Settings - Report log
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- label: I know how to reproduce the issue which may not be specific to my device
|
||||||
|
required: false
|
||||||
|
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: A clear and concise description of what the bug is
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: To Reproduce
|
||||||
|
description: Steps to reproduce the behaviour
|
||||||
|
placeholder: |
|
||||||
|
- 1. Go to '...'
|
||||||
|
- 2. Click on '....'
|
||||||
|
- 3. Scroll down to '....'
|
||||||
|
- 4. See error
|
||||||
|
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Expected behavior
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Logs
|
||||||
|
description: If applicable, add crash or any other logs to help us figure out the problem.
|
||||||
|
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Device info
|
||||||
|
value: |
|
||||||
|
- Device:
|
||||||
|
- OS Version:
|
||||||
|
- KernelSU Version:
|
||||||
|
- Kernel Version:
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add any other context about the problem here.
|
||||||
11
.github/ISSUE_TEMPLATE/custom.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/custom.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
name: Custom issue template
|
||||||
|
description: WARNING! If you are reporting a bug but use this template, the issue will be closed directly.
|
||||||
|
title: '[Custom]'
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: "Describe your problem."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: Feature Request
|
||||||
|
description: "Suggest an idea for this project"
|
||||||
|
title: "[Feature]"
|
||||||
|
labels: "feature"
|
||||||
|
assignees: tiann
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
id: feature-info
|
||||||
|
attributes:
|
||||||
|
value: "## Feature Infomation"
|
||||||
|
- type: textarea
|
||||||
|
id: feature-main
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "Is your feature request related to a problem? Please describe."
|
||||||
|
description: "A clear and concise description of what the problem is."
|
||||||
|
placeholder: "I'm always frustrated when [...]"
|
||||||
|
- type: textarea
|
||||||
|
id: feature-solution
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "Describe the solution you'd like."
|
||||||
|
description: "A clear and concise description of what you want to happen."
|
||||||
|
- type: textarea
|
||||||
|
id: feature-describe
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "Describe alternatives you've considered."
|
||||||
|
description: "A clear and concise description of any alternative solutions or features you've considered."
|
||||||
|
- type: textarea
|
||||||
|
id: feature-extra
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "Additional context"
|
||||||
|
description: "Add any other context or screenshots about the feature request here."
|
||||||
|
|
||||||
64
.github/scripts/build_a12.sh
vendored
Normal file
64
.github/scripts/build_a12.sh
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
build_from_image() {
|
||||||
|
export TITLE
|
||||||
|
TITLE=kernel-aarch64-${1//Image-/}
|
||||||
|
echo "[+] title: $TITLE"
|
||||||
|
|
||||||
|
export PATCH_LEVEL
|
||||||
|
PATCH_LEVEL=$(echo "$1" | awk -F_ '{ print $2}')
|
||||||
|
echo "[+] patch level: $PATCH_LEVEL"
|
||||||
|
|
||||||
|
echo '[+] Download prebuilt ramdisk'
|
||||||
|
GKI_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-"${PATCH_LEVEL}"_r1.zip
|
||||||
|
FALLBACK_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-2023-01_r1.zip
|
||||||
|
status=$(curl -sL -w "%{http_code}" "$GKI_URL" -o /dev/null)
|
||||||
|
if [ "$status" = "200" ]; then
|
||||||
|
curl -Lo gki-kernel.zip "$GKI_URL"
|
||||||
|
else
|
||||||
|
echo "[+] $GKI_URL not found, using $FALLBACK_URL"
|
||||||
|
curl -Lo gki-kernel.zip "$FALLBACK_URL"
|
||||||
|
fi
|
||||||
|
unzip gki-kernel.zip && rm gki-kernel.zip
|
||||||
|
|
||||||
|
echo '[+] Unpack prebuilt boot.img'
|
||||||
|
BOOT_IMG=$(find . -maxdepth 1 -name "boot*.img")
|
||||||
|
$UNPACK_BOOTIMG --boot_img="$BOOT_IMG"
|
||||||
|
rm "$BOOT_IMG"
|
||||||
|
|
||||||
|
echo '[+] Building Image.gz'
|
||||||
|
$GZIP -n -k -f -9 Image >Image.gz
|
||||||
|
|
||||||
|
echo '[+] Building boot.img'
|
||||||
|
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
|
||||||
|
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
|
||||||
|
echo '[+] Building boot-gz.img'
|
||||||
|
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
|
||||||
|
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
|
||||||
|
echo '[+] Building boot-lz4.img'
|
||||||
|
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
|
||||||
|
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
|
||||||
|
echo '[+] Compress images'
|
||||||
|
for image in boot*.img; do
|
||||||
|
$GZIP -n -f -9 "$image"
|
||||||
|
mv "$image".gz "${1//Image-/}"-"$image".gz
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[+] Images to upload"
|
||||||
|
find . -type f -name "*.gz"
|
||||||
|
|
||||||
|
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
|
||||||
|
}
|
||||||
|
|
||||||
|
for dir in Image*; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
echo "----- Building $dir -----"
|
||||||
|
cd "$dir"
|
||||||
|
build_from_image "$dir"
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
43
.github/scripts/build_a13.sh
vendored
Normal file
43
.github/scripts/build_a13.sh
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
build_from_image() {
|
||||||
|
export TITLE
|
||||||
|
TITLE=kernel-aarch64-${1//Image-/}
|
||||||
|
|
||||||
|
echo "[+] title: $TITLE"
|
||||||
|
echo '[+] Building Image.gz'
|
||||||
|
$GZIP -n -k -f -9 Image >Image.gz
|
||||||
|
|
||||||
|
echo '[+] Building boot.img'
|
||||||
|
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img
|
||||||
|
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
|
||||||
|
echo '[+] Building boot-gz.img'
|
||||||
|
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img
|
||||||
|
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
|
||||||
|
echo '[+] Building boot-lz4.img'
|
||||||
|
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img
|
||||||
|
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
|
||||||
|
echo '[+] Compress images'
|
||||||
|
for image in boot*.img; do
|
||||||
|
$GZIP -n -f -9 "$image"
|
||||||
|
mv "$image".gz "${1//Image-/}"-"$image".gz
|
||||||
|
done
|
||||||
|
|
||||||
|
echo '[+] Images to upload'
|
||||||
|
find . -type f -name "*.gz"
|
||||||
|
|
||||||
|
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
|
||||||
|
}
|
||||||
|
|
||||||
|
for dir in Image*; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
echo "----- Building $dir -----"
|
||||||
|
cd "$dir"
|
||||||
|
build_from_image "$dir"
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
done
|
||||||
59
.github/workflows/add-device.yml
vendored
Normal file
59
.github/workflows/add-device.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
name: handle-add-device-issue
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [labeled]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
handle-add-device:
|
||||||
|
if: github.event.label.name == 'add-device'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
ISSUE_CONTENT: ${{ github.event.issue.body }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Parse issue body
|
||||||
|
id: handle-add-device
|
||||||
|
run: |
|
||||||
|
python3 scripts/add_device_handler.py website/docs/repos.json || true
|
||||||
|
- name: Commit
|
||||||
|
if: steps.handle-add-device.outputs.success == 'true'
|
||||||
|
run: |
|
||||||
|
git config --local user.name "GitHub Actions"
|
||||||
|
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add website/docs/repos.json
|
||||||
|
git commit -m "add device: ${{ steps.handle-add-device.outputs.device }}"
|
||||||
|
- name: Make pull request
|
||||||
|
if: steps.handle-add-device.outputs.success == 'true'
|
||||||
|
id: cpr
|
||||||
|
uses: peter-evans/create-pull-request@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
commit-message: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
|
||||||
|
title: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
|
||||||
|
body: |
|
||||||
|
${{ steps.handle-add-device.outputs.device }} has been added to the website.
|
||||||
|
Related issue: ${{ github.event.issue.html_url }}
|
||||||
|
branch: "add-device-${{ github.event.issue.number }}"
|
||||||
|
labels: add-device
|
||||||
|
delete-branch: true
|
||||||
|
- name: Check outputs
|
||||||
|
if: ${{ steps.cpr.outputs.pull-request-number }}
|
||||||
|
run: |
|
||||||
|
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
|
||||||
|
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
|
||||||
|
- uses: Kernel-SU/actions-comment-on-issue@master
|
||||||
|
if: ${{ steps.cpr.outputs.pull-request-number }}
|
||||||
|
with:
|
||||||
|
message: "Automatically created pull request: ${{ steps.cpr.outputs.pull-request-url }}"
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- uses: Kernel-SU/actions-comment-on-issue@master
|
||||||
|
if: steps.handle-add-device.outputs.success != 'true'
|
||||||
|
with:
|
||||||
|
message: "Cannot create pull request. Please check the issue content. Or you can create a pull request manually."
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: close issue
|
||||||
|
uses: peter-evans/close-issue@v1
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.issue.number }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
31
.github/workflows/build-debug-kernel.yml
vendored
Normal file
31
.github/workflows/build-debug-kernel.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: Build debug kernel
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-debug-kernel-a12:
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
with:
|
||||||
|
version: android12-5.10
|
||||||
|
version_name: android12-5.10.185
|
||||||
|
tag: android12-5.10-2023-09
|
||||||
|
os_patch_level: 2023-09
|
||||||
|
patch_path: "5.10"
|
||||||
|
debug: true
|
||||||
|
build-debug-kernel-a13:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 187
|
||||||
|
os_patch_level: 2023-08
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 119
|
||||||
|
os_patch_level: 2023-09
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
with:
|
||||||
|
version: android13-${{ matrix.version }}
|
||||||
|
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||||
|
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||||
|
patch_path: ${{ matrix.version }}
|
||||||
|
debug: true
|
||||||
135
.github/workflows/build-kernel-a12.yml
vendored
Normal file
135
.github/workflows/build-kernel-a12.yml
vendored
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
name: Build Kernel - Android 12
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main", "ci", "checkci"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-a12.yml"
|
||||||
|
- ".github/workflows/gki-kernel.yml"
|
||||||
|
- ".github/scripts/build_a12.sh"
|
||||||
|
- "kernel/**"
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-a12.yml"
|
||||||
|
- ".github/workflows/gki-kernel.yml"
|
||||||
|
- ".github/scripts/build-a12.sh"
|
||||||
|
- "kernel/**"
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
build-kernel:
|
||||||
|
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- sub_level: 66
|
||||||
|
os_patch_level: 2022-01
|
||||||
|
- sub_level: 81
|
||||||
|
os_patch_level: 2022-03
|
||||||
|
- sub_level: 101
|
||||||
|
os_patch_level: 2022-05
|
||||||
|
- sub_level: 110
|
||||||
|
os_patch_level: 2022-07
|
||||||
|
- sub_level: 117
|
||||||
|
os_patch_level: 2022-09
|
||||||
|
- sub_level: 136
|
||||||
|
os_patch_level: 2022-11
|
||||||
|
- sub_level: 149
|
||||||
|
os_patch_level: 2023-01
|
||||||
|
- sub_level: 160
|
||||||
|
os_patch_level: 2023-03
|
||||||
|
- sub_level: 168
|
||||||
|
os_patch_level: 2023-05
|
||||||
|
- sub_level: 177
|
||||||
|
os_patch_level: 2023-07
|
||||||
|
- sub_level: 185
|
||||||
|
os_patch_level: 2023-09
|
||||||
|
- sub_level: 198
|
||||||
|
os_patch_level: 2023-11
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
version: android12-5.10
|
||||||
|
version_name: android12-5.10.${{ matrix.sub_level }}
|
||||||
|
tag: android12-5.10-${{ matrix.os_patch_level }}
|
||||||
|
os_patch_level: ${{ matrix.os_patch_level }}
|
||||||
|
patch_path: "5.10"
|
||||||
|
|
||||||
|
upload-artifacts:
|
||||||
|
needs: build-kernel
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: List artifacts
|
||||||
|
run: |
|
||||||
|
tree
|
||||||
|
|
||||||
|
- name: Download prebuilt toolchain
|
||||||
|
run: |
|
||||||
|
AOSP_MIRROR=https://android.googlesource.com
|
||||||
|
BRANCH=main-kernel-build-2023
|
||||||
|
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
||||||
|
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
||||||
|
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
||||||
|
pip3 install telethon==1.31.1
|
||||||
|
|
||||||
|
- name: Set boot sign key
|
||||||
|
env:
|
||||||
|
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
||||||
|
run: |
|
||||||
|
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
||||||
|
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
|
- name: Build boot images
|
||||||
|
run: |
|
||||||
|
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
||||||
|
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
||||||
|
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
||||||
|
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
||||||
|
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
||||||
|
cd $GITHUB_WORKSPACE/KernelSU
|
||||||
|
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||||
|
echo "VERSION: $VERSION"
|
||||||
|
cd -
|
||||||
|
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a12.sh
|
||||||
|
|
||||||
|
- name: Display structure of boot files
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- name: Upload images artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: boot-images-android12
|
||||||
|
path: Image-android12*/*.img.gz
|
||||||
|
|
||||||
|
check-build-kernel:
|
||||||
|
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
with:
|
||||||
|
version: android12-5.10
|
||||||
|
version_name: android12-5.10.177
|
||||||
|
tag: android12-5.10-2023-06
|
||||||
|
os_patch_level: 2023-06
|
||||||
|
patch_path: "5.10"
|
||||||
171
.github/workflows/build-kernel-a13.yml
vendored
Normal file
171
.github/workflows/build-kernel-a13.yml
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
name: Build Kernel - Android 13
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main", "ci", "checkci"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-a13.yml"
|
||||||
|
- ".github/workflows/gki-kernel.yml"
|
||||||
|
- ".github/scripts/build_a13.sh"
|
||||||
|
- "kernel/**"
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-a13.yml"
|
||||||
|
- ".github/workflows/gki-kernel.yml"
|
||||||
|
- ".github/scripts/build-a13.sh"
|
||||||
|
- "kernel/**"
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
build-kernel:
|
||||||
|
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 107
|
||||||
|
os_patch_level: 2022-11
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 149
|
||||||
|
os_patch_level: 2023-01
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 157
|
||||||
|
os_patch_level: 2023-03
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 168
|
||||||
|
os_patch_level: 2023-05
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 177
|
||||||
|
os_patch_level: 2023-06
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 186
|
||||||
|
os_patch_level: 2023-08
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 186
|
||||||
|
os_patch_level: 2023-09
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 189
|
||||||
|
os_patch_level: 2023-11
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 198
|
||||||
|
os_patch_level: 2023-12
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 41
|
||||||
|
os_patch_level: 2022-11
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 74
|
||||||
|
os_patch_level: 2023-01
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 78
|
||||||
|
os_patch_level: 2023-03
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 94
|
||||||
|
os_patch_level: 2023-05
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 104
|
||||||
|
os_patch_level: 2023-07
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 119
|
||||||
|
os_patch_level: 2023-09
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 123
|
||||||
|
os_patch_level: 2023-11
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 137
|
||||||
|
os_patch_level: 2023-12
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
version: android13-${{ matrix.version }}
|
||||||
|
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||||
|
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||||
|
os_patch_level: ${{ matrix.os_patch_level }}
|
||||||
|
patch_path: ${{ matrix.version }}
|
||||||
|
|
||||||
|
upload-artifacts:
|
||||||
|
needs: build-kernel
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: List artifacts
|
||||||
|
run: |
|
||||||
|
tree
|
||||||
|
|
||||||
|
- name: Download prebuilt toolchain
|
||||||
|
run: |
|
||||||
|
AOSP_MIRROR=https://android.googlesource.com
|
||||||
|
BRANCH=main-kernel-build-2023
|
||||||
|
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
||||||
|
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
||||||
|
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
||||||
|
pip3 install telethon==1.31.1
|
||||||
|
|
||||||
|
- name: Set boot sign key
|
||||||
|
env:
|
||||||
|
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
||||||
|
run: |
|
||||||
|
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
||||||
|
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
|
- name: Build boot images
|
||||||
|
run: |
|
||||||
|
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
||||||
|
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
||||||
|
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
||||||
|
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
||||||
|
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
||||||
|
cd $GITHUB_WORKSPACE/KernelSU
|
||||||
|
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||||
|
echo "VERSION: $VERSION"
|
||||||
|
cd -
|
||||||
|
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
|
||||||
|
|
||||||
|
- name: Display structure of boot files
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- name: Upload images artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: boot-images-android13
|
||||||
|
path: Image-android13*/*.img.gz
|
||||||
|
|
||||||
|
check-build-kernel:
|
||||||
|
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- version: "5.10"
|
||||||
|
sub_level: 189
|
||||||
|
os_patch_level: 2023-10
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 123
|
||||||
|
os_patch_level: 2023-10
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
with:
|
||||||
|
version: android13-${{ matrix.version }}
|
||||||
|
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||||
|
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||||
|
os_patch_level: ${{ matrix.os_patch_level }}
|
||||||
|
patch_path: ${{ matrix.version }}
|
||||||
132
.github/workflows/build-kernel-a14.yml
vendored
Normal file
132
.github/workflows/build-kernel-a14.yml
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
name: Build Kernel - Android 14
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main", "ci", "checkci"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-a14.yml"
|
||||||
|
- ".github/workflows/gki-kernel.yml"
|
||||||
|
- ".github/scripts/build_a13.sh"
|
||||||
|
- "kernel/**"
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-a14.yml"
|
||||||
|
- ".github/workflows/gki-kernel.yml"
|
||||||
|
- ".github/scripts/build-a13.sh"
|
||||||
|
- "kernel/**"
|
||||||
|
workflow_call:
|
||||||
|
jobs:
|
||||||
|
build-kernel:
|
||||||
|
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 110
|
||||||
|
os_patch_level: 2023-09
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 131
|
||||||
|
os_patch_level: 2023-11
|
||||||
|
- version: "6.1"
|
||||||
|
sub_level: 25
|
||||||
|
os_patch_level: 2023-10
|
||||||
|
- version: "6.1"
|
||||||
|
sub_level: 43
|
||||||
|
os_patch_level: 2023-11
|
||||||
|
- version: "6.1"
|
||||||
|
sub_level: 57
|
||||||
|
os_patch_level: 2023-12
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
version: android14-${{ matrix.version }}
|
||||||
|
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||||
|
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||||
|
os_patch_level: ${{ matrix.os_patch_level }}
|
||||||
|
patch_path: ${{ matrix.version }}
|
||||||
|
|
||||||
|
upload-artifacts:
|
||||||
|
needs: build-kernel
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: List artifacts
|
||||||
|
run: |
|
||||||
|
tree
|
||||||
|
|
||||||
|
- name: Download prebuilt toolchain
|
||||||
|
run: |
|
||||||
|
AOSP_MIRROR=https://android.googlesource.com
|
||||||
|
BRANCH=main-kernel-build-2023
|
||||||
|
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
||||||
|
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
||||||
|
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
||||||
|
pip3 install telethon==1.31.1
|
||||||
|
|
||||||
|
- name: Set boot sign key
|
||||||
|
env:
|
||||||
|
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
||||||
|
run: |
|
||||||
|
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
||||||
|
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
|
- name: Build boot images
|
||||||
|
run: |
|
||||||
|
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
||||||
|
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
||||||
|
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
||||||
|
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
||||||
|
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
||||||
|
cd $GITHUB_WORKSPACE/KernelSU
|
||||||
|
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||||
|
echo "VERSION: $VERSION"
|
||||||
|
cd -
|
||||||
|
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
|
||||||
|
|
||||||
|
- name: Display structure of boot files
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- name: Upload images artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: boot-images-android14
|
||||||
|
path: Image-android14*/*.img.gz
|
||||||
|
|
||||||
|
check-build-kernel:
|
||||||
|
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- version: "5.15"
|
||||||
|
sub_level: 110
|
||||||
|
os_patch_level: 2023-09
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
|
with:
|
||||||
|
version: android14-${{ matrix.version }}
|
||||||
|
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
|
||||||
|
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||||
|
os_patch_level: ${{ matrix.os_patch_level }}
|
||||||
|
patch_path: ${{ matrix.version }}
|
||||||
148
.github/workflows/build-kernel-arcvm.yml
vendored
Normal file
148
.github/workflows/build-kernel-arcvm.yml
vendored
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
name: Build Kernel - ChromeOS ARCVM
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main", "ci", "checkci"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-arcvm.yml"
|
||||||
|
- "kernel/**"
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-arcvm.yml"
|
||||||
|
- "kernel/**"
|
||||||
|
workflow_call:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && !github.event.pull_request.draft)
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [x86_64]
|
||||||
|
version: ["5.10.178"]
|
||||||
|
include:
|
||||||
|
- arch: x86_64
|
||||||
|
git_tag: chromeos-5.10-arcvm
|
||||||
|
file_name: "bzImage"
|
||||||
|
|
||||||
|
name: Build ChromeOS ARCVM kernel
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
env:
|
||||||
|
LTO: thin
|
||||||
|
ROOT_DIR: /
|
||||||
|
KERNEL_DIR: ${{ github.workspace }}/kernel
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install Build Tools
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends bc \
|
||||||
|
bison build-essential ca-certificates flex git gnupg \
|
||||||
|
libelf-dev libssl-dev lsb-release software-properties-common wget \
|
||||||
|
libncurses-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu nuget gzip \
|
||||||
|
rsync python3 device-tree-compiler
|
||||||
|
|
||||||
|
sudo ln -s --force python3 /usr/bin/python
|
||||||
|
|
||||||
|
export LLVM_VERSION=12
|
||||||
|
wget https://apt.llvm.org/llvm.sh
|
||||||
|
chmod +x llvm.sh
|
||||||
|
sudo ./llvm.sh $LLVM_VERSION
|
||||||
|
rm ./llvm.sh
|
||||||
|
sudo ln -s --force /usr/bin/clang-$LLVM_VERSION /usr/bin/clang
|
||||||
|
sudo ln -s --force /usr/bin/ld.lld-$LLVM_VERSION /usr/bin/ld.lld
|
||||||
|
sudo ln -s --force /usr/bin/llvm-objdump-$LLVM_VERSION /usr/bin/llvm-objdump
|
||||||
|
sudo ln -s --force /usr/bin/llvm-ar-$LLVM_VERSION /usr/bin/llvm-ar
|
||||||
|
sudo ln -s --force /usr/bin/llvm-nm-$LLVM_VERSION /usr/bin/llvm-nm
|
||||||
|
sudo ln -s --force /usr/bin/llvm-strip-$LLVM_VERSION /usr/bin/llvm-strip
|
||||||
|
sudo ln -s --force /usr/bin/llvm-objcopy-$LLVM_VERSION /usr/bin/llvm-objcopy
|
||||||
|
sudo ln -s --force /usr/bin/llvm-readelf-$LLVM_VERSION /usr/bin/llvm-readelf
|
||||||
|
sudo ln -s --force /usr/bin/clang++-$LLVM_VERSION /usr/bin/clang++
|
||||||
|
|
||||||
|
- name: Checkout KernelSU
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup kernel source
|
||||||
|
run: git clone https://chromium.googlesource.com/chromiumos/third_party/kernel.git -b ${{ matrix.git_tag }} --depth=1
|
||||||
|
|
||||||
|
- name: Setup KernelSU
|
||||||
|
working-directory: kernel
|
||||||
|
run: |
|
||||||
|
echo "[+] KernelSU setup"
|
||||||
|
KERNEL_ROOT=$GITHUB_WORKSPACE/kernel
|
||||||
|
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
|
||||||
|
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
|
||||||
|
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
|
||||||
|
|
||||||
|
echo "[+] Add KernelSU driver to Makefile"
|
||||||
|
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
|
||||||
|
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
|
||||||
|
|
||||||
|
echo "[+] Apply KernelSU patches"
|
||||||
|
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch || echo "[-] No patch found"
|
||||||
|
|
||||||
|
echo "[+] Patch script/setlocalversion"
|
||||||
|
sed -i 's/-dirty//g' $KERNEL_ROOT/scripts/setlocalversion
|
||||||
|
|
||||||
|
echo "[+] KernelSU setup done."
|
||||||
|
cd $GITHUB_WORKSPACE/KernelSU
|
||||||
|
VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||||
|
echo "VERSION: $VERSION"
|
||||||
|
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Kernel
|
||||||
|
working-directory: kernel
|
||||||
|
run: |
|
||||||
|
set -a && . build.config.gki.x86_64; set +a
|
||||||
|
export DEFCONFIG=x86_64_arcvm_defconfig
|
||||||
|
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
|
||||||
|
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
|
||||||
|
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||||
|
fi
|
||||||
|
|
||||||
|
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} mrproper
|
||||||
|
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} ${DEFCONFIG} < /dev/null
|
||||||
|
scripts/config --file .config -e LTO_CLANG -d LTO_NONE -e LTO_CLANG_THIN -d LTO_CLANG_FULL -e THINLTO
|
||||||
|
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} -j$(nproc) bzImage modules prepare-objtool
|
||||||
|
|
||||||
|
echo "file_path=${PWD}/arch/x86/boot/bzImage" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Upload kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
|
||||||
|
path: "${{ env.file_path }}"
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
|
- name: Post to Telegram
|
||||||
|
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
run: |
|
||||||
|
TITLE=kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
|
||||||
|
echo "[+] title: $TITLE"
|
||||||
|
export TITLE
|
||||||
|
export VERSION="${{ env.kernelsu_version }}"
|
||||||
|
echo "[+] Compress images"
|
||||||
|
gzip -n -f -9 "${{ env.file_path }}"
|
||||||
|
echo "[+] Image to upload"
|
||||||
|
ls -l "${{ env.file_path }}.gz"
|
||||||
|
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
pip3 install telethon==1.31.1
|
||||||
|
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
|
||||||
|
fi
|
||||||
38
.github/workflows/build-kernel-wsa.yml
vendored
Normal file
38
.github/workflows/build-kernel-wsa.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: Build Kernel - WSA
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main", "ci", "checkci"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-wsa.yml"
|
||||||
|
- ".github/workflows/wsa-kernel.yml"
|
||||||
|
- "kernel/**"
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/build-kernel-wsa.yml"
|
||||||
|
- ".github/workflows/wsa-kernel.yml"
|
||||||
|
- "kernel/**"
|
||||||
|
workflow_call:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [x86_64, arm64]
|
||||||
|
version: ["5.15.94.2", "5.15.104.1", "5.15.104.2", "5.15.104.3", "5.15.104.4"]
|
||||||
|
uses: ./.github/workflows/wsa-kernel.yml
|
||||||
|
with:
|
||||||
|
arch: ${{ matrix.arch }}
|
||||||
|
version: ${{ matrix.version }}
|
||||||
|
|
||||||
|
check_build:
|
||||||
|
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
|
||||||
|
uses: ./.github/workflows/wsa-kernel.yml
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [x86_64, arm64]
|
||||||
|
with:
|
||||||
|
arch: ${{ matrix.arch }}
|
||||||
|
version: "5.15.104.4"
|
||||||
25
.github/workflows/build-ksud.yml
vendored
Normal file
25
.github/workflows/build-ksud.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: Build KSUD
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main", "ci" ]
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/build-ksud.yml'
|
||||||
|
- '.github/workflows/ksud.yml'
|
||||||
|
- 'userspace/ksud/**'
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/build-ksud.yml'
|
||||||
|
- '.github/workflows/ksud.yml'
|
||||||
|
- 'userspace/ksud/**'
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- target: aarch64-linux-android
|
||||||
|
- target: x86_64-linux-android
|
||||||
|
- target: x86_64-pc-windows-gnu # only for build
|
||||||
|
uses: ./.github/workflows/ksud.yml
|
||||||
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
139
.github/workflows/build-manager.yml
vendored
Normal file
139
.github/workflows/build-manager.yml
vendored
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
name: Build Manager
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/build-manager.yml'
|
||||||
|
- 'manager/**'
|
||||||
|
- 'userspace/ksud/**'
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- 'manager/**'
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-ksud:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- target: aarch64-linux-android
|
||||||
|
- target: x86_64-linux-android
|
||||||
|
uses: ./.github/workflows/ksud.yml
|
||||||
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
|
||||||
|
build-manager:
|
||||||
|
needs: build-ksud
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./manager
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup need_upload
|
||||||
|
id: need_upload
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Write key
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
|
||||||
|
{
|
||||||
|
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
|
||||||
|
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
|
||||||
|
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
|
||||||
|
echo KEYSTORE_FILE='../key.jks'
|
||||||
|
} >> gradle.properties
|
||||||
|
echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: "temurin"
|
||||||
|
java-version: "17"
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
gradle-home-cache-cleanup: true
|
||||||
|
|
||||||
|
- name: Download arm64 ksud
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ksud-aarch64-linux-android
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Download x86_64 ksud
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ksud-x86_64-linux-android
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Copy ksud to app jniLibs
|
||||||
|
run: |
|
||||||
|
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||||
|
mkdir -p app/src/main/jniLibs/x86_64
|
||||||
|
cp -f ../aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud.so
|
||||||
|
cp -f ../x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud.so
|
||||||
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: |
|
||||||
|
{
|
||||||
|
echo 'org.gradle.parallel=true'
|
||||||
|
echo 'org.gradle.vfs.watch=true'
|
||||||
|
echo 'org.gradle.jvmargs=-Xmx2048m'
|
||||||
|
echo 'android.native.buildOutput=verbose'
|
||||||
|
} >> gradle.properties
|
||||||
|
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
|
||||||
|
./gradlew clean assembleRelease
|
||||||
|
|
||||||
|
- name: Upload build artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: manager
|
||||||
|
path: manager/app/build/outputs/apk/release/*.apk
|
||||||
|
|
||||||
|
- name: Upload mappings
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: "mappings"
|
||||||
|
path: "manager/app/build/outputs/mapping/release/"
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
|
- name: Upload to telegram
|
||||||
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
TITLE: Manager
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
export VERSION=$(git rev-list --count HEAD)
|
||||||
|
APK=$(find ./app/build/outputs/apk/release -name "*.apk")
|
||||||
|
pip3 install telethon==1.31.1
|
||||||
|
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
|
||||||
|
fi
|
||||||
64
.github/workflows/build-su.yml
vendored
Normal file
64
.github/workflows/build-su.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
name: Build SU
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main", "ci" ]
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/build-su.yml'
|
||||||
|
- 'userspace/su/**'
|
||||||
|
- 'scripts/ksubot.py'
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- 'userspace/su/**'
|
||||||
|
jobs:
|
||||||
|
build-su:
|
||||||
|
name: Build userspace su
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup need_upload
|
||||||
|
id: need_upload
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
- uses: nttld/setup-ndk@v1
|
||||||
|
with:
|
||||||
|
ndk-version: r25c
|
||||||
|
- name: Build su
|
||||||
|
working-directory: ./userspace/su
|
||||||
|
run: ndk-build
|
||||||
|
- name: Upload a Build Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: su
|
||||||
|
path: ./userspace/su/libs
|
||||||
|
- name: Bot session cache
|
||||||
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
- name: Upload to telegram
|
||||||
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
TITLE: SU
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
export VERSION=$(git rev-list --count HEAD)
|
||||||
|
pip3 install telethon==1.31.1
|
||||||
|
mv ./userspace/su/libs/arm64-v8a/su su-arm64
|
||||||
|
mv ./userspace/su/libs/x86_64/su su-x86_64
|
||||||
|
python3 scripts/ksubot.py su-arm64 su-x86_64
|
||||||
|
fi
|
||||||
37
.github/workflows/clippy.yml
vendored
Normal file
37
.github/workflows/clippy.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: Clippy check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/clippy.yml'
|
||||||
|
- 'userspace/ksud/**'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/clippy.yml'
|
||||||
|
- 'userspace/ksud/**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: '-Dwarnings'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clippy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
|
||||||
|
- run: rustup default 1.67.0
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: userspace/ksud
|
||||||
|
|
||||||
|
- name: Install cross
|
||||||
|
run: cargo install cross --locked
|
||||||
|
|
||||||
|
- name: Run clippy
|
||||||
|
run: |
|
||||||
|
cross clippy --manifest-path userspace/ksud/Cargo.toml --target aarch64-linux-android --release
|
||||||
|
cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release
|
||||||
67
.github/workflows/deploy-website.yml
vendored
Normal file
67
.github/workflows/deploy-website.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
name: Deploy Website
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- website
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/deploy-website.yml'
|
||||||
|
- 'website/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||||
|
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||||
|
concurrency:
|
||||||
|
group: pages
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Build job
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./website
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Not needed if lastUpdated is not enabled
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
cache: yarn # or pnpm / yarn
|
||||||
|
cache-dependency-path: website/yarn.lock
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
- name: Build with VitePress
|
||||||
|
run: |
|
||||||
|
yarn docs:build
|
||||||
|
touch docs/.vitepress/dist/.nojekyll
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: website/docs/.vitepress/dist
|
||||||
|
|
||||||
|
# Deployment job
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
203
.github/workflows/gki-kernel.yml
vendored
Normal file
203
.github/workflows/gki-kernel.yml
vendored
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
name: GKI Kernel Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Output directory of gki,
|
||||||
|
for example: android12-5.10
|
||||||
|
version_name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
With SUBLEVEL of kernel,
|
||||||
|
for example: android12-5.10.66
|
||||||
|
tag:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Part of branch name of common kernel manifest,
|
||||||
|
for example: android12-5.10-2021-11
|
||||||
|
os_patch_level:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Patch level of common kernel manifest,
|
||||||
|
for example: 2021-11
|
||||||
|
default: 2022-05
|
||||||
|
patch_path:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Directory name of .github/patches/<patch_path>
|
||||||
|
for example: 5.10
|
||||||
|
use_cache:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
embed_ksud:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ksud-aarch64-linux-android
|
||||||
|
description: >
|
||||||
|
Artifact name of prebuilt ksud to be embedded
|
||||||
|
for example: ksud-aarch64-linux-android
|
||||||
|
debug:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
secrets:
|
||||||
|
BOOT_SIGN_KEY:
|
||||||
|
required: false
|
||||||
|
CHAT_ID:
|
||||||
|
required: false
|
||||||
|
BOT_TOKEN:
|
||||||
|
required: false
|
||||||
|
MESSAGE_THREAD_ID:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build ${{ inputs.version_name }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||||
|
CCACHE_NOHASHDIR: "true"
|
||||||
|
CCACHE_HARDLINK: "true"
|
||||||
|
steps:
|
||||||
|
- name: Maximize build space
|
||||||
|
uses: easimon/maximize-build-space@master
|
||||||
|
with:
|
||||||
|
root-reserve-mb: 8192
|
||||||
|
temp-reserve-mb: 2048
|
||||||
|
remove-dotnet: 'true'
|
||||||
|
remove-android: 'true'
|
||||||
|
remove-haskell: 'true'
|
||||||
|
remove-codeql: 'true'
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup need_upload
|
||||||
|
id: need_upload
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup kernel source
|
||||||
|
run: |
|
||||||
|
echo "Free space:"
|
||||||
|
df -h
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
sudo apt-get install repo -y
|
||||||
|
mkdir android-kernel && cd android-kernel
|
||||||
|
repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.16
|
||||||
|
REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${{ inputs.tag }})
|
||||||
|
DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
|
||||||
|
if grep -q deprecated <<< $REMOTE_BRANCH; then
|
||||||
|
echo "Found deprecated branch: ${{ inputs.tag }}"
|
||||||
|
sed -i 's/"${{ inputs.tag }}"/"deprecated\/${{ inputs.tag }}"/g' $DEFAULT_MANIFEST_PATH
|
||||||
|
cat $DEFAULT_MANIFEST_PATH
|
||||||
|
fi
|
||||||
|
repo --version
|
||||||
|
repo --trace sync -c -j$(nproc --all) --no-tags
|
||||||
|
df -h
|
||||||
|
|
||||||
|
- name: Setup KernelSU
|
||||||
|
env:
|
||||||
|
PATCH_PATH: ${{ inputs.patch_path }}
|
||||||
|
IS_DEBUG_KERNEL: ${{ inputs.debug }}
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/android-kernel
|
||||||
|
echo "[+] KernelSU setup"
|
||||||
|
GKI_ROOT=$(pwd)
|
||||||
|
echo "[+] GKI_ROOT: $GKI_ROOT"
|
||||||
|
echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers"
|
||||||
|
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
|
||||||
|
echo "[+] Add KernelSU driver to Makefile"
|
||||||
|
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
|
||||||
|
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
|
||||||
|
echo "[+] Apply KernelSU patches"
|
||||||
|
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found"
|
||||||
|
|
||||||
|
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
|
||||||
|
echo "[+] Enable debug features for kernel"
|
||||||
|
echo "ccflags-y += -DCONFIG_KSU_DEBUG" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
|
||||||
|
fi
|
||||||
|
repo status
|
||||||
|
echo "[+] KernelSU setup done."
|
||||||
|
|
||||||
|
- name: Symbol magic
|
||||||
|
run: |
|
||||||
|
echo "[+] Export all symbol from abi_gki_aarch64.xml"
|
||||||
|
COMMON_ROOT=$GITHUB_WORKSPACE/android-kernel/common
|
||||||
|
KSU_ROOT=$GITHUB_WORKSPACE/KernelSU
|
||||||
|
ABI_XML=$COMMON_ROOT/android/abi_gki_aarch64.xml
|
||||||
|
SYMBOL_LIST=$COMMON_ROOT/android/abi_gki_aarch64
|
||||||
|
# python3 $KSU_ROOT/scripts/abi_gki_all.py $ABI_XML > $SYMBOL_LIST
|
||||||
|
echo "[+] Add KernelSU symbols"
|
||||||
|
cat $KSU_ROOT/kernel/export_symbol.txt | awk '{sub("[ \t]+","");print " "$0}' >> $SYMBOL_LIST
|
||||||
|
|
||||||
|
- name: Setup ccache
|
||||||
|
if: inputs.use_cache == true
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2
|
||||||
|
with:
|
||||||
|
key: gki-kernel-aarch64-${{ inputs.version_name }}
|
||||||
|
max-size: 2G
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
|
- name: Make working directory clean to avoid dirty
|
||||||
|
working-directory: android-kernel
|
||||||
|
run: |
|
||||||
|
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
|
||||||
|
git config --global user.email "bot@kernelsu.org"
|
||||||
|
git config --global user.name "KernelSUBot"
|
||||||
|
cd common/ && git add -A && git commit -a -m "Add KernelSU"
|
||||||
|
repo status
|
||||||
|
|
||||||
|
- name: Build boot.img
|
||||||
|
working-directory: android-kernel
|
||||||
|
run: |
|
||||||
|
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
|
||||||
|
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
|
||||||
|
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||||
|
fi
|
||||||
|
if [ -e build/build.sh ]; then
|
||||||
|
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
|
||||||
|
else
|
||||||
|
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Prepare artifacts
|
||||||
|
id: prepareArtifacts
|
||||||
|
run: |
|
||||||
|
OUTDIR=android-kernel/out/${{ inputs.version }}/dist
|
||||||
|
if [ ! -e $OUTDIR ]; then
|
||||||
|
OUTDIR=android-kernel/dist
|
||||||
|
fi
|
||||||
|
mkdir output
|
||||||
|
cp $OUTDIR/Image ./output/
|
||||||
|
cp $OUTDIR/Image.lz4 ./output/
|
||||||
|
git clone https://github.com/Kernel-SU/AnyKernel3
|
||||||
|
rm -rf ./AnyKernel3/.git
|
||||||
|
cp $OUTDIR/Image ./AnyKernel3/
|
||||||
|
|
||||||
|
- name: Upload Image and Image.gz
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Image-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
|
||||||
|
path: ./output/*
|
||||||
|
|
||||||
|
- name: Upload AnyKernel3
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
|
||||||
|
path: ./AnyKernel3/*
|
||||||
36
.github/workflows/ksud.yml
vendored
Normal file
36
.github/workflows/ksud.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: Build ksud
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
target:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
use_cache:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
|
||||||
|
- run: rustup default 1.67.0
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: userspace/ksud
|
||||||
|
cache-targets: false
|
||||||
|
|
||||||
|
- name: Install cross
|
||||||
|
run: cargo install cross --locked
|
||||||
|
|
||||||
|
- name: Build ksud
|
||||||
|
run: cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml
|
||||||
|
|
||||||
|
- name: Upload ksud artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ksud-${{ inputs.target }}
|
||||||
|
path: userspace/ksud/target/**/release/ksud
|
||||||
77
.github/workflows/release.yml
vendored
Normal file
77
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
name: Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-manager:
|
||||||
|
uses: ./.github/workflows/build-manager.yml
|
||||||
|
secrets: inherit
|
||||||
|
build-a12-kernel:
|
||||||
|
uses: ./.github/workflows/build-kernel-a12.yml
|
||||||
|
secrets: inherit
|
||||||
|
build-a13-kernel:
|
||||||
|
uses: ./.github/workflows/build-kernel-a13.yml
|
||||||
|
secrets: inherit
|
||||||
|
build-a14-kernel:
|
||||||
|
uses: ./.github/workflows/build-kernel-a14.yml
|
||||||
|
secrets: inherit
|
||||||
|
build-wsa-kernel:
|
||||||
|
uses: ./.github/workflows/build-kernel-wsa.yml
|
||||||
|
secrets: inherit
|
||||||
|
build-arcvm-kernel:
|
||||||
|
uses: ./.github/workflows/build-kernel-arcvm.yml
|
||||||
|
secrets: inherit
|
||||||
|
release:
|
||||||
|
needs:
|
||||||
|
- build-manager
|
||||||
|
- build-a12-kernel
|
||||||
|
- build-a13-kernel
|
||||||
|
- build-a14-kernel
|
||||||
|
- build-wsa-kernel
|
||||||
|
- build-arcvm-kernel
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
- name: Zip AnyKernel3
|
||||||
|
run: |
|
||||||
|
for dir in AnyKernel3-*; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
echo "----- Zip $dir -----"
|
||||||
|
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Zip WSA kernel
|
||||||
|
run: |
|
||||||
|
for dir in kernel-WSA-*; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
echo "------ Zip $dir ----------"
|
||||||
|
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Zip ChromeOS ARCVM kernel
|
||||||
|
run: |
|
||||||
|
for dir in kernel-ARCVM-*; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
echo "------ Zip $dir ----------"
|
||||||
|
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Display structure of downloaded files
|
||||||
|
run: ls -R
|
||||||
|
|
||||||
|
- name: release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
manager/*.apk
|
||||||
|
AnyKernel3-*.zip
|
||||||
|
boot-images-*/Image-*/*.img.gz
|
||||||
|
kernel-WSA*.zip
|
||||||
|
kernel-ARCVM*.zip
|
||||||
33
.github/workflows/rustfmt.yml
vendored
Normal file
33
.github/workflows/rustfmt.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: Rustfmt check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/rustfmt.yml'
|
||||||
|
- 'userspace/ksud/**'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/rustfmt.yml'
|
||||||
|
- 'userspace/ksud/**'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
with:
|
||||||
|
components: rustfmt
|
||||||
|
|
||||||
|
- uses: LoliGothick/rustfmt-check@master
|
||||||
|
with:
|
||||||
|
token: ${{ github.token }}
|
||||||
|
working-directory: userspace/ksud
|
||||||
27
.github/workflows/shellcheck.yml
vendored
Normal file
27
.github/workflows/shellcheck.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: ShellCheck
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/shellcheck.yml'
|
||||||
|
- '**/*.sh'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/shellcheck.yml'
|
||||||
|
- '**/*.sh'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
shellcheck:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run ShellCheck
|
||||||
|
uses: ludeeus/action-shellcheck@2.0.0
|
||||||
|
with:
|
||||||
|
ignore_names: gradlew
|
||||||
|
ignore_paths: ./userspace/ksud/src/installer.sh
|
||||||
135
.github/workflows/wsa-kernel.yml
vendored
Normal file
135
.github/workflows/wsa-kernel.yml
vendored
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
name: Build Kernel - WSA
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
arch:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Build arch: x86_64 / arm64
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Build version
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }}
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
env:
|
||||||
|
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||||
|
CCACHE_NOHASHDIR: "true"
|
||||||
|
CCACHE_HARDLINK: "true"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install Build Tools
|
||||||
|
uses: awalsh128/cache-apt-pkgs-action@v1
|
||||||
|
with:
|
||||||
|
packages: bc bison build-essential flex libelf-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu gzip ccache
|
||||||
|
version: 1.0
|
||||||
|
|
||||||
|
- name: Cache LLVM
|
||||||
|
id: cache-llvm
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ./llvm
|
||||||
|
key: llvm-12.0.1
|
||||||
|
|
||||||
|
- name: Setup LLVM
|
||||||
|
uses: KyleMayes/install-llvm-action@v1
|
||||||
|
with:
|
||||||
|
version: "12.0.1"
|
||||||
|
force-version: true
|
||||||
|
ubuntu-version: "16.04"
|
||||||
|
cached: ${{ steps.cache-llvm.outputs.cache-hit }}
|
||||||
|
|
||||||
|
- name: Checkout KernelSU
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup kernel source
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: microsoft/WSA-Linux-Kernel
|
||||||
|
ref: android-lts/latte-2/${{ inputs.version }}
|
||||||
|
path: WSA-Linux-Kernel
|
||||||
|
|
||||||
|
- name: Setup Ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2
|
||||||
|
with:
|
||||||
|
key: WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }}
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||||
|
max-size: 2G
|
||||||
|
|
||||||
|
- name: Setup KernelSU
|
||||||
|
working-directory: WSA-Linux-Kernel
|
||||||
|
run: |
|
||||||
|
echo "[+] KernelSU setup"
|
||||||
|
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
|
||||||
|
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
|
||||||
|
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
|
||||||
|
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
|
||||||
|
echo "[+] Add KernelSU driver to Makefile"
|
||||||
|
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
|
||||||
|
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
|
||||||
|
echo "[+] Apply KernelSU patches"
|
||||||
|
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch || echo "[-] No patch found"
|
||||||
|
echo "[+] KernelSU setup done."
|
||||||
|
cd $GITHUB_WORKSPACE/KernelSU
|
||||||
|
VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||||
|
echo "VERSION: $VERSION"
|
||||||
|
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Kernel
|
||||||
|
working-directory: WSA-Linux-Kernel
|
||||||
|
run: |
|
||||||
|
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
|
||||||
|
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
|
||||||
|
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||||
|
fi
|
||||||
|
declare -A ARCH_MAP=(["x86_64"]="x64" ["arm64"]="arm64")
|
||||||
|
cp configs/wsa/config-wsa-${ARCH_MAP[${{ inputs.arch }}]} .config
|
||||||
|
make olddefconfig
|
||||||
|
declare -A FILE_NAME=(["x86_64"]="bzImage" ["arm64"]="Image")
|
||||||
|
make -j`nproc` LLVM=1 ARCH=${{ inputs.arch }} $(if [ "${{ inputs.arch }}" == "arm64" ]; then echo CROSS_COMPILE=aarch64-linux-gnu; fi) ${FILE_NAME[${{ inputs.arch }}]} CCACHE="/usr/bin/ccache"
|
||||||
|
declare -A ARCH_MAP_FILE=(["x86_64"]="x86" ["arm64"]="arm64")
|
||||||
|
echo "file_path=WSA-Linux-Kernel/arch/${ARCH_MAP_FILE[${{ inputs.arch }}]}/boot/${FILE_NAME[${{ inputs.arch }}]}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Upload kernel-${{ inputs.arch }}-${{ inputs.version }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: kernel-WSA-${{ inputs.arch }}-${{ inputs.version }}
|
||||||
|
path: "${{ env.file_path }}"
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
|
- name: Post to Telegram
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ secrets.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
run: |
|
||||||
|
TITLE=kernel-${{ inputs.arch }}-WSA-${{ inputs.version }}
|
||||||
|
echo "[+] title: $TITLE"
|
||||||
|
export TITLE
|
||||||
|
export VERSION="${{ env.kernelsu_version }}"
|
||||||
|
echo "[+] Compress images"
|
||||||
|
gzip -n -f -9 "${{ env.file_path }}"
|
||||||
|
echo "[+] Image to upload"
|
||||||
|
ls -l "${{ env.file_path }}.gz"
|
||||||
|
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
pip3 install telethon==1.31.1
|
||||||
|
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
|
||||||
|
fi
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.idea
|
||||||
|
.vscode
|
||||||
31
README.md
31
README.md
@@ -1,31 +0,0 @@
|
|||||||
# KernelSU
|
|
||||||
|
|
||||||
A Kernel based root solution for Android GKI.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
1. Flash a custom kernel with KernelSU, you can build it yourself or use prebuilt boot.img.
|
|
||||||
2. Install Manager App and enjoy :)
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
### Build GKI Kernel
|
|
||||||
|
|
||||||
1. Download the GKI source first, you can refer the [GKI build instruction](https://source.android.com/docs/core/architecture/kernel/generic-kernel-image)
|
|
||||||
2. cd `<GKI kernel source dir>`
|
|
||||||
3. `curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -`
|
|
||||||
4. Build the kernel.
|
|
||||||
|
|
||||||
### Build the Manager App
|
|
||||||
|
|
||||||
Just open Android Studio and import the project.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[GPL-3](http://www.gnu.org/copyleft/gpl.html)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)
|
|
||||||
- [genuine](https://github.com/brevent/genuine/)
|
|
||||||
- [Diamorphine](https://github.com/m0nad/Diamorphine)
|
|
||||||
7
SECURITY.md
Normal file
7
SECURITY.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Reporting Security Issues
|
||||||
|
|
||||||
|
The KernelSU team and community take security bugs in KernelSU seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
|
||||||
|
|
||||||
|
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/tiann/KernelSU/security/advisories/new) tab, or you can mailto [weishu](mailto:twsxtd@gmail.com) directly.
|
||||||
|
|
||||||
|
The KernelSU team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
|
||||||
57
docs/README.md
Normal file
57
docs/README.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
A Kernel-based root solution for Android devices.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
1. Kernel-based `su` and root access management.
|
||||||
|
2. Module system based on [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Lock up the root power in a cage.
|
||||||
|
|
||||||
|
## Compatibility State
|
||||||
|
|
||||||
|
KernelSU officially supports Android GKI 2.0 devices (kernel 5.10+). Older kernels (4.14+) are also compatible, but the kernel will have to be built manually.
|
||||||
|
|
||||||
|
With this, WSA, ChromeOS, and container-based Android are all supported.
|
||||||
|
|
||||||
|
Currently, only `arm64-v8a` and `x86_64` are supported.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- [Installation Instruction](https://kernelsu.org/guide/installation.html)
|
||||||
|
- [How to build?](https://kernelsu.org/guide/how-to-build.html)
|
||||||
|
- [Official Website](https://kernelsu.org/)
|
||||||
|
|
||||||
|
## Translation
|
||||||
|
|
||||||
|
To help translate KernelSU or improve existing translations, please use [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR of Manager's translation is no longer accepted, because it will conflict with Weblate.
|
||||||
|
|
||||||
|
## Discussion
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
For information on reporting security vulnerabilities in KernelSU, see [SECURITY.md](/SECURITY.md).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
- Files under the `kernel` directory are [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- All other parts except the `kernel` directory are [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): the KernelSU idea.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): the powerful root tool.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): apk v2 signature validation.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): some rootkit skills.
|
||||||
57
docs/README_CN.md
Normal file
57
docs/README_CN.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
一个 Android 上基于内核的 root 方案。
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
- 基于内核的 `su` 和权限管理。
|
||||||
|
- 基于 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模块系统。
|
||||||
|
- [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html): 把 Root 权限关进笼子里。
|
||||||
|
|
||||||
|
## 兼容状态
|
||||||
|
|
||||||
|
KernelSU 官方支持 GKI 2.0 的设备(内核版本5.10以上);旧内核也是兼容的(最低4.14+),不过需要自己编译内核。
|
||||||
|
|
||||||
|
WSA, ChromeOS 和运行在容器上的 Android 也可以与 KernelSU 一起工作。
|
||||||
|
|
||||||
|
目前支持架构 : `arm64-v8a` 和 `x86_64`。
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
- [安装教程](https://kernelsu.org/zh_CN/guide/installation.html)
|
||||||
|
- [如何构建?](https://kernelsu.org/zh_CN/guide/how-to-build.html)
|
||||||
|
- [官方网站](https://kernelsu.org/zh_CN/)
|
||||||
|
|
||||||
|
## 参与翻译
|
||||||
|
|
||||||
|
要将 KernelSU 翻译成您的语言,或完善现有的翻译,请使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。现已不再接受有关管理器翻译的PR,因为这会与Weblate冲突。
|
||||||
|
|
||||||
|
## 讨论
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## 安全性
|
||||||
|
|
||||||
|
有关报告 KernelSU 安全漏洞的信息,请参阅 [SECURITY.md](/SECURITY.md)。
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
- 目录 `kernel` 下所有文件为 [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。
|
||||||
|
- 除 `kernel` 目录的其他部分均为 [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。
|
||||||
|
|
||||||
|
## 鸣谢
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU 的灵感。
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk):强大的 root 工具箱。
|
||||||
|
- [genuine](https://github.com/brevent/genuine/):apk v2 签名验证。
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
|
||||||
56
docs/README_ES.md
Normal file
56
docs/README_ES.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Una solución root basada en el kernel para dispositivos Android.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Características
|
||||||
|
|
||||||
|
1. Binario `su` basado en el kernel y gestión de acceso root.
|
||||||
|
2. Sistema de módulos basado en [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
|
||||||
|
## Estado de compatibilidad
|
||||||
|
|
||||||
|
**KernelSU** soporta de forma oficial dispositivos Android con **GKI 2.0** (a partir de la versión **5.10** del kernel). Los kernels antiguos (a partir de la versión **4.14**) también son compatibles, pero necesitas compilarlos por tu cuenta.
|
||||||
|
|
||||||
|
Con esto, WSA, ChromeOS y Android basado en contenedores están todos compatibles.
|
||||||
|
|
||||||
|
Actualmente, solo se admiten las arquitecturas `arm64-v8a` y `x86_64`.
|
||||||
|
|
||||||
|
## Uso
|
||||||
|
|
||||||
|
- [¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
|
||||||
|
- [¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
|
||||||
|
- [Site oficial](https://kernelsu.org/)
|
||||||
|
|
||||||
|
## Traducción
|
||||||
|
|
||||||
|
Para ayudar a traducir KernelSU o mejorar las traducciones existentes, utilice [Weblate](https://hosted.weblate.org/engage/kernelsu/). Ya no se aceptan PR de la traducción de Manager porque entrará en conflicto con Weblate.
|
||||||
|
|
||||||
|
## Discusión
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Seguridad
|
||||||
|
|
||||||
|
Para obtener información sobre cómo informar vulnerabilidades de seguridad en KernelSU, consulte [SECURITY.md](/SECURITY.md).
|
||||||
|
|
||||||
|
## Licencia
|
||||||
|
|
||||||
|
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## Créditos
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de KernelSU.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): la poderosa herramienta root.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): validación de firma apk v2.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): algunas habilidades de rootkit.
|
||||||
53
docs/README_ID.md
Normal file
53
docs/README_ID.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Solusi root berbasis Kernel untuk perangkat Android.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Fitur
|
||||||
|
|
||||||
|
1. Manajemen akses root dan `su` berbasis kernel.
|
||||||
|
2. Sistem modul berdasarkan [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
3. [Profil Aplikasi](https://kernelsu.org/guide/app-profile.html): Kunci daya root di dalam sangkar.
|
||||||
|
|
||||||
|
## Status Kompatibilitas
|
||||||
|
|
||||||
|
KernelSU secara resmi mendukung perangkat Android GKI 2.0 (dengan kernel 5.10+), kernel lama (4.14+) juga kompatibel, tetapi Anda perlu membuat kernel sendiri.
|
||||||
|
|
||||||
|
WSA, ChromeOS, dan Android berbasis wadah juga dapat bekerja dengan KernelSU terintegrasi.
|
||||||
|
|
||||||
|
Dan ABI yang didukung saat ini adalah: `arm64-v8a` dan `x86_64`
|
||||||
|
|
||||||
|
## Penggunaan
|
||||||
|
|
||||||
|
- [Petunjuk Instalasi](https://kernelsu.org/id_ID/guide/installation.html)
|
||||||
|
- [Bagaimana cara membuat?](https://kernelsu.org/id_ID/guide/how-to-build.html)
|
||||||
|
- [Situs Web Resmi](https://kernelsu.org/id_ID/)
|
||||||
|
|
||||||
|
## Terjemahan
|
||||||
|
|
||||||
|
Untuk menerjemahkan KernelSU ke dalam bahasa Anda atau menyempurnakan terjemahan yang sudah ada, harap gunakan [Weblat](https://hosted.weblate.org/engage/kernelsu/).
|
||||||
|
|
||||||
|
## Diskusi
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Lisensi
|
||||||
|
|
||||||
|
- File di bawah direktori `kernel` adalah [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## Kredit
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ide KernelSU.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): alat root yang ampuh.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): validasi tanda tangan apk v2.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): beberapa keterampilan rootkit.
|
||||||
53
docs/README_IN.md
Normal file
53
docs/README_IN.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | **हिंदी**
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Android उपकरणों के लिए कर्नेल-आधारित रूट समाधान।
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## विशेषताएँ
|
||||||
|
|
||||||
|
1. कर्नेल-आधारित `su` और रूट एक्सेस प्रबंधन।
|
||||||
|
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) पर आधारित मॉड्यूल प्रणाली।
|
||||||
|
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Root शक्ति को पिंजरे में बंद कर दो।
|
||||||
|
|
||||||
|
## अनुकूलता अवस्था
|
||||||
|
|
||||||
|
KernelSU आधिकारिक तौर पर Android GKI 2.0 डिवाइस (कर्नेल 5.10+) का समर्थन करता है। पुराने कर्नेल (4.14+) भी संगत हैं, लेकिन कर्नेल को मैन्युअल रूप से बनाना होगा।
|
||||||
|
|
||||||
|
इसके साथ, WSA, ChromeOS और कंटेनर-आधारित Android सभी समर्थित हैं।
|
||||||
|
|
||||||
|
वर्तमान में, केवल `arm64-v8a` और `x86_64` समर्थित हैं।
|
||||||
|
|
||||||
|
## प्रयोग
|
||||||
|
|
||||||
|
- [स्थापना निर्देश](https://kernelsu.org/guide/installation.html)
|
||||||
|
- [कैसे बनाना है ?](https://kernelsu.org/guide/how-to-build.html)
|
||||||
|
- [आधिकारिक वेबसाइट](https://kernelsu.org/)
|
||||||
|
|
||||||
|
## अनुवाद करना
|
||||||
|
|
||||||
|
KernelSU का अनुवाद करने या मौजूदा अनुवादों को बेहतर बनाने में सहायता के लिए, कृपया इसका उपयोग करें [Weblate](https://hosted.weblate.org/engage/kernelsu/).
|
||||||
|
|
||||||
|
## बहस
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## लाइसेंस
|
||||||
|
|
||||||
|
- `Kernel` निर्देशिका के अंतर्गत फ़ाइलें हैं [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
- `Kernel` निर्देशिका को छोड़कर अन्य सभी भाग हैं [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||||
|
|
||||||
|
## आभार सूची
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU विचार।
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): शक्तिशाली root उपकरण।
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): apk v2 हस्ताक्षर सत्यापन।
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): कुछ रूटकिट कौशल।
|
||||||
53
docs/README_IW.md
Normal file
53
docs/README_IW.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
פתרון לניהול root מבוסס על Kernel עבור מכשירי Android.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## תכונות
|
||||||
|
|
||||||
|
1. ניהול root ו־`su` מבוססים על Kernel.
|
||||||
|
2. מערכת מודולים מבוססת [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
3. [פרופיל אפליקציה](https://kernelsu.org/guide/app-profile.html): נעילת גישת root בכלוב.
|
||||||
|
|
||||||
|
## מצב תאימות
|
||||||
|
|
||||||
|
KernelSU תומך במכשירי Android GKI 2.0 (kernel 5.10+) באופן רשמי. לליבות ישנות (4.14+) יש גם תאימות, אך יידרש לבנות את הליבה באופן ידני.
|
||||||
|
|
||||||
|
באמצעות זה, תמיכה זמינה גם ל-WSA, ChromeOS ומכשירי Android המבוססים על מיכלים.
|
||||||
|
|
||||||
|
כרגע, רק `arm64-v8a` ו־`x86_64` נתמכים.
|
||||||
|
|
||||||
|
## שימוש
|
||||||
|
|
||||||
|
- [הוראות התקנה](https://kernelsu.org/guide/installation.html)
|
||||||
|
- [איך לבנות?](https://kernelsu.org/guide/how-to-build.html)
|
||||||
|
- [האתר רשמי](https://kernelsu.org/)
|
||||||
|
|
||||||
|
## תרגום
|
||||||
|
|
||||||
|
כדי לעזור בתרגום של KernelSU או לשפר תרגומים קיימים, יש להשתמש ב-[Weblate](https://hosted.weblate.org/engage/kernelsu/).
|
||||||
|
|
||||||
|
## דיון
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## רשיון
|
||||||
|
|
||||||
|
- קבצים תחת הספרייה `kernel` מוגנים על פי [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- כל החלקים האחרים, למעט הספרייה `kernel`, מוגנים על פי [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## קרדיטים
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): הרעיון של KernelSU.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): הכלי הסופר חזק לניהול root.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): אימות חתימת apk v2.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): כמה יכולות רוט.
|
||||||
53
docs/README_JP.md
Normal file
53
docs/README_JP.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Android におけるカーネルベースの root ソリューションです。
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## 特徴
|
||||||
|
|
||||||
|
1. カーネルベースの `su` と権限管理。
|
||||||
|
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) に基づくモジュールシステム。
|
||||||
|
3. [アプリのプロファイル](https://kernelsu.org/guide/app-profile.html): root の権限をケージ内に閉じ込めます。
|
||||||
|
|
||||||
|
## 対応状況
|
||||||
|
|
||||||
|
KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上)を公式にサポートしています。古いカーネル(4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。
|
||||||
|
|
||||||
|
WSA 、ChromeOS とコンテナ上で動作する Android でも KernelSU を統合して動かせます。
|
||||||
|
|
||||||
|
現在サポートしているアーキテクチャは `arm64-v8a` および `x86_64` です。
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
- [インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html)
|
||||||
|
- [ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html)
|
||||||
|
- [公式サイト](https://kernelsu.org/ja_JP/)
|
||||||
|
|
||||||
|
## 翻訳
|
||||||
|
|
||||||
|
KernelSU をあなたの言語に翻訳するか、既存の翻訳を改善するには、[Weblate](https://hosted.weblate.org/engage/kernelsu/) を使用してください。Manager翻訳した PR は、Weblate と競合するため受け入れられなくなりました。
|
||||||
|
|
||||||
|
## ディスカッション
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## ライセンス
|
||||||
|
|
||||||
|
- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。
|
||||||
|
- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。
|
||||||
|
|
||||||
|
## クレジット
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU のアイデア元。
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk):強力な root ツール。
|
||||||
|
- [genuine](https://github.com/brevent/genuine/):apk v2 の署名検証。
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル。
|
||||||
55
docs/README_PL.md
Normal file
55
docs/README_PL.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Polski** | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Rozwiązanie root oparte na jądrze dla urządzeń z systemem Android.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Cechy
|
||||||
|
|
||||||
|
1. Oparte na jądrze `su` i zarządzanie dostępem roota.
|
||||||
|
2. System modułów oparty na [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
|
||||||
|
## Kompatybilność
|
||||||
|
|
||||||
|
KernelSU oficjalnie obsługuje urządzenia z Androidem GKI 2.0 (z jądrem 5.10+), starsze jądra (4.14+) są również kompatybilne, ale musisz sam skompilować jądro.
|
||||||
|
|
||||||
|
WSA i Android oparty na kontenerach również powinny działać ze zintegrowanym KernelSU.
|
||||||
|
|
||||||
|
Aktualnie obsługiwane ABI to : `arm64-v8a` i `x86_64`.
|
||||||
|
|
||||||
|
## Użycie
|
||||||
|
|
||||||
|
- [Instalacja](https://kernelsu.org/guide/installation.html)
|
||||||
|
- [Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
|
||||||
|
|
||||||
|
## Tłumaczenie
|
||||||
|
|
||||||
|
Aby pomóc w tłumaczeniu KernelSU lub ulepszyć istniejące tłumaczenia, użyj [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR tłumaczenia Managera nie jest już akceptowany, ponieważ będzie kolidował z Weblate.
|
||||||
|
|
||||||
|
## Dyskusja
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Bezpieczeństwo
|
||||||
|
|
||||||
|
Informacje na temat zgłaszania luk w zabezpieczeniach w KernelSU można znaleźć w pliku [SECURITY.md](/SECURITY.md).
|
||||||
|
|
||||||
|
## Licencja
|
||||||
|
|
||||||
|
- Pliki w katalogu `kernel` są na licencji [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## Podziękowania
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): pomysłodawca KernelSU.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): walidacja podpisu apk v2.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): cenna znajomość rootkitów.
|
||||||
57
docs/README_PT-BR.md
Normal file
57
docs/README_PT-BR.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Uma solução root baseada em kernel para dispositivos Android.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Características
|
||||||
|
|
||||||
|
1. `su` e gerenciamento de acesso root baseado em kernel.
|
||||||
|
2. Sistema modular baseado em [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
3. [Perfil do Aplicativo](https://kernelsu.org/pt_BR/guide/app-profile.html): Tranque o poder root em uma gaiola.
|
||||||
|
|
||||||
|
## Estado de compatibilidade
|
||||||
|
|
||||||
|
O KernelSU oferece suporte oficial a dispositivos Android GKI 2.0 (kernel 5.10+). Kernels mais antigos (4.14+) também são compatíveis, mas o kernel terá que ser construído manualmente.
|
||||||
|
|
||||||
|
Com isso, WSA, ChromeOS e Android baseado em contêiner são todos suportados.
|
||||||
|
|
||||||
|
Atualmente, apenas `arm64-v8a` e `x86_64` são suportados.
|
||||||
|
|
||||||
|
## Uso
|
||||||
|
|
||||||
|
- [Instalação](https://kernelsu.org/pt_BR/guide/installation.html)
|
||||||
|
- [Como construir o KernelSU?](https://kernelsu.org/pt_BR/guide/how-to-build.html)
|
||||||
|
- [Site oficial](https://kernelsu.org/pt_BR/)
|
||||||
|
|
||||||
|
## Tradução
|
||||||
|
|
||||||
|
Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, utilize o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Gerenciador não são mais aceitas, pois podem entrar em conflito com o Weblate.
|
||||||
|
|
||||||
|
## Discussão
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Segurança
|
||||||
|
|
||||||
|
Para obter informações sobre como relatar vulnerabilidades de segurança do KernelSU, consulte [SECURITY.md](/SECURITY.md).
|
||||||
|
|
||||||
|
## Licença
|
||||||
|
|
||||||
|
- Os arquivos no diretório `kernel` são [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- Todas as outras partes, exceto o diretório `kernel` são [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## Créditos
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): a ideia do KernelSU.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): a poderosa ferramenta root.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): validação de assinatura apk v2.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): algumas habilidades de rootkit.
|
||||||
49
docs/README_RU.md
Normal file
49
docs/README_RU.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Решение на основе ядра root для Android-устройств.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Особенности
|
||||||
|
|
||||||
|
1. Управление `su` и root-доступом на основе ядра.
|
||||||
|
2. Система модулей на основе [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
3. [Профиль приложений](https://kernelsu.org/ru_RU/guide/app-profile.html): Запри корневую силу в клетке.
|
||||||
|
|
||||||
|
## Совместимость
|
||||||
|
|
||||||
|
KernelSU официально поддерживает устройства на базе Android GKI 2.0 (с ядром 5.10+), старые ядра (4.14+) также совместимы, но для этого необходимо собрать ядро самостоятельно.
|
||||||
|
|
||||||
|
WSA и Android на основе контейнеров также должны работать с интегрированным KernelSU.
|
||||||
|
|
||||||
|
В настоящее время поддерживаются следующие ABI: `arm64-v8a` и `x86_64`.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
- [Установка](https://kernelsu.org/ru_RU/guide/installation.html)
|
||||||
|
- [Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
|
||||||
|
- [официальный сайт](https://kernelsu.org/ru_RU/)
|
||||||
|
|
||||||
|
## Обсуждение
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
- Файлы в директории `kernel` [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- Все остальные части, кроме директории `kernel` [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## Благодарности
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): идея KernelSU.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): реализация sepolicy.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): проверка подписи apk v2.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): некоторые навыки руткита.
|
||||||
57
docs/README_TR.md
Normal file
57
docs/README_TR.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Android cihazlar için kernel tabanlı root çözümü.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Özellikler
|
||||||
|
|
||||||
|
1. Kernel-tabanlı `su` ve root erişimi yönetimi.
|
||||||
|
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)'ye dayalı modül sistemi.
|
||||||
|
3. [Uygulama profili](https://kernelsu.org/guide/app-profile.html): Root gücünü bir kafese kapatın.
|
||||||
|
|
||||||
|
## Uyumluluk Durumu
|
||||||
|
|
||||||
|
KernelSU resmi olarak Android GKI 2.0 cihazlarını (5.10+ kernelli) destekler, eski kernellerle de (4.14+) uyumludur, ancak kerneli kendinizin derlemeniz gerekir.
|
||||||
|
|
||||||
|
Bununla birlikte; WSA, ChromeOS ve konteyner tabanlı Android'in tamamı desteklenmektedir.
|
||||||
|
|
||||||
|
Şimdilik sadece `arm64-v8a` ve `x86_64` desteklenmektedir.
|
||||||
|
|
||||||
|
## Kullanım
|
||||||
|
|
||||||
|
- [Yükleme yönergeleri](https://kernelsu.org/guide/installation.html)
|
||||||
|
- [Nasıl derlenir?](https://kernelsu.org/guide/how-to-build.html)
|
||||||
|
- [Resmi WEB sitesi](https://kernelsu.org/)
|
||||||
|
|
||||||
|
## Çeviri
|
||||||
|
|
||||||
|
KernelSU'nun çevirisine veya mevcut çevirilerin iyileştirilmesine yardımcı olmak için lütfen [Weblate](https://hosted.weblate.org/engage/kernelsu/) kullanın. Yönetici uygulamasının PR ile çevirisi, Weblate ile çakışacağından artık kabul edilmeyecektir.
|
||||||
|
|
||||||
|
## Tartışma
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Güvenlik
|
||||||
|
|
||||||
|
KernelSU'daki güvenlik açıklarını bildirme hakkında bilgi için, bkz [SECURITY.md](/SECURITY.md).
|
||||||
|
|
||||||
|
## Lisans
|
||||||
|
|
||||||
|
- `kernel` klasöründeki dosyalar [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır.
|
||||||
|
- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3-veya-sonraki](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
|
||||||
|
|
||||||
|
## Krediler
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU fikri.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): güçlü root aracı.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): apk v2 imza doğrulaması.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): bazı rootkit becerileri.
|
||||||
47
docs/README_TW.md
Normal file
47
docs/README_TW.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
一個基於核心的 Android 裝置 Root 解決方案
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
- 基於核心的 `su` 和 Root 存取權管理。
|
||||||
|
- 基於 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模組系統。
|
||||||
|
|
||||||
|
## 相容性狀態
|
||||||
|
|
||||||
|
KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+);舊版核心同樣相容 (最低 4.14+),但需要自行編譯核心。
|
||||||
|
|
||||||
|
WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
|
||||||
|
|
||||||
|
目前支援架構:`arm64-v8a` 和 `x86_64`。
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
- [安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
|
||||||
|
- [如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
|
||||||
|
|
||||||
|
### 討論
|
||||||
|
|
||||||
|
- Telegram:[@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## 授權
|
||||||
|
|
||||||
|
- 目錄 `kernel` 下所有檔案為 [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)。
|
||||||
|
- 除 `kernel` 目錄的其他部分均為 [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html)。
|
||||||
|
|
||||||
|
## 致謝
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/):KernelSU 的靈感。
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk):sepolicy 實作。
|
||||||
|
- [genuine](https://github.com/brevent/genuine/):apk v2 簽章驗證。
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
|
||||||
53
docs/README_VI.md
Normal file
53
docs/README_VI.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md)
|
||||||
|
|
||||||
|
# KernelSU
|
||||||
|
|
||||||
|
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
|
||||||
|
|
||||||
|
Giải pháp root thông qua thay đổi trên Kernel hệ điều hành cho các thiết bị Android.
|
||||||
|
|
||||||
|
[](https://github.com/tiann/KernelSU/releases/latest)
|
||||||
|
[](https://hosted.weblate.org/engage/kernelsu)
|
||||||
|
[](https://t.me/KernelSU)
|
||||||
|
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||||
|
[](/LICENSE)
|
||||||
|
|
||||||
|
## Tính năng
|
||||||
|
|
||||||
|
1. Hỗ trợ gói thực thi `su` và quản lý quyền root.
|
||||||
|
2. Hệ thống mô-đun thông qua [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
|
||||||
|
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Hạn chế quyền root của ứng dụng.
|
||||||
|
|
||||||
|
## Tình trạng tương thích
|
||||||
|
|
||||||
|
KernelSU chính thức hỗ trợ các thiết bị Android với kernel GKI 2.0 (phiên bản kernel 5.10+), các phiên bản kernel cũ hơn (4.14+) cũng tương thích, nhưng bạn cần phải tự biên dịch.
|
||||||
|
|
||||||
|
WSA, ChromeOS và Android dựa trên container(container-based) cũng được hỗ trợ bởi KernelSU.
|
||||||
|
|
||||||
|
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a` và `x86_64`.
|
||||||
|
|
||||||
|
## Sử dụng
|
||||||
|
|
||||||
|
- [Hướng dẫn cài đặt](https://kernelsu.org/vi_VN/guide/installation.html)
|
||||||
|
- [Cách để build?](https://kernelsu.org/vi_VN/guide/how-to-build.html)
|
||||||
|
- [Website Chính Thức](https://kernelsu.org/vi_VN/)
|
||||||
|
|
||||||
|
## Hỗ trợ dịch
|
||||||
|
|
||||||
|
Nếu bạn muốn hỗ trợ dịch KernelSU sang một ngôn ngữ khác hoặc cải thiện các bản dịch trước, vui lòng sử dụng [Weblate](https://hosted.weblate.org/engage/kernelsu/).
|
||||||
|
|
||||||
|
## Thảo luận
|
||||||
|
|
||||||
|
- Telegram: [@KernelSU](https://t.me/KernelSU)
|
||||||
|
|
||||||
|
## Giấy phép
|
||||||
|
|
||||||
|
- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
|
||||||
|
- Tất cả các thành phần khác ngoại trừ thư mục `kernel` dùng giấy phép [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
|
||||||
|
|
||||||
|
## Lời cảm ơn
|
||||||
|
|
||||||
|
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ý tưởng cho KernelSU.
|
||||||
|
- [Magisk](https://github.com/topjohnwu/Magisk): công cụ root mạnh mẽ.
|
||||||
|
- [genuine](https://github.com/brevent/genuine/): phương pháp xác thực apk v2.
|
||||||
|
- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit.
|
||||||
111
js/README.md
Normal file
111
js/README.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Library for KernelSU's module WebUI
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add kernelsu
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### exec
|
||||||
|
|
||||||
|
Spawns a **root** shell and runs a command within that shell, passing the `stdout` and `stderr` to a Promise when complete.
|
||||||
|
|
||||||
|
- `command` `<string>` The command to run, with space-separated arguments.
|
||||||
|
- `options` `<Object>`
|
||||||
|
- `cwd` - Current working directory of the child process
|
||||||
|
- `env` - Environment key-value pairs
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { exec } from 'kernelsu';
|
||||||
|
|
||||||
|
const { errno, stdout, stderr } = await exec('ls -l', { cwd: '/tmp' });
|
||||||
|
if (errno === 0) {
|
||||||
|
// success
|
||||||
|
console.log(stdout);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### spawn
|
||||||
|
|
||||||
|
Spawns a new process using the given `command` in **root** shell, with command-line arguments in `args`. If omitted, `args` defaults to an empty array.
|
||||||
|
|
||||||
|
Returns a `ChildProcess`, Instances of the ChildProcess represent spawned child processes.
|
||||||
|
|
||||||
|
- `command` `<string>` The command to run.
|
||||||
|
- `args` `<string[]>` List of string arguments.
|
||||||
|
- `options` `<Object>`:
|
||||||
|
- `cwd` `<string>` - Current working directory of the child process
|
||||||
|
- `env` `<Object>` - Environment key-value pairs
|
||||||
|
|
||||||
|
Example of running `ls -lh /data`, capturing `stdout`, `stderr`, and the exit code:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { spawn } from 'kernelsu';
|
||||||
|
|
||||||
|
const ls = spawn('ls', ['-lh', '/data']);
|
||||||
|
|
||||||
|
ls.stdout.on('data', (data) => {
|
||||||
|
console.log(`stdout: ${data}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
ls.stderr.on('data', (data) => {
|
||||||
|
console.log(`stderr: ${data}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
ls.on('exit', (code) => {
|
||||||
|
console.log(`child process exited with code ${code}`);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ChildProcess
|
||||||
|
|
||||||
|
##### Event 'exit'
|
||||||
|
|
||||||
|
- `code` `<number>` The exit code if the child exited on its own.
|
||||||
|
|
||||||
|
The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise null
|
||||||
|
|
||||||
|
##### Event 'error'
|
||||||
|
|
||||||
|
- `err` `<Error>` The error.
|
||||||
|
|
||||||
|
The `'error'` event is emitted whenever:
|
||||||
|
|
||||||
|
- The process could not be spawned.
|
||||||
|
- The process could not be killed.
|
||||||
|
|
||||||
|
##### `stdout`
|
||||||
|
|
||||||
|
A `Readable Stream` that represents the child process's `stdout`.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const subprocess = spawn('ls');
|
||||||
|
|
||||||
|
subprocess.stdout.on('data', (data) => {
|
||||||
|
console.log(`Received chunk ${data}`);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `stderr`
|
||||||
|
|
||||||
|
A `Readable Stream` that represents the child process's `stderr`.
|
||||||
|
|
||||||
|
### fullScreen
|
||||||
|
|
||||||
|
Request the WebView enter/exit full screen.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { fullScreen } from 'kernelsu';
|
||||||
|
fullScreen(true);
|
||||||
|
```
|
||||||
|
|
||||||
|
### toast
|
||||||
|
|
||||||
|
Show a toast message.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { toast } from 'kernelsu';
|
||||||
|
toast('Hello, world!');
|
||||||
|
```
|
||||||
115
js/index.js
Normal file
115
js/index.js
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
let callbackCounter = 0;
|
||||||
|
function getUniqueCallbackName(prefix) {
|
||||||
|
return `${prefix}_callback_${Date.now()}_${callbackCounter++}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exec(command, options) {
|
||||||
|
if (typeof options === "undefined") {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// Generate a unique callback function name
|
||||||
|
const callbackFuncName = getUniqueCallbackName("exec");
|
||||||
|
|
||||||
|
// Define the success callback function
|
||||||
|
window[callbackFuncName] = (errno, stdout, stderr) => {
|
||||||
|
resolve({ errno, stdout, stderr });
|
||||||
|
cleanup(callbackFuncName);
|
||||||
|
};
|
||||||
|
|
||||||
|
function cleanup(successName) {
|
||||||
|
delete window[successName];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ksu.exec(command, JSON.stringify(options), callbackFuncName);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
cleanup(callbackFuncName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function Stdio() {
|
||||||
|
this.listeners = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Stdio.prototype.on = function (event, listener) {
|
||||||
|
if (!this.listeners[event]) {
|
||||||
|
this.listeners[event] = [];
|
||||||
|
}
|
||||||
|
this.listeners[event].push(listener);
|
||||||
|
};
|
||||||
|
|
||||||
|
Stdio.prototype.emit = function (event, ...args) {
|
||||||
|
if (this.listeners[event]) {
|
||||||
|
this.listeners[event].forEach((listener) => listener(...args));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function ChildProcess() {
|
||||||
|
this.listeners = {};
|
||||||
|
this.stdin = new Stdio();
|
||||||
|
this.stdout = new Stdio();
|
||||||
|
this.stderr = new Stdio();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChildProcess.prototype.on = function (event, listener) {
|
||||||
|
if (!this.listeners[event]) {
|
||||||
|
this.listeners[event] = [];
|
||||||
|
}
|
||||||
|
this.listeners[event].push(listener);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChildProcess.prototype.emit = function (event, ...args) {
|
||||||
|
if (this.listeners[event]) {
|
||||||
|
this.listeners[event].forEach((listener) => listener(...args));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export function spawn(command, args, options) {
|
||||||
|
if (typeof args === "undefined") {
|
||||||
|
args = [];
|
||||||
|
} else if (typeof args === "object") {
|
||||||
|
// allow for (command, options) signature
|
||||||
|
options = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === "undefined") {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const child = new ChildProcess();
|
||||||
|
const childCallbackName = getUniqueCallbackName("spawn");
|
||||||
|
window[childCallbackName] = child;
|
||||||
|
|
||||||
|
function cleanup(name) {
|
||||||
|
delete window[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
child.on("exit", code => {
|
||||||
|
cleanup(childCallbackName);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
ksu.spawn(
|
||||||
|
command,
|
||||||
|
JSON.stringify(args),
|
||||||
|
JSON.stringify(options),
|
||||||
|
childCallbackName
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
child.emit("error", error);
|
||||||
|
cleanup(childCallbackName);
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fullScreen(isFullScreen) {
|
||||||
|
ksu.fullScreen(isFullScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toast(message) {
|
||||||
|
ksu.toast(message);
|
||||||
|
}
|
||||||
25
js/package.json
Normal file
25
js/package.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "kernelsu",
|
||||||
|
"version": "1.0.6",
|
||||||
|
"description": "Library for KernelSU's module WebUI",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "npm run test"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/tiann/KernelSU.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"su",
|
||||||
|
"kernelsu",
|
||||||
|
"module",
|
||||||
|
"webui"
|
||||||
|
],
|
||||||
|
"author": "weishu",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/tiann/KernelSU/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/tiann/KernelSU#readme"
|
||||||
|
}
|
||||||
10
justfile
Normal file
10
justfile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
alias bk := build_ksud
|
||||||
|
alias bm := build_manager
|
||||||
|
|
||||||
|
build_ksud:
|
||||||
|
cross build --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml
|
||||||
|
|
||||||
|
build_manager: build_ksud
|
||||||
|
cp userspace/ksud/target/aarch64-linux-android/release/ksud manager/app/src/main/jniLibs/arm64-v8a/libksud.so
|
||||||
|
cd manager && ./gradlew aDebug
|
||||||
|
|
||||||
548
kernel/.clang-format
Normal file
548
kernel/.clang-format
Normal file
@@ -0,0 +1,548 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
#
|
||||||
|
# clang-format configuration file. Intended for clang-format >= 4.
|
||||||
|
#
|
||||||
|
# For more information, see:
|
||||||
|
#
|
||||||
|
# Documentation/process/clang-format.rst
|
||||||
|
# https://clang.llvm.org/docs/ClangFormat.html
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||||
|
#
|
||||||
|
---
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: false
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
#AfterExternBlock: false # Unknown to clang-format-5.0
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
#SplitEmptyFunction: true # Unknown to clang-format-4.0
|
||||||
|
#SplitEmptyRecord: true # Unknown to clang-format-4.0
|
||||||
|
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
#CompactNamespaces: false # Unknown to clang-format-4.0
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 8
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
#FixNamespaceComments: false # Unknown to clang-format-4.0
|
||||||
|
|
||||||
|
# Taken from:
|
||||||
|
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
|
||||||
|
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
|
||||||
|
# | sort | uniq
|
||||||
|
ForEachMacros:
|
||||||
|
- 'apei_estatus_for_each_section'
|
||||||
|
- 'ata_for_each_dev'
|
||||||
|
- 'ata_for_each_link'
|
||||||
|
- '__ata_qc_for_each'
|
||||||
|
- 'ata_qc_for_each'
|
||||||
|
- 'ata_qc_for_each_raw'
|
||||||
|
- 'ata_qc_for_each_with_internal'
|
||||||
|
- 'ax25_for_each'
|
||||||
|
- 'ax25_uid_for_each'
|
||||||
|
- '__bio_for_each_bvec'
|
||||||
|
- 'bio_for_each_bvec'
|
||||||
|
- 'bio_for_each_bvec_all'
|
||||||
|
- 'bio_for_each_integrity_vec'
|
||||||
|
- '__bio_for_each_segment'
|
||||||
|
- 'bio_for_each_segment'
|
||||||
|
- 'bio_for_each_segment_all'
|
||||||
|
- 'bio_list_for_each'
|
||||||
|
- 'bip_for_each_vec'
|
||||||
|
- 'bitmap_for_each_clear_region'
|
||||||
|
- 'bitmap_for_each_set_region'
|
||||||
|
- 'blkg_for_each_descendant_post'
|
||||||
|
- 'blkg_for_each_descendant_pre'
|
||||||
|
- 'blk_queue_for_each_rl'
|
||||||
|
- 'bond_for_each_slave'
|
||||||
|
- 'bond_for_each_slave_rcu'
|
||||||
|
- 'bpf_for_each_spilled_reg'
|
||||||
|
- 'btree_for_each_safe128'
|
||||||
|
- 'btree_for_each_safe32'
|
||||||
|
- 'btree_for_each_safe64'
|
||||||
|
- 'btree_for_each_safel'
|
||||||
|
- 'card_for_each_dev'
|
||||||
|
- 'cgroup_taskset_for_each'
|
||||||
|
- 'cgroup_taskset_for_each_leader'
|
||||||
|
- 'cpufreq_for_each_entry'
|
||||||
|
- 'cpufreq_for_each_entry_idx'
|
||||||
|
- 'cpufreq_for_each_valid_entry'
|
||||||
|
- 'cpufreq_for_each_valid_entry_idx'
|
||||||
|
- 'css_for_each_child'
|
||||||
|
- 'css_for_each_descendant_post'
|
||||||
|
- 'css_for_each_descendant_pre'
|
||||||
|
- 'device_for_each_child_node'
|
||||||
|
- 'dma_fence_chain_for_each'
|
||||||
|
- 'do_for_each_ftrace_op'
|
||||||
|
- 'drm_atomic_crtc_for_each_plane'
|
||||||
|
- 'drm_atomic_crtc_state_for_each_plane'
|
||||||
|
- 'drm_atomic_crtc_state_for_each_plane_state'
|
||||||
|
- 'drm_atomic_for_each_plane_damage'
|
||||||
|
- 'drm_client_for_each_connector_iter'
|
||||||
|
- 'drm_client_for_each_modeset'
|
||||||
|
- 'drm_connector_for_each_possible_encoder'
|
||||||
|
- 'drm_for_each_bridge_in_chain'
|
||||||
|
- 'drm_for_each_connector_iter'
|
||||||
|
- 'drm_for_each_crtc'
|
||||||
|
- 'drm_for_each_encoder'
|
||||||
|
- 'drm_for_each_encoder_mask'
|
||||||
|
- 'drm_for_each_fb'
|
||||||
|
- 'drm_for_each_legacy_plane'
|
||||||
|
- 'drm_for_each_plane'
|
||||||
|
- 'drm_for_each_plane_mask'
|
||||||
|
- 'drm_for_each_privobj'
|
||||||
|
- 'drm_mm_for_each_hole'
|
||||||
|
- 'drm_mm_for_each_node'
|
||||||
|
- 'drm_mm_for_each_node_in_range'
|
||||||
|
- 'drm_mm_for_each_node_safe'
|
||||||
|
- 'flow_action_for_each'
|
||||||
|
- 'for_each_active_dev_scope'
|
||||||
|
- 'for_each_active_drhd_unit'
|
||||||
|
- 'for_each_active_iommu'
|
||||||
|
- 'for_each_aggr_pgid'
|
||||||
|
- 'for_each_available_child_of_node'
|
||||||
|
- 'for_each_bio'
|
||||||
|
- 'for_each_board_func_rsrc'
|
||||||
|
- 'for_each_bvec'
|
||||||
|
- 'for_each_card_auxs'
|
||||||
|
- 'for_each_card_auxs_safe'
|
||||||
|
- 'for_each_card_components'
|
||||||
|
- 'for_each_card_dapms'
|
||||||
|
- 'for_each_card_pre_auxs'
|
||||||
|
- 'for_each_card_prelinks'
|
||||||
|
- 'for_each_card_rtds'
|
||||||
|
- 'for_each_card_rtds_safe'
|
||||||
|
- 'for_each_card_widgets'
|
||||||
|
- 'for_each_card_widgets_safe'
|
||||||
|
- 'for_each_cgroup_storage_type'
|
||||||
|
- 'for_each_child_of_node'
|
||||||
|
- 'for_each_clear_bit'
|
||||||
|
- 'for_each_clear_bit_from'
|
||||||
|
- 'for_each_cmsghdr'
|
||||||
|
- 'for_each_compatible_node'
|
||||||
|
- 'for_each_component_dais'
|
||||||
|
- 'for_each_component_dais_safe'
|
||||||
|
- 'for_each_comp_order'
|
||||||
|
- 'for_each_console'
|
||||||
|
- 'for_each_cpu'
|
||||||
|
- 'for_each_cpu_and'
|
||||||
|
- 'for_each_cpu_not'
|
||||||
|
- 'for_each_cpu_wrap'
|
||||||
|
- 'for_each_dapm_widgets'
|
||||||
|
- 'for_each_dev_addr'
|
||||||
|
- 'for_each_dev_scope'
|
||||||
|
- 'for_each_displayid_db'
|
||||||
|
- 'for_each_dma_cap_mask'
|
||||||
|
- 'for_each_dpcm_be'
|
||||||
|
- 'for_each_dpcm_be_rollback'
|
||||||
|
- 'for_each_dpcm_be_safe'
|
||||||
|
- 'for_each_dpcm_fe'
|
||||||
|
- 'for_each_drhd_unit'
|
||||||
|
- 'for_each_dss_dev'
|
||||||
|
- 'for_each_efi_memory_desc'
|
||||||
|
- 'for_each_efi_memory_desc_in_map'
|
||||||
|
- 'for_each_element'
|
||||||
|
- 'for_each_element_extid'
|
||||||
|
- 'for_each_element_id'
|
||||||
|
- 'for_each_endpoint_of_node'
|
||||||
|
- 'for_each_evictable_lru'
|
||||||
|
- 'for_each_fib6_node_rt_rcu'
|
||||||
|
- 'for_each_fib6_walker_rt'
|
||||||
|
- 'for_each_free_mem_pfn_range_in_zone'
|
||||||
|
- 'for_each_free_mem_pfn_range_in_zone_from'
|
||||||
|
- 'for_each_free_mem_range'
|
||||||
|
- 'for_each_free_mem_range_reverse'
|
||||||
|
- 'for_each_func_rsrc'
|
||||||
|
- 'for_each_hstate'
|
||||||
|
- 'for_each_if'
|
||||||
|
- 'for_each_iommu'
|
||||||
|
- 'for_each_ip_tunnel_rcu'
|
||||||
|
- 'for_each_irq_nr'
|
||||||
|
- 'for_each_link_codecs'
|
||||||
|
- 'for_each_link_cpus'
|
||||||
|
- 'for_each_link_platforms'
|
||||||
|
- 'for_each_lru'
|
||||||
|
- 'for_each_matching_node'
|
||||||
|
- 'for_each_matching_node_and_match'
|
||||||
|
- 'for_each_member'
|
||||||
|
- 'for_each_mem_region'
|
||||||
|
- 'for_each_memblock_type'
|
||||||
|
- 'for_each_memcg_cache_index'
|
||||||
|
- 'for_each_mem_pfn_range'
|
||||||
|
- '__for_each_mem_range'
|
||||||
|
- 'for_each_mem_range'
|
||||||
|
- '__for_each_mem_range_rev'
|
||||||
|
- 'for_each_mem_range_rev'
|
||||||
|
- 'for_each_migratetype_order'
|
||||||
|
- 'for_each_msi_entry'
|
||||||
|
- 'for_each_msi_entry_safe'
|
||||||
|
- 'for_each_net'
|
||||||
|
- 'for_each_net_continue_reverse'
|
||||||
|
- 'for_each_netdev'
|
||||||
|
- 'for_each_netdev_continue'
|
||||||
|
- 'for_each_netdev_continue_rcu'
|
||||||
|
- 'for_each_netdev_continue_reverse'
|
||||||
|
- 'for_each_netdev_feature'
|
||||||
|
- 'for_each_netdev_in_bond_rcu'
|
||||||
|
- 'for_each_netdev_rcu'
|
||||||
|
- 'for_each_netdev_reverse'
|
||||||
|
- 'for_each_netdev_safe'
|
||||||
|
- 'for_each_net_rcu'
|
||||||
|
- 'for_each_new_connector_in_state'
|
||||||
|
- 'for_each_new_crtc_in_state'
|
||||||
|
- 'for_each_new_mst_mgr_in_state'
|
||||||
|
- 'for_each_new_plane_in_state'
|
||||||
|
- 'for_each_new_private_obj_in_state'
|
||||||
|
- 'for_each_node'
|
||||||
|
- 'for_each_node_by_name'
|
||||||
|
- 'for_each_node_by_type'
|
||||||
|
- 'for_each_node_mask'
|
||||||
|
- 'for_each_node_state'
|
||||||
|
- 'for_each_node_with_cpus'
|
||||||
|
- 'for_each_node_with_property'
|
||||||
|
- 'for_each_nonreserved_multicast_dest_pgid'
|
||||||
|
- 'for_each_of_allnodes'
|
||||||
|
- 'for_each_of_allnodes_from'
|
||||||
|
- 'for_each_of_cpu_node'
|
||||||
|
- 'for_each_of_pci_range'
|
||||||
|
- 'for_each_old_connector_in_state'
|
||||||
|
- 'for_each_old_crtc_in_state'
|
||||||
|
- 'for_each_old_mst_mgr_in_state'
|
||||||
|
- 'for_each_oldnew_connector_in_state'
|
||||||
|
- 'for_each_oldnew_crtc_in_state'
|
||||||
|
- 'for_each_oldnew_mst_mgr_in_state'
|
||||||
|
- 'for_each_oldnew_plane_in_state'
|
||||||
|
- 'for_each_oldnew_plane_in_state_reverse'
|
||||||
|
- 'for_each_oldnew_private_obj_in_state'
|
||||||
|
- 'for_each_old_plane_in_state'
|
||||||
|
- 'for_each_old_private_obj_in_state'
|
||||||
|
- 'for_each_online_cpu'
|
||||||
|
- 'for_each_online_node'
|
||||||
|
- 'for_each_online_pgdat'
|
||||||
|
- 'for_each_pci_bridge'
|
||||||
|
- 'for_each_pci_dev'
|
||||||
|
- 'for_each_pci_msi_entry'
|
||||||
|
- 'for_each_pcm_streams'
|
||||||
|
- 'for_each_physmem_range'
|
||||||
|
- 'for_each_populated_zone'
|
||||||
|
- 'for_each_possible_cpu'
|
||||||
|
- 'for_each_present_cpu'
|
||||||
|
- 'for_each_prime_number'
|
||||||
|
- 'for_each_prime_number_from'
|
||||||
|
- 'for_each_process'
|
||||||
|
- 'for_each_process_thread'
|
||||||
|
- 'for_each_property_of_node'
|
||||||
|
- 'for_each_registered_fb'
|
||||||
|
- 'for_each_requested_gpio'
|
||||||
|
- 'for_each_requested_gpio_in_range'
|
||||||
|
- 'for_each_reserved_mem_range'
|
||||||
|
- 'for_each_reserved_mem_region'
|
||||||
|
- 'for_each_rtd_codec_dais'
|
||||||
|
- 'for_each_rtd_codec_dais_rollback'
|
||||||
|
- 'for_each_rtd_components'
|
||||||
|
- 'for_each_rtd_cpu_dais'
|
||||||
|
- 'for_each_rtd_cpu_dais_rollback'
|
||||||
|
- 'for_each_rtd_dais'
|
||||||
|
- 'for_each_set_bit'
|
||||||
|
- 'for_each_set_bit_from'
|
||||||
|
- 'for_each_set_clump8'
|
||||||
|
- 'for_each_sg'
|
||||||
|
- 'for_each_sg_dma_page'
|
||||||
|
- 'for_each_sg_page'
|
||||||
|
- 'for_each_sgtable_dma_page'
|
||||||
|
- 'for_each_sgtable_dma_sg'
|
||||||
|
- 'for_each_sgtable_page'
|
||||||
|
- 'for_each_sgtable_sg'
|
||||||
|
- 'for_each_sibling_event'
|
||||||
|
- 'for_each_subelement'
|
||||||
|
- 'for_each_subelement_extid'
|
||||||
|
- 'for_each_subelement_id'
|
||||||
|
- '__for_each_thread'
|
||||||
|
- 'for_each_thread'
|
||||||
|
- 'for_each_unicast_dest_pgid'
|
||||||
|
- 'for_each_wakeup_source'
|
||||||
|
- 'for_each_zone'
|
||||||
|
- 'for_each_zone_zonelist'
|
||||||
|
- 'for_each_zone_zonelist_nodemask'
|
||||||
|
- 'fwnode_for_each_available_child_node'
|
||||||
|
- 'fwnode_for_each_child_node'
|
||||||
|
- 'fwnode_graph_for_each_endpoint'
|
||||||
|
- 'gadget_for_each_ep'
|
||||||
|
- 'genradix_for_each'
|
||||||
|
- 'genradix_for_each_from'
|
||||||
|
- 'hash_for_each'
|
||||||
|
- 'hash_for_each_possible'
|
||||||
|
- 'hash_for_each_possible_rcu'
|
||||||
|
- 'hash_for_each_possible_rcu_notrace'
|
||||||
|
- 'hash_for_each_possible_safe'
|
||||||
|
- 'hash_for_each_rcu'
|
||||||
|
- 'hash_for_each_safe'
|
||||||
|
- 'hctx_for_each_ctx'
|
||||||
|
- 'hlist_bl_for_each_entry'
|
||||||
|
- 'hlist_bl_for_each_entry_rcu'
|
||||||
|
- 'hlist_bl_for_each_entry_safe'
|
||||||
|
- 'hlist_for_each'
|
||||||
|
- 'hlist_for_each_entry'
|
||||||
|
- 'hlist_for_each_entry_continue'
|
||||||
|
- 'hlist_for_each_entry_continue_rcu'
|
||||||
|
- 'hlist_for_each_entry_continue_rcu_bh'
|
||||||
|
- 'hlist_for_each_entry_from'
|
||||||
|
- 'hlist_for_each_entry_from_rcu'
|
||||||
|
- 'hlist_for_each_entry_rcu'
|
||||||
|
- 'hlist_for_each_entry_rcu_bh'
|
||||||
|
- 'hlist_for_each_entry_rcu_notrace'
|
||||||
|
- 'hlist_for_each_entry_safe'
|
||||||
|
- '__hlist_for_each_rcu'
|
||||||
|
- 'hlist_for_each_safe'
|
||||||
|
- 'hlist_nulls_for_each_entry'
|
||||||
|
- 'hlist_nulls_for_each_entry_from'
|
||||||
|
- 'hlist_nulls_for_each_entry_rcu'
|
||||||
|
- 'hlist_nulls_for_each_entry_safe'
|
||||||
|
- 'i3c_bus_for_each_i2cdev'
|
||||||
|
- 'i3c_bus_for_each_i3cdev'
|
||||||
|
- 'ide_host_for_each_port'
|
||||||
|
- 'ide_port_for_each_dev'
|
||||||
|
- 'ide_port_for_each_present_dev'
|
||||||
|
- 'idr_for_each_entry'
|
||||||
|
- 'idr_for_each_entry_continue'
|
||||||
|
- 'idr_for_each_entry_continue_ul'
|
||||||
|
- 'idr_for_each_entry_ul'
|
||||||
|
- 'in_dev_for_each_ifa_rcu'
|
||||||
|
- 'in_dev_for_each_ifa_rtnl'
|
||||||
|
- 'inet_bind_bucket_for_each'
|
||||||
|
- 'inet_lhash2_for_each_icsk_rcu'
|
||||||
|
- 'key_for_each'
|
||||||
|
- 'key_for_each_safe'
|
||||||
|
- 'klp_for_each_func'
|
||||||
|
- 'klp_for_each_func_safe'
|
||||||
|
- 'klp_for_each_func_static'
|
||||||
|
- 'klp_for_each_object'
|
||||||
|
- 'klp_for_each_object_safe'
|
||||||
|
- 'klp_for_each_object_static'
|
||||||
|
- 'kunit_suite_for_each_test_case'
|
||||||
|
- 'kvm_for_each_memslot'
|
||||||
|
- 'kvm_for_each_vcpu'
|
||||||
|
- 'list_for_each'
|
||||||
|
- 'list_for_each_codec'
|
||||||
|
- 'list_for_each_codec_safe'
|
||||||
|
- 'list_for_each_continue'
|
||||||
|
- 'list_for_each_entry'
|
||||||
|
- 'list_for_each_entry_continue'
|
||||||
|
- 'list_for_each_entry_continue_rcu'
|
||||||
|
- 'list_for_each_entry_continue_reverse'
|
||||||
|
- 'list_for_each_entry_from'
|
||||||
|
- 'list_for_each_entry_from_rcu'
|
||||||
|
- 'list_for_each_entry_from_reverse'
|
||||||
|
- 'list_for_each_entry_lockless'
|
||||||
|
- 'list_for_each_entry_rcu'
|
||||||
|
- 'list_for_each_entry_reverse'
|
||||||
|
- 'list_for_each_entry_safe'
|
||||||
|
- 'list_for_each_entry_safe_continue'
|
||||||
|
- 'list_for_each_entry_safe_from'
|
||||||
|
- 'list_for_each_entry_safe_reverse'
|
||||||
|
- 'list_for_each_prev'
|
||||||
|
- 'list_for_each_prev_safe'
|
||||||
|
- 'list_for_each_safe'
|
||||||
|
- 'llist_for_each'
|
||||||
|
- 'llist_for_each_entry'
|
||||||
|
- 'llist_for_each_entry_safe'
|
||||||
|
- 'llist_for_each_safe'
|
||||||
|
- 'mci_for_each_dimm'
|
||||||
|
- 'media_device_for_each_entity'
|
||||||
|
- 'media_device_for_each_intf'
|
||||||
|
- 'media_device_for_each_link'
|
||||||
|
- 'media_device_for_each_pad'
|
||||||
|
- 'nanddev_io_for_each_page'
|
||||||
|
- 'netdev_for_each_lower_dev'
|
||||||
|
- 'netdev_for_each_lower_private'
|
||||||
|
- 'netdev_for_each_lower_private_rcu'
|
||||||
|
- 'netdev_for_each_mc_addr'
|
||||||
|
- 'netdev_for_each_uc_addr'
|
||||||
|
- 'netdev_for_each_upper_dev_rcu'
|
||||||
|
- 'netdev_hw_addr_list_for_each'
|
||||||
|
- 'nft_rule_for_each_expr'
|
||||||
|
- 'nla_for_each_attr'
|
||||||
|
- 'nla_for_each_nested'
|
||||||
|
- 'nlmsg_for_each_attr'
|
||||||
|
- 'nlmsg_for_each_msg'
|
||||||
|
- 'nr_neigh_for_each'
|
||||||
|
- 'nr_neigh_for_each_safe'
|
||||||
|
- 'nr_node_for_each'
|
||||||
|
- 'nr_node_for_each_safe'
|
||||||
|
- 'of_for_each_phandle'
|
||||||
|
- 'of_property_for_each_string'
|
||||||
|
- 'of_property_for_each_u32'
|
||||||
|
- 'pci_bus_for_each_resource'
|
||||||
|
- 'pcm_for_each_format'
|
||||||
|
- 'ping_portaddr_for_each_entry'
|
||||||
|
- 'plist_for_each'
|
||||||
|
- 'plist_for_each_continue'
|
||||||
|
- 'plist_for_each_entry'
|
||||||
|
- 'plist_for_each_entry_continue'
|
||||||
|
- 'plist_for_each_entry_safe'
|
||||||
|
- 'plist_for_each_safe'
|
||||||
|
- 'pnp_for_each_card'
|
||||||
|
- 'pnp_for_each_dev'
|
||||||
|
- 'protocol_for_each_card'
|
||||||
|
- 'protocol_for_each_dev'
|
||||||
|
- 'queue_for_each_hw_ctx'
|
||||||
|
- 'radix_tree_for_each_slot'
|
||||||
|
- 'radix_tree_for_each_tagged'
|
||||||
|
- 'rbtree_postorder_for_each_entry_safe'
|
||||||
|
- 'rdma_for_each_block'
|
||||||
|
- 'rdma_for_each_port'
|
||||||
|
- 'rdma_umem_for_each_dma_block'
|
||||||
|
- 'resource_list_for_each_entry'
|
||||||
|
- 'resource_list_for_each_entry_safe'
|
||||||
|
- 'rhl_for_each_entry_rcu'
|
||||||
|
- 'rhl_for_each_rcu'
|
||||||
|
- 'rht_for_each'
|
||||||
|
- 'rht_for_each_entry'
|
||||||
|
- 'rht_for_each_entry_from'
|
||||||
|
- 'rht_for_each_entry_rcu'
|
||||||
|
- 'rht_for_each_entry_rcu_from'
|
||||||
|
- 'rht_for_each_entry_safe'
|
||||||
|
- 'rht_for_each_from'
|
||||||
|
- 'rht_for_each_rcu'
|
||||||
|
- 'rht_for_each_rcu_from'
|
||||||
|
- '__rq_for_each_bio'
|
||||||
|
- 'rq_for_each_bvec'
|
||||||
|
- 'rq_for_each_segment'
|
||||||
|
- 'scsi_for_each_prot_sg'
|
||||||
|
- 'scsi_for_each_sg'
|
||||||
|
- 'sctp_for_each_hentry'
|
||||||
|
- 'sctp_skb_for_each'
|
||||||
|
- 'shdma_for_each_chan'
|
||||||
|
- '__shost_for_each_device'
|
||||||
|
- 'shost_for_each_device'
|
||||||
|
- 'sk_for_each'
|
||||||
|
- 'sk_for_each_bound'
|
||||||
|
- 'sk_for_each_entry_offset_rcu'
|
||||||
|
- 'sk_for_each_from'
|
||||||
|
- 'sk_for_each_rcu'
|
||||||
|
- 'sk_for_each_safe'
|
||||||
|
- 'sk_nulls_for_each'
|
||||||
|
- 'sk_nulls_for_each_from'
|
||||||
|
- 'sk_nulls_for_each_rcu'
|
||||||
|
- 'snd_array_for_each'
|
||||||
|
- 'snd_pcm_group_for_each_entry'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_path'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_path_safe'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_sink_path'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_source_path'
|
||||||
|
- 'tb_property_for_each'
|
||||||
|
- 'tcf_exts_for_each_action'
|
||||||
|
- 'udp_portaddr_for_each_entry'
|
||||||
|
- 'udp_portaddr_for_each_entry_rcu'
|
||||||
|
- 'usb_hub_for_each_child'
|
||||||
|
- 'v4l2_device_for_each_subdev'
|
||||||
|
- 'v4l2_m2m_for_each_dst_buf'
|
||||||
|
- 'v4l2_m2m_for_each_dst_buf_safe'
|
||||||
|
- 'v4l2_m2m_for_each_src_buf'
|
||||||
|
- 'v4l2_m2m_for_each_src_buf_safe'
|
||||||
|
- 'virtio_device_for_each_vq'
|
||||||
|
- 'while_for_each_ftrace_op'
|
||||||
|
- 'xa_for_each'
|
||||||
|
- 'xa_for_each_marked'
|
||||||
|
- 'xa_for_each_range'
|
||||||
|
- 'xa_for_each_start'
|
||||||
|
- 'xas_for_each'
|
||||||
|
- 'xas_for_each_conflict'
|
||||||
|
- 'xas_for_each_marked'
|
||||||
|
- 'xbc_array_for_each_value'
|
||||||
|
- 'xbc_for_each_key_value'
|
||||||
|
- 'xbc_node_for_each_array_value'
|
||||||
|
- 'xbc_node_for_each_child'
|
||||||
|
- 'xbc_node_for_each_key_value'
|
||||||
|
- 'zorro_for_each_dev'
|
||||||
|
|
||||||
|
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
#IndentPPDirectives: None # Unknown to clang-format-5.0
|
||||||
|
IndentWidth: 8
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
|
||||||
|
ObjCBlockIndentWidth: 8
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
|
||||||
|
# Taken from git's rules
|
||||||
|
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 30
|
||||||
|
PenaltyBreakComment: 10
|
||||||
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakString: 10
|
||||||
|
PenaltyExcessCharacter: 100
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
#SortUsingDeclarations: false # Unknown to clang-format-4.0
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
|
||||||
|
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp03
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Always
|
||||||
|
...
|
||||||
4
kernel/.clangd
Normal file
4
kernel/.clangd
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Diagnostics:
|
||||||
|
UnusedIncludes: Strict
|
||||||
|
ClangTidy:
|
||||||
|
Remove: bugprone-sizeof-expression
|
||||||
@@ -1,5 +1,17 @@
|
|||||||
|
menu "KernelSU"
|
||||||
|
|
||||||
config KSU
|
config KSU
|
||||||
tristate "KernelSU module"
|
tristate "KernelSU function support"
|
||||||
|
depends on OVERLAY_FS
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This is the KSU privilege driver for android system.
|
Enable kernel-level root privileges on Android System.
|
||||||
|
|
||||||
|
config KSU_DEBUG
|
||||||
|
bool "KernelSU debug mode"
|
||||||
|
depends on KSU
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable KernelSU debug mode
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|||||||
339
kernel/LICENSE
Normal file
339
kernel/LICENSE
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
@@ -1,9 +1,46 @@
|
|||||||
obj-y += ksu.o
|
obj-y += ksu.o
|
||||||
obj-y += allowlist.o
|
obj-y += allowlist.o
|
||||||
obj-y += apk_sign.o
|
kernelsu-objs := apk_sign.o
|
||||||
|
obj-y += kernelsu.o
|
||||||
obj-y += module_api.o
|
obj-y += module_api.o
|
||||||
obj-y += sucompat.o
|
obj-y += sucompat.o
|
||||||
|
obj-y += uid_observer.o
|
||||||
|
obj-y += manager.o
|
||||||
|
obj-y += core_hook.o
|
||||||
|
obj-y += ksud.o
|
||||||
|
obj-y += embed_ksud.o
|
||||||
|
obj-y += kernel_compat.o
|
||||||
|
|
||||||
obj-y += selinux/
|
obj-y += selinux/
|
||||||
|
# .git is a text file while the module is imported by 'git submodule add'.
|
||||||
|
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
|
||||||
|
KSU_GIT_VERSION := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git rev-list --count HEAD)
|
||||||
|
# ksu_version: major * 10000 + git version + 200 for historical reasons
|
||||||
|
$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 200))
|
||||||
|
$(info -- KernelSU version: $(KSU_VERSION))
|
||||||
|
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
|
||||||
|
else # If there is no .git file, the default version will be passed.
|
||||||
|
$(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU a git submodule!")
|
||||||
|
ccflags-y += -DKSU_VERSION=16
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef KSU_EXPECTED_SIZE
|
||||||
|
KSU_EXPECTED_SIZE := 0x033b
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef KSU_EXPECTED_HASH
|
||||||
|
KSU_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef KSU_MANAGER_PACKAGE
|
||||||
|
ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\"
|
||||||
|
$(info -- KernelSU Manager package name: $(KSU_MANAGER_PACKAGE))
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(info -- KernelSU Manager signature size: $(KSU_EXPECTED_SIZE))
|
||||||
|
$(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
|
||||||
|
|
||||||
|
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
|
||||||
|
ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\"
|
||||||
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
||||||
|
ccflags-y += -Wno-declaration-after-statement
|
||||||
|
|||||||
@@ -1,252 +1,519 @@
|
|||||||
#include <linux/cpu.h>
|
#include "ksu.h"
|
||||||
#include <linux/errno.h>
|
#include "linux/compiler.h"
|
||||||
#include <linux/init.h>
|
#include "linux/fs.h"
|
||||||
#include <linux/kernel.h>
|
#include "linux/gfp.h"
|
||||||
#include <linux/kprobes.h>
|
#include "linux/kernel.h"
|
||||||
#include <linux/memory.h>
|
#include "linux/list.h"
|
||||||
#include <linux/module.h>
|
#include "linux/printk.h"
|
||||||
#include <linux/printk.h>
|
#include "linux/slab.h"
|
||||||
#include <linux/slab.h>
|
#include "linux/types.h"
|
||||||
#include <linux/string.h>
|
#include "linux/version.h"
|
||||||
#include <linux/uaccess.h>
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||||
#include <linux/uidgid.h>
|
#include "linux/compiler_types.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <linux/fdtable.h>
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/fs_struct.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
#include <linux/rcupdate.h>
|
|
||||||
|
|
||||||
#include <linux/delay.h> // msleep
|
|
||||||
|
|
||||||
#include "klog.h"
|
|
||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
#include "allowlist.h"
|
||||||
|
|
||||||
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
|
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
|
||||||
#define FILE_FORMAT_VERSION 1 // u32
|
#define FILE_FORMAT_VERSION 3 // u32
|
||||||
|
|
||||||
|
#define KSU_APP_PROFILE_PRESERVE_UID 9999 // NOBODY_UID
|
||||||
|
#define KSU_DEFAULT_SELINUX_DOMAIN "u:r:su:s0"
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(allowlist_mutex);
|
||||||
|
|
||||||
|
// default profiles, these may be used frequently, so we cache it
|
||||||
|
static struct root_profile default_root_profile;
|
||||||
|
static struct non_root_profile default_non_root_profile;
|
||||||
|
|
||||||
|
static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly __aligned(PAGE_SIZE);
|
||||||
|
static int allow_list_pointer __read_mostly = 0;
|
||||||
|
|
||||||
|
static void remove_uid_from_arr(uid_t uid)
|
||||||
|
{
|
||||||
|
int *temp_arr;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (allow_list_pointer == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
temp_arr = kmalloc(sizeof(allow_list_arr), GFP_KERNEL);
|
||||||
|
if (temp_arr == NULL) {
|
||||||
|
pr_err("%s: unable to allocate memory\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = j = 0; i < allow_list_pointer; i++) {
|
||||||
|
if (allow_list_arr[i] == uid)
|
||||||
|
continue;
|
||||||
|
temp_arr[j++] = allow_list_arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_list_pointer = j;
|
||||||
|
|
||||||
|
for (; j < ARRAY_SIZE(allow_list_arr); j++)
|
||||||
|
temp_arr[j] = -1;
|
||||||
|
|
||||||
|
memcpy(&allow_list_arr, temp_arr, PAGE_SIZE);
|
||||||
|
kfree(temp_arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_default_profiles()
|
||||||
|
{
|
||||||
|
default_root_profile.uid = 0;
|
||||||
|
default_root_profile.gid = 0;
|
||||||
|
default_root_profile.groups_count = 1;
|
||||||
|
default_root_profile.groups[0] = 0;
|
||||||
|
memset(&default_root_profile.capabilities, 0xff,
|
||||||
|
sizeof(default_root_profile.capabilities));
|
||||||
|
default_root_profile.namespaces = 0;
|
||||||
|
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
||||||
|
|
||||||
|
// This means that we will umount modules by default!
|
||||||
|
default_non_root_profile.umount_modules = true;
|
||||||
|
}
|
||||||
|
|
||||||
struct perm_data {
|
struct perm_data {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
uid_t uid;
|
struct app_profile profile;
|
||||||
bool allow;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct list_head allow_list;
|
static struct list_head allow_list;
|
||||||
|
|
||||||
#define KERNEL_SU_ALLOWLIST "/data/adb/.ksu_allowlist"
|
static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
|
||||||
|
#define BITMAP_UID_MAX ((sizeof(allow_list_bitmap) * BITS_PER_BYTE) - 1)
|
||||||
|
|
||||||
|
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
|
||||||
|
|
||||||
static struct workqueue_struct *ksu_workqueue;
|
|
||||||
static struct work_struct ksu_save_work;
|
static struct work_struct ksu_save_work;
|
||||||
static struct work_struct ksu_load_work;
|
static struct work_struct ksu_load_work;
|
||||||
|
|
||||||
bool persistent_allow_list(void);
|
bool persistent_allow_list(void);
|
||||||
|
|
||||||
struct file *permissive_filp_open(const char * path, int flags, umode_t mode) {
|
void ksu_show_allow_list(void)
|
||||||
struct file* fp;
|
{
|
||||||
// fixme: u:r:kernel:s0 don't have permission to write /data/adb...
|
struct perm_data *p = NULL;
|
||||||
bool enforcing = getenforce();
|
struct list_head *pos = NULL;
|
||||||
if (enforcing) setenforce(false);
|
pr_info("ksu_show_allow_list\n");
|
||||||
fp = filp_open(path, flags, mode);
|
list_for_each (pos, &allow_list) {
|
||||||
if (enforcing) setenforce(true);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
return fp;
|
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
|
||||||
|
p->profile.allow_su);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_allow_uid(uid_t uid, bool allow) {
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
|
static void ksu_grant_root_to_shell()
|
||||||
// find the node first!
|
{
|
||||||
struct perm_data *p = NULL;
|
struct app_profile profile = {
|
||||||
struct list_head *pos = NULL;
|
.allow_su = true,
|
||||||
bool result = false;
|
.current_uid = 2000,
|
||||||
list_for_each(pos, &allow_list) {
|
};
|
||||||
p = list_entry(pos, struct perm_data, list);
|
strcpy(profile.key, "com.android.shell");
|
||||||
pr_info("ksu_allow_uid :%d, allow: %d\n", p->uid, p->allow);
|
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
||||||
if (uid == p->uid) {
|
ksu_set_app_profile(&profile, false);
|
||||||
p->allow = allow;
|
|
||||||
result = true;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// not found, alloc a new node!
|
|
||||||
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
|
|
||||||
if (!p) {
|
|
||||||
pr_err("alloc allow node failed.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
p->uid = uid;
|
|
||||||
p->allow = allow;
|
|
||||||
|
|
||||||
list_add_tail(&p->list, &allow_list);
|
|
||||||
result = true;
|
|
||||||
|
|
||||||
exit:
|
|
||||||
|
|
||||||
persistent_allow_list();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_is_allow_uid(uid_t uid) {
|
|
||||||
struct perm_data *p = NULL;
|
|
||||||
struct list_head *pos = NULL;
|
|
||||||
list_for_each(pos, &allow_list) {
|
|
||||||
p = list_entry(pos, struct perm_data, list);
|
|
||||||
// pr_info("is_allow_uid uid :%d, allow: %d\n", p->uid, p->allow);
|
|
||||||
if (uid == p->uid) {
|
|
||||||
return p->allow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ksu_get_allow_list(int *array, int *length, bool allow) {
|
|
||||||
struct perm_data *p = NULL;
|
|
||||||
struct list_head *pos = NULL;
|
|
||||||
int i = 0;
|
|
||||||
list_for_each(pos, &allow_list) {
|
|
||||||
p = list_entry(pos, struct perm_data, list);
|
|
||||||
pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
|
|
||||||
if (p->allow == allow) {
|
|
||||||
array[i++] = p->uid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*length = i;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_persistent_allow_list(struct work_struct *work) {
|
|
||||||
u32 magic = FILE_MAGIC;
|
|
||||||
u32 version = FILE_FORMAT_VERSION;
|
|
||||||
struct perm_data *p = NULL;
|
|
||||||
struct list_head *pos = NULL;
|
|
||||||
loff_t off = 0;
|
|
||||||
|
|
||||||
struct file *fp = permissive_filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
|
|
||||||
|
|
||||||
if (IS_ERR(fp)) {
|
|
||||||
pr_err("save_allow_list creat file failed: %d\n", PTR_ERR(fp));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store magic and version
|
|
||||||
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
|
|
||||||
pr_err("save_allow_list write magic failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
|
||||||
pr_err("save_allow_list write version failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each(pos, &allow_list) {
|
|
||||||
p = list_entry(pos, struct perm_data, list);
|
|
||||||
pr_info("save allow list uid :%d, allow: %d\n", p->uid, p->allow);
|
|
||||||
kernel_write(fp, &p->uid, sizeof(p->uid), &off);
|
|
||||||
kernel_write(fp, &p->allow, sizeof(p->allow), &off);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
filp_close(fp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_load_allow_list(struct work_struct *work) {
|
|
||||||
|
|
||||||
loff_t off = 0;
|
|
||||||
ssize_t ret = 0;
|
|
||||||
struct file *fp = NULL;
|
|
||||||
int n = 0;
|
|
||||||
u32 magic;
|
|
||||||
u32 version;
|
|
||||||
|
|
||||||
fp = filp_open("/data/adb/", O_RDONLY, 0);
|
|
||||||
if (IS_ERR(fp)) {
|
|
||||||
int errno = PTR_ERR(fp);
|
|
||||||
pr_err("load_allow_list open '/data/adb' failed: %d\n", PTR_ERR(fp));
|
|
||||||
if (errno == -ENOENT) {
|
|
||||||
msleep(2000);
|
|
||||||
queue_work(ksu_workqueue, &ksu_load_work);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
pr_info("load_allow list dir exist now!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
filp_close(fp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// load allowlist now!
|
|
||||||
fp = permissive_filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
|
|
||||||
|
|
||||||
if (IS_ERR(fp)) {
|
|
||||||
pr_err("load_allow_list open file failed: %d\n", PTR_ERR(fp));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify magic
|
|
||||||
if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) || magic != FILE_MAGIC) {
|
|
||||||
pr_err("allowlist file invalid: %d!\n", magic);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kernel_read(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
|
||||||
pr_err("allowlist read version: %d failed\n", version);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("allowlist version: %d\n", version);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
u32 uid;
|
|
||||||
bool allow = false;
|
|
||||||
ret = kernel_read(fp, &uid, sizeof(uid), &off);
|
|
||||||
if (ret <= 0) {
|
|
||||||
pr_info("load_allow_list read err: %d\n", ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ret = kernel_read(fp, &allow, sizeof(allow), &off);
|
|
||||||
|
|
||||||
pr_info("load_allow_uid: %d, allow: %d\n", uid, allow);
|
|
||||||
|
|
||||||
ksu_allow_uid(uid, allow);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
|
|
||||||
filp_close(fp, 0);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool ksu_get_app_profile(struct app_profile *profile)
|
||||||
|
{
|
||||||
|
struct perm_data *p = NULL;
|
||||||
|
struct list_head *pos = NULL;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
list_for_each (pos, &allow_list) {
|
||||||
|
p = list_entry(pos, struct perm_data, list);
|
||||||
|
bool uid_match = profile->current_uid == p->profile.current_uid;
|
||||||
|
if (uid_match) {
|
||||||
|
// found it, override it with ours
|
||||||
|
memcpy(profile, &p->profile, sizeof(*profile));
|
||||||
|
found = true;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_work(void) {
|
static inline bool forbid_system_uid(uid_t uid) {
|
||||||
ksu_workqueue = alloc_workqueue("kernelsu_work_queue", 0, 0);
|
#define SHELL_UID 2000
|
||||||
INIT_WORK(&ksu_save_work, do_persistent_allow_list);
|
#define SYSTEM_UID 1000
|
||||||
INIT_WORK(&ksu_load_work, do_load_allow_list);
|
return uid < SHELL_UID && uid != SYSTEM_UID;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
static bool profile_valid(struct app_profile *profile)
|
||||||
|
{
|
||||||
|
if (!profile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forbid_system_uid(profile->current_uid)) {
|
||||||
|
pr_err("uid lower than 2000 is unsupported: %d\n", profile->current_uid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile->version < KSU_APP_PROFILE_VER) {
|
||||||
|
pr_info("Unsupported profile version: %d\n", profile->version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile->allow_su) {
|
||||||
|
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
|
||||||
|
{
|
||||||
|
struct perm_data *p = NULL;
|
||||||
|
struct list_head *pos = NULL;
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (!profile_valid(profile)) {
|
||||||
|
pr_err("Failed to set app profile: invalid profile!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each (pos, &allow_list) {
|
||||||
|
p = list_entry(pos, struct perm_data, list);
|
||||||
|
// both uid and package must match, otherwise it will break multiple package with different user id
|
||||||
|
if (profile->current_uid == p->profile.current_uid &&
|
||||||
|
!strcmp(profile->key, p->profile.key)) {
|
||||||
|
// found it, just override it all!
|
||||||
|
memcpy(&p->profile, profile, sizeof(*profile));
|
||||||
|
result = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found, alloc a new node!
|
||||||
|
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
|
||||||
|
if (!p) {
|
||||||
|
pr_err("ksu_set_app_profile alloc failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&p->profile, profile, sizeof(*profile));
|
||||||
|
if (profile->allow_su) {
|
||||||
|
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
|
||||||
|
profile->key, profile->current_uid,
|
||||||
|
profile->rp_config.profile.gid,
|
||||||
|
profile->rp_config.profile.selinux_domain);
|
||||||
|
} else {
|
||||||
|
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
|
||||||
|
profile->key, profile->current_uid,
|
||||||
|
profile->nrp_config.profile.umount_modules);
|
||||||
|
}
|
||||||
|
list_add_tail(&p->list, &allow_list);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (profile->current_uid <= BITMAP_UID_MAX) {
|
||||||
|
if (profile->allow_su)
|
||||||
|
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= 1 << (profile->current_uid % BITS_PER_BYTE);
|
||||||
|
else
|
||||||
|
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= ~(1 << (profile->current_uid % BITS_PER_BYTE));
|
||||||
|
} else {
|
||||||
|
if (profile->allow_su) {
|
||||||
|
/*
|
||||||
|
* 1024 apps with uid higher than BITMAP_UID_MAX
|
||||||
|
* registered to request superuser?
|
||||||
|
*/
|
||||||
|
if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) {
|
||||||
|
pr_err("too many apps registered\n");
|
||||||
|
WARN_ON(1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
allow_list_arr[allow_list_pointer++] = profile->current_uid;
|
||||||
|
} else {
|
||||||
|
remove_uid_from_arr(profile->current_uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
// check if the default profiles is changed, cache it to a single struct to accelerate access.
|
||||||
|
if (unlikely(!strcmp(profile->key, "$"))) {
|
||||||
|
// set default non root profile
|
||||||
|
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
|
||||||
|
sizeof(default_non_root_profile));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(!strcmp(profile->key, "#"))) {
|
||||||
|
// set default root profile
|
||||||
|
memcpy(&default_root_profile, &profile->rp_config.profile,
|
||||||
|
sizeof(default_root_profile));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (persist)
|
||||||
|
persistent_allow_list();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __ksu_is_allow_uid(uid_t uid)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (unlikely(uid == 0)) {
|
||||||
|
// already root, but only allow our domain.
|
||||||
|
return is_ksu_domain();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forbid_system_uid(uid)) {
|
||||||
|
// do not bother going through the list if it's system
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likely(uid <= BITMAP_UID_MAX)) {
|
||||||
|
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE)));
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < allow_list_pointer; i++) {
|
||||||
|
if (allow_list_arr[i] == uid)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ksu_uid_should_umount(uid_t uid)
|
||||||
|
{
|
||||||
|
struct app_profile profile = { .current_uid = uid };
|
||||||
|
bool found = ksu_get_app_profile(&profile);
|
||||||
|
if (!found) {
|
||||||
|
// no app profile found, it must be non root app
|
||||||
|
return default_non_root_profile.umount_modules;
|
||||||
|
}
|
||||||
|
if (profile.allow_su) {
|
||||||
|
// if found and it is granted to su, we shouldn't umount for it
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// found an app profile
|
||||||
|
if (profile.nrp_config.use_default) {
|
||||||
|
return default_non_root_profile.umount_modules;
|
||||||
|
} else {
|
||||||
|
return profile.nrp_config.profile.umount_modules;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct root_profile *ksu_get_root_profile(uid_t uid)
|
||||||
|
{
|
||||||
|
struct perm_data *p = NULL;
|
||||||
|
struct list_head *pos = NULL;
|
||||||
|
|
||||||
|
list_for_each (pos, &allow_list) {
|
||||||
|
p = list_entry(pos, struct perm_data, list);
|
||||||
|
if (uid == p->profile.current_uid && p->profile.allow_su) {
|
||||||
|
if (!p->profile.rp_config.use_default) {
|
||||||
|
return &p->profile.rp_config.profile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use default profile
|
||||||
|
return &default_root_profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ksu_get_allow_list(int *array, int *length, bool allow)
|
||||||
|
{
|
||||||
|
struct perm_data *p = NULL;
|
||||||
|
struct list_head *pos = NULL;
|
||||||
|
int i = 0;
|
||||||
|
list_for_each (pos, &allow_list) {
|
||||||
|
p = list_entry(pos, struct perm_data, list);
|
||||||
|
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
|
||||||
|
if (p->profile.allow_su == allow) {
|
||||||
|
array[i++] = p->profile.current_uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*length = i;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_save_allow_list(struct work_struct *work)
|
||||||
|
{
|
||||||
|
u32 magic = FILE_MAGIC;
|
||||||
|
u32 version = FILE_FORMAT_VERSION;
|
||||||
|
struct perm_data *p = NULL;
|
||||||
|
struct list_head *pos = NULL;
|
||||||
|
loff_t off = 0;
|
||||||
|
|
||||||
|
struct file *fp =
|
||||||
|
ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
if (IS_ERR(fp)) {
|
||||||
|
pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store magic and version
|
||||||
|
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
|
||||||
|
sizeof(magic)) {
|
||||||
|
pr_err("save_allow_list write magic failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
|
||||||
|
sizeof(version)) {
|
||||||
|
pr_err("save_allow_list write version failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each (pos, &allow_list) {
|
||||||
|
p = list_entry(pos, struct perm_data, list);
|
||||||
|
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
|
||||||
|
p->profile.key, p->profile.current_uid,
|
||||||
|
p->profile.allow_su);
|
||||||
|
|
||||||
|
ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile),
|
||||||
|
&off);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
filp_close(fp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_load_allow_list(struct work_struct *work)
|
||||||
|
{
|
||||||
|
loff_t off = 0;
|
||||||
|
ssize_t ret = 0;
|
||||||
|
struct file *fp = NULL;
|
||||||
|
u32 magic;
|
||||||
|
u32 version;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
|
// always allow adb shell by default
|
||||||
|
ksu_grant_root_to_shell();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// load allowlist now!
|
||||||
|
fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
|
||||||
|
if (IS_ERR(fp)) {
|
||||||
|
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify magic
|
||||||
|
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) !=
|
||||||
|
sizeof(magic) ||
|
||||||
|
magic != FILE_MAGIC) {
|
||||||
|
pr_err("allowlist file invalid: %d!\n", magic);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) !=
|
||||||
|
sizeof(version)) {
|
||||||
|
pr_err("allowlist read version: %d failed\n", version);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("allowlist version: %d\n", version);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
struct app_profile profile;
|
||||||
|
|
||||||
|
ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile),
|
||||||
|
&off);
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
pr_info("load_allow_list read err: %zd\n", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n",
|
||||||
|
profile.key, profile.current_uid, profile.allow_su);
|
||||||
|
ksu_set_app_profile(&profile, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
ksu_show_allow_list();
|
||||||
|
filp_close(fp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data)
|
||||||
|
{
|
||||||
|
struct perm_data *np = NULL;
|
||||||
|
struct perm_data *n = NULL;
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
// TODO: use RCU!
|
||||||
|
mutex_lock(&allowlist_mutex);
|
||||||
|
list_for_each_entry_safe (np, n, &allow_list, list) {
|
||||||
|
uid_t uid = np->profile.current_uid;
|
||||||
|
char *package = np->profile.key;
|
||||||
|
// we use this uid for special cases, don't prune it!
|
||||||
|
bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID;
|
||||||
|
if (!is_preserved_uid && !is_uid_valid(uid, package, data)) {
|
||||||
|
modified = true;
|
||||||
|
pr_info("prune uid: %d, package: %s\n", uid, package);
|
||||||
|
list_del(&np->list);
|
||||||
|
if (likely(uid <= BITMAP_UID_MAX)) {
|
||||||
|
allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE));
|
||||||
|
}
|
||||||
|
remove_uid_from_arr(uid);
|
||||||
|
smp_mb();
|
||||||
|
kfree(np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&allowlist_mutex);
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
persistent_allow_list();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure allow list works cross boot
|
// make sure allow list works cross boot
|
||||||
bool persistent_allow_list(void) {
|
bool persistent_allow_list(void)
|
||||||
queue_work(ksu_workqueue, &ksu_save_work);
|
{
|
||||||
return true;
|
return ksu_queue_work(&ksu_save_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_allowlist_init(void) {
|
bool ksu_load_allow_list(void)
|
||||||
|
{
|
||||||
INIT_LIST_HEAD(&allow_list);
|
return ksu_queue_work(&ksu_load_work);
|
||||||
|
|
||||||
init_work();
|
|
||||||
|
|
||||||
// start load allow list.
|
|
||||||
queue_work(ksu_workqueue, &ksu_load_work);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_allowlist_exit(void) {
|
void ksu_allowlist_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
destroy_workqueue(ksu_workqueue);
|
BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE);
|
||||||
|
BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE);
|
||||||
|
|
||||||
return true;
|
for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++)
|
||||||
}
|
allow_list_arr[i] = -1;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&allow_list);
|
||||||
|
|
||||||
|
INIT_WORK(&ksu_save_work, do_save_allow_list);
|
||||||
|
INIT_WORK(&ksu_load_work, do_load_allow_list);
|
||||||
|
|
||||||
|
init_default_profiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_allowlist_exit(void)
|
||||||
|
{
|
||||||
|
struct perm_data *np = NULL;
|
||||||
|
struct perm_data *n = NULL;
|
||||||
|
|
||||||
|
do_save_allow_list(NULL);
|
||||||
|
|
||||||
|
// free allowlist
|
||||||
|
mutex_lock(&allowlist_mutex);
|
||||||
|
list_for_each_entry_safe (np, n, &allow_list, list) {
|
||||||
|
list_del(&np->list);
|
||||||
|
kfree(np);
|
||||||
|
}
|
||||||
|
mutex_unlock(&allowlist_mutex);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,27 @@
|
|||||||
#ifndef __KSU_H_ALLOWLIST
|
#ifndef __KSU_H_ALLOWLIST
|
||||||
#define __KSU_H_ALLOWLIST
|
#define __KSU_H_ALLOWLIST
|
||||||
|
|
||||||
bool ksu_allowlist_init();
|
#include "linux/types.h"
|
||||||
|
#include "ksu.h"
|
||||||
|
|
||||||
bool ksu_allowlist_exit();
|
void ksu_allowlist_init(void);
|
||||||
|
|
||||||
bool ksu_is_allow_uid(uid_t uid);
|
void ksu_allowlist_exit(void);
|
||||||
|
|
||||||
bool ksu_allow_uid(uid_t uid, bool allow);
|
bool ksu_load_allow_list(void);
|
||||||
|
|
||||||
bool ksu_get_allow_list(int* array, int* length, bool allow);
|
void ksu_show_allow_list(void);
|
||||||
|
|
||||||
#endif
|
bool __ksu_is_allow_uid(uid_t uid);
|
||||||
|
#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid))
|
||||||
|
|
||||||
|
bool ksu_get_allow_list(int *array, int *length, bool allow);
|
||||||
|
|
||||||
|
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), void *data);
|
||||||
|
|
||||||
|
bool ksu_get_app_profile(struct app_profile *);
|
||||||
|
bool ksu_set_app_profile(struct app_profile *, bool persist);
|
||||||
|
|
||||||
|
bool ksu_uid_should_umount(uid_t uid);
|
||||||
|
struct root_profile *ksu_get_root_profile(uid_t uid);
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,120 +1,335 @@
|
|||||||
#include <linux/fs.h>
|
#include "linux/err.h"
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/gfp.h"
|
||||||
|
#include "linux/kernel.h"
|
||||||
|
#include "linux/moduleparam.h"
|
||||||
|
|
||||||
#include "apk_sign.h"
|
#include "apk_sign.h"
|
||||||
#include "klog.h"
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
#include "linux/slab.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
|
||||||
static int check_v2_signature(char* path, unsigned expected_size, unsigned expected_hash) {
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||||
unsigned char buffer[0x11] = {0};
|
#include "crypto/sha2.h"
|
||||||
u32 size4;
|
|
||||||
u64 size8, size_of_block;
|
|
||||||
|
|
||||||
loff_t pos;
|
|
||||||
|
|
||||||
int sign = -1;
|
|
||||||
struct file* fp = filp_open(path, O_RDONLY, 0);
|
|
||||||
if (IS_ERR(fp)) {
|
|
||||||
pr_err("open %s error.", path);
|
|
||||||
return PTR_ERR(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
sign = 1;
|
|
||||||
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
|
|
||||||
for (int i = 0;; ++i) {
|
|
||||||
unsigned short n;
|
|
||||||
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
|
|
||||||
kernel_read(fp, &n, 2, &pos);
|
|
||||||
if (n == i) {
|
|
||||||
pos -= 22;
|
|
||||||
kernel_read(fp, &size4, 4, &pos);
|
|
||||||
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == 0xffff) {
|
|
||||||
pr_info("error: cannot find eocd\n");
|
|
||||||
goto clean;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += 12;
|
|
||||||
// offset
|
|
||||||
kernel_read(fp, &size4, 0x4, &pos);
|
|
||||||
pos = size4 - 0x18;
|
|
||||||
|
|
||||||
kernel_read(fp, &size8, 0x8, &pos);
|
|
||||||
kernel_read(fp, buffer, 0x10, &pos);
|
|
||||||
if (strcmp((char *) buffer, "APK Sig Block 42")) {
|
|
||||||
goto clean;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = size4 - (size8 + 0x8);
|
|
||||||
kernel_read(fp, &size_of_block, 0x8, &pos);
|
|
||||||
if (size_of_block != size8) {
|
|
||||||
goto clean;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t offset;
|
|
||||||
kernel_read(fp, &size8, 0x8, &pos); // sequence length
|
|
||||||
if (size8 == size_of_block) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
kernel_read(fp, &id, 0x4, &pos); // id
|
|
||||||
offset = 4;
|
|
||||||
pr_info("id: 0x%08x\n", id);
|
|
||||||
if ((id ^ 0xdeadbeefu) == 0xafa439f5u || (id ^ 0xdeadbeefu) == 0x2efed62f) {
|
|
||||||
kernel_read(fp, &size4, 0x4, &pos); // signer-sequence length
|
|
||||||
kernel_read(fp, &size4, 0x4, &pos); // signer length
|
|
||||||
kernel_read(fp, &size4, 0x4, &pos); // signed data length
|
|
||||||
offset += 0x4 * 3;
|
|
||||||
|
|
||||||
kernel_read(fp, &size4, 0x4, &pos); // digests-sequence length
|
|
||||||
pos += size4;
|
|
||||||
offset += 0x4 + size4;
|
|
||||||
|
|
||||||
kernel_read(fp, &size4, 0x4, &pos); // certificates length
|
|
||||||
kernel_read(fp, &size4, 0x4, &pos); // certificate length
|
|
||||||
offset += 0x4 * 2;
|
|
||||||
#if 0
|
|
||||||
int hash = 1;
|
|
||||||
signed char c;
|
|
||||||
for (unsigned i = 0; i < size4; ++i) {
|
|
||||||
kernel_read(fp, &c, 0x1, &pos);
|
|
||||||
hash = 31 * hash + c;
|
|
||||||
}
|
|
||||||
offset += size4;
|
|
||||||
pr_info(" size: 0x%04x, hash: 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
|
|
||||||
#else
|
#else
|
||||||
if (size4 == expected_size) {
|
#include "crypto/sha.h"
|
||||||
int hash = 1;
|
|
||||||
signed char c;
|
|
||||||
for (unsigned i = 0; i < size4; ++i) {
|
|
||||||
kernel_read(fp, &c, 0x1, &pos);
|
|
||||||
hash = 31 * hash + c;
|
|
||||||
}
|
|
||||||
offset += size4;
|
|
||||||
if ((((unsigned) hash) ^ 0x14131211u) == expected_hash) {
|
|
||||||
sign = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// don't try again.
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
pos += (size8 - offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
clean:
|
struct sdesc {
|
||||||
filp_close(fp, 0);
|
struct shash_desc shash;
|
||||||
|
char ctx[];
|
||||||
|
};
|
||||||
|
|
||||||
return sign;
|
static struct sdesc *init_sdesc(struct crypto_shash *alg)
|
||||||
|
{
|
||||||
|
struct sdesc *sdesc;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
|
||||||
|
sdesc = kmalloc(size, GFP_KERNEL);
|
||||||
|
if (!sdesc)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
sdesc->shash.tfm = alg;
|
||||||
|
return sdesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EXPECTED_SIZE 0x033b
|
static int calc_hash(struct crypto_shash *alg, const unsigned char *data,
|
||||||
#define EXPECTED_HASH 0xb0b91415
|
unsigned int datalen, unsigned char *digest)
|
||||||
|
{
|
||||||
|
struct sdesc *sdesc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
int is_manager_apk(char* path) {
|
sdesc = init_sdesc(alg);
|
||||||
return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
|
if (IS_ERR(sdesc)) {
|
||||||
}
|
pr_info("can't alloc sdesc\n");
|
||||||
|
return PTR_ERR(sdesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
|
||||||
|
kfree(sdesc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ksu_sha256(const unsigned char *data, unsigned int datalen,
|
||||||
|
unsigned char *digest)
|
||||||
|
{
|
||||||
|
struct crypto_shash *alg;
|
||||||
|
char *hash_alg_name = "sha256";
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
alg = crypto_alloc_shash(hash_alg_name, 0, 0);
|
||||||
|
if (IS_ERR(alg)) {
|
||||||
|
pr_info("can't alloc alg %s\n", hash_alg_name);
|
||||||
|
return PTR_ERR(alg);
|
||||||
|
}
|
||||||
|
ret = calc_hash(alg, data, datalen, digest);
|
||||||
|
crypto_free_shash(alg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset,
|
||||||
|
unsigned expected_size, const char *expected_sha256)
|
||||||
|
{
|
||||||
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length
|
||||||
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length
|
||||||
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length
|
||||||
|
|
||||||
|
*offset += 0x4 * 3;
|
||||||
|
|
||||||
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length
|
||||||
|
|
||||||
|
*pos += *size4;
|
||||||
|
*offset += 0x4 + *size4;
|
||||||
|
|
||||||
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length
|
||||||
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length
|
||||||
|
*offset += 0x4 * 2;
|
||||||
|
|
||||||
|
if (*size4 == expected_size) {
|
||||||
|
*offset += *size4;
|
||||||
|
|
||||||
|
#define CERT_MAX_LENGTH 1024
|
||||||
|
char cert[CERT_MAX_LENGTH];
|
||||||
|
if (*size4 > CERT_MAX_LENGTH) {
|
||||||
|
pr_info("cert length overlimit\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ksu_kernel_read_compat(fp, cert, *size4, pos);
|
||||||
|
unsigned char digest[SHA256_DIGEST_SIZE];
|
||||||
|
if (IS_ERR(ksu_sha256(cert, *size4, digest))) {
|
||||||
|
pr_info("sha256 error\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char hash_str[SHA256_DIGEST_SIZE * 2 + 1];
|
||||||
|
hash_str[SHA256_DIGEST_SIZE * 2] = '\0';
|
||||||
|
|
||||||
|
bin2hex(hash_str, digest, SHA256_DIGEST_SIZE);
|
||||||
|
pr_info("sha256: %s, expected: %s\n", hash_str,
|
||||||
|
expected_sha256);
|
||||||
|
if (strcmp(expected_sha256, hash_str) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct zip_entry_header {
|
||||||
|
uint32_t signature;
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t compression;
|
||||||
|
uint16_t mod_time;
|
||||||
|
uint16_t mod_date;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t compressed_size;
|
||||||
|
uint32_t uncompressed_size;
|
||||||
|
uint16_t file_name_length;
|
||||||
|
uint16_t extra_field_length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
// This is a necessary but not sufficient condition, but it is enough for us
|
||||||
|
static bool has_v1_signature_file(struct file *fp)
|
||||||
|
{
|
||||||
|
struct zip_entry_header header;
|
||||||
|
const char MANIFEST[] = "META-INF/MANIFEST.MF";
|
||||||
|
|
||||||
|
loff_t pos = 0;
|
||||||
|
|
||||||
|
while (ksu_kernel_read_compat(fp, &header,
|
||||||
|
sizeof(struct zip_entry_header), &pos) ==
|
||||||
|
sizeof(struct zip_entry_header)) {
|
||||||
|
if (header.signature != 0x04034b50) {
|
||||||
|
// ZIP magic: 'PK'
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Read the entry file name
|
||||||
|
if (header.file_name_length == sizeof(MANIFEST) - 1) {
|
||||||
|
char fileName[sizeof(MANIFEST)];
|
||||||
|
ksu_kernel_read_compat(fp, fileName,
|
||||||
|
header.file_name_length, &pos);
|
||||||
|
fileName[header.file_name_length] = '\0';
|
||||||
|
|
||||||
|
// Check if the entry matches META-INF/MANIFEST.MF
|
||||||
|
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) ==
|
||||||
|
0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Skip the entry file name
|
||||||
|
pos += header.file_name_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip to the next entry
|
||||||
|
pos += header.extra_field_length + header.compressed_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __always_inline bool check_v2_signature(char *path,
|
||||||
|
unsigned expected_size,
|
||||||
|
const char *expected_sha256)
|
||||||
|
{
|
||||||
|
unsigned char buffer[0x11] = { 0 };
|
||||||
|
u32 size4;
|
||||||
|
u64 size8, size_of_block;
|
||||||
|
|
||||||
|
loff_t pos;
|
||||||
|
|
||||||
|
bool v2_signing_valid = false;
|
||||||
|
int v2_signing_blocks = 0;
|
||||||
|
bool v3_signing_exist = false;
|
||||||
|
bool v3_1_signing_exist = false;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
|
||||||
|
if (IS_ERR(fp)) {
|
||||||
|
pr_err("open %s error.\n", path);
|
||||||
|
return PTR_ERR(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable inotify for this file
|
||||||
|
fp->f_mode |= FMODE_NONOTIFY;
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
|
||||||
|
for (i = 0;; ++i) {
|
||||||
|
unsigned short n;
|
||||||
|
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
|
||||||
|
ksu_kernel_read_compat(fp, &n, 2, &pos);
|
||||||
|
if (n == i) {
|
||||||
|
pos -= 22;
|
||||||
|
ksu_kernel_read_compat(fp, &size4, 4, &pos);
|
||||||
|
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 0xffff) {
|
||||||
|
pr_info("error: cannot find eocd\n");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += 12;
|
||||||
|
// offset
|
||||||
|
ksu_kernel_read_compat(fp, &size4, 0x4, &pos);
|
||||||
|
pos = size4 - 0x18;
|
||||||
|
|
||||||
|
ksu_kernel_read_compat(fp, &size8, 0x8, &pos);
|
||||||
|
ksu_kernel_read_compat(fp, buffer, 0x10, &pos);
|
||||||
|
if (strcmp((char *)buffer, "APK Sig Block 42")) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = size4 - (size8 + 0x8);
|
||||||
|
ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos);
|
||||||
|
if (size_of_block != size8) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t offset;
|
||||||
|
ksu_kernel_read_compat(fp, &size8, 0x8,
|
||||||
|
&pos); // sequence length
|
||||||
|
if (size8 == size_of_block) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id
|
||||||
|
offset = 4;
|
||||||
|
pr_info("id: 0x%08x\n", id);
|
||||||
|
if (id == 0x7109871au) {
|
||||||
|
v2_signing_blocks++;
|
||||||
|
v2_signing_valid =
|
||||||
|
check_block(fp, &size4, &pos, &offset,
|
||||||
|
expected_size, expected_sha256);
|
||||||
|
} else if (id == 0xf05368c0u) {
|
||||||
|
// http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#73
|
||||||
|
v3_signing_exist = true;
|
||||||
|
} else if (id == 0x1b93ad61u) {
|
||||||
|
// http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#74
|
||||||
|
v3_1_signing_exist = true;
|
||||||
|
}
|
||||||
|
pos += (size8 - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v2_signing_blocks != 1) {
|
||||||
|
pr_err("Unexpected v2 signature count: %d\n",
|
||||||
|
v2_signing_blocks);
|
||||||
|
v2_signing_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v2_signing_valid) {
|
||||||
|
int has_v1_signing = has_v1_signature_file(fp);
|
||||||
|
if (has_v1_signing) {
|
||||||
|
pr_err("Unexpected v1 signature scheme found!\n");
|
||||||
|
filp_close(fp, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clean:
|
||||||
|
filp_close(fp, 0);
|
||||||
|
|
||||||
|
if (v3_signing_exist || v3_1_signing_exist) {
|
||||||
|
pr_err("Unexpected v3 signature scheme found!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v2_signing_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
|
|
||||||
|
unsigned ksu_expected_size = EXPECTED_SIZE;
|
||||||
|
const char *ksu_expected_hash = EXPECTED_HASH;
|
||||||
|
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
|
static int set_expected_size(const char *val, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
int rv = param_set_uint(val, kp);
|
||||||
|
ksu_invalidate_manager_uid();
|
||||||
|
pr_info("ksu_expected_size set to %x\n", ksu_expected_size);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_expected_hash(const char *val, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
pr_info("set_expected_hash: %s\n", val);
|
||||||
|
int rv = param_set_charp(val, kp);
|
||||||
|
ksu_invalidate_manager_uid();
|
||||||
|
pr_info("ksu_expected_hash set to %s\n", ksu_expected_hash);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kernel_param_ops expected_size_ops = {
|
||||||
|
.set = set_expected_size,
|
||||||
|
.get = param_get_uint,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kernel_param_ops expected_hash_ops = {
|
||||||
|
.set = set_expected_hash,
|
||||||
|
.get = param_get_charp,
|
||||||
|
.free = param_free_charp,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_param_cb(ksu_expected_size, &expected_size_ops, &ksu_expected_size,
|
||||||
|
S_IRUSR | S_IWUSR);
|
||||||
|
module_param_cb(ksu_expected_hash, &expected_hash_ops, &ksu_expected_hash,
|
||||||
|
S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
|
bool is_manager_apk(char *path)
|
||||||
|
{
|
||||||
|
return check_v2_signature(path, ksu_expected_size, ksu_expected_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
bool is_manager_apk(char *path)
|
||||||
|
{
|
||||||
|
return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#ifndef __KSU_H_APK_V2_SIGN
|
#ifndef __KSU_H_APK_V2_SIGN
|
||||||
#define __KSU_H_APK_V2_SIGN
|
#define __KSU_H_APK_V2_SIGN
|
||||||
|
|
||||||
// return 0 if signature match
|
#include "linux/types.h"
|
||||||
int is_manager_apk(char* path);
|
|
||||||
|
|
||||||
#endif
|
bool is_manager_apk(char *path);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,21 +1,28 @@
|
|||||||
#ifndef __KSU_H_ARCH
|
#ifndef __KSU_H_ARCH
|
||||||
#define __KSU_H_ARCH
|
#define __KSU_H_ARCH
|
||||||
|
|
||||||
|
#include "linux/version.h"
|
||||||
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
|
|
||||||
#define __PT_PARM1_REG regs[0]
|
#define __PT_PARM1_REG regs[0]
|
||||||
#define __PT_PARM2_REG regs[1]
|
#define __PT_PARM2_REG regs[1]
|
||||||
#define __PT_PARM3_REG regs[2]
|
#define __PT_PARM3_REG regs[2]
|
||||||
#define __PT_PARM4_REG regs[3]
|
#define __PT_SYSCALL_PARM4_REG regs[3]
|
||||||
|
#define __PT_CCALL_PARM4_REG regs[3]
|
||||||
#define __PT_PARM5_REG regs[4]
|
#define __PT_PARM5_REG regs[4]
|
||||||
|
#define __PT_PARM6_REG regs[5]
|
||||||
#define __PT_RET_REG regs[30]
|
#define __PT_RET_REG regs[30]
|
||||||
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
|
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
|
||||||
#define __PT_RC_REG regs[0]
|
#define __PT_RC_REG regs[0]
|
||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG pc
|
#define __PT_IP_REG pc
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
#define PRCTL_SYMBOL "__arm64_sys_prctl"
|
#define PRCTL_SYMBOL "__arm64_sys_prctl"
|
||||||
|
#else
|
||||||
|
#define PRCTL_SYMBOL "sys_prctl"
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
|
|
||||||
@@ -23,16 +30,20 @@
|
|||||||
#define __PT_PARM2_REG si
|
#define __PT_PARM2_REG si
|
||||||
#define __PT_PARM3_REG dx
|
#define __PT_PARM3_REG dx
|
||||||
/* syscall uses r10 for PARM4 */
|
/* syscall uses r10 for PARM4 */
|
||||||
#define __PT_PARM4_REG r10
|
#define __PT_SYSCALL_PARM4_REG r10
|
||||||
// #define __PT_PARM4_REG cx
|
#define __PT_CCALL_PARM4_REG cx
|
||||||
#define __PT_PARM5_REG r8
|
#define __PT_PARM5_REG r8
|
||||||
|
#define __PT_PARM6_REG r9
|
||||||
#define __PT_RET_REG sp
|
#define __PT_RET_REG sp
|
||||||
#define __PT_FP_REG bp
|
#define __PT_FP_REG bp
|
||||||
#define __PT_RC_REG ax
|
#define __PT_RC_REG ax
|
||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG ip
|
#define __PT_IP_REG ip
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
#define PRCTL_SYMBOL "__x64_sys_prctl"
|
#define PRCTL_SYMBOL "__x64_sys_prctl"
|
||||||
|
#else
|
||||||
|
#define PRCTL_SYMBOL "sys_prctl"
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "Unsupported arch"
|
#error "Unsupported arch"
|
||||||
@@ -46,13 +57,14 @@
|
|||||||
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
|
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
|
||||||
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
|
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
|
||||||
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
|
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
|
||||||
#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)
|
#define PT_REGS_SYSCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_SYSCALL_PARM4_REG)
|
||||||
|
#define PT_REGS_CCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_CCALL_PARM4_REG)
|
||||||
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
|
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
|
||||||
|
#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG)
|
||||||
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)
|
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)
|
||||||
#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)
|
#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)
|
||||||
#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)
|
#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)
|
||||||
#define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG)
|
#define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG)
|
||||||
#define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG)
|
#define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG)
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif
|
|
||||||
|
|||||||
742
kernel/core_hook.c
Normal file
742
kernel/core_hook.c
Normal file
@@ -0,0 +1,742 @@
|
|||||||
|
#include "linux/capability.h"
|
||||||
|
#include "linux/cred.h"
|
||||||
|
#include "linux/dcache.h"
|
||||||
|
#include "linux/err.h"
|
||||||
|
#include "linux/init.h"
|
||||||
|
#include "linux/init_task.h"
|
||||||
|
#include "linux/kernel.h"
|
||||||
|
#include "linux/kprobes.h"
|
||||||
|
#include "linux/lsm_hooks.h"
|
||||||
|
#include "linux/nsproxy.h"
|
||||||
|
#include "linux/path.h"
|
||||||
|
#include "linux/printk.h"
|
||||||
|
#include "linux/uaccess.h"
|
||||||
|
#include "linux/uidgid.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
#include "linux/mount.h"
|
||||||
|
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/namei.h"
|
||||||
|
#include "linux/rcupdate.h"
|
||||||
|
|
||||||
|
#include "allowlist.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "core_hook.h"
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "ksu.h"
|
||||||
|
#include "ksud.h"
|
||||||
|
#include "manager.h"
|
||||||
|
#include "selinux/selinux.h"
|
||||||
|
#include "uid_observer.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
|
static bool ksu_module_mounted = false;
|
||||||
|
|
||||||
|
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
|
||||||
|
|
||||||
|
static inline bool is_allow_su()
|
||||||
|
{
|
||||||
|
if (is_manager()) {
|
||||||
|
// we are manager, allow!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return ksu_is_allow_uid(current_uid().val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_isolated_uid(uid_t uid)
|
||||||
|
{
|
||||||
|
#define FIRST_ISOLATED_UID 99000
|
||||||
|
#define LAST_ISOLATED_UID 99999
|
||||||
|
#define FIRST_APP_ZYGOTE_ISOLATED_UID 90000
|
||||||
|
#define LAST_APP_ZYGOTE_ISOLATED_UID 98999
|
||||||
|
uid_t appid = uid % 100000;
|
||||||
|
return (appid >= FIRST_ISOLATED_UID && appid <= LAST_ISOLATED_UID) ||
|
||||||
|
(appid >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
|
||||||
|
appid <= LAST_APP_ZYGOTE_ISOLATED_UID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct group_info root_groups = { .usage = ATOMIC_INIT(2) };
|
||||||
|
|
||||||
|
static void setup_groups(struct root_profile *profile, struct cred *cred)
|
||||||
|
{
|
||||||
|
if (profile->groups_count > KSU_MAX_GROUPS) {
|
||||||
|
pr_warn("Failed to setgroups, too large group: %d!\n",
|
||||||
|
profile->uid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile->groups_count == 1 && profile->groups[0] == 0) {
|
||||||
|
// setgroup to root and return early.
|
||||||
|
if (cred->group_info)
|
||||||
|
put_group_info(cred->group_info);
|
||||||
|
cred->group_info = get_group_info(&root_groups);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ngroups = profile->groups_count;
|
||||||
|
struct group_info *group_info = groups_alloc(ngroups);
|
||||||
|
if (!group_info) {
|
||||||
|
pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ngroups; i++) {
|
||||||
|
gid_t gid = profile->groups[i];
|
||||||
|
kgid_t kgid = make_kgid(current_user_ns(), gid);
|
||||||
|
if (!gid_valid(kgid)) {
|
||||||
|
pr_warn("Failed to setgroups, invalid gid: %d\n", gid);
|
||||||
|
put_group_info(group_info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
||||||
|
group_info->gid[i] = kgid;
|
||||||
|
#else
|
||||||
|
GROUP_AT(group_info, i) = kgid;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
groups_sort(group_info);
|
||||||
|
set_groups(cred, group_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void escape_to_root(void)
|
||||||
|
{
|
||||||
|
struct cred *cred;
|
||||||
|
|
||||||
|
cred = (struct cred *)__task_cred(current);
|
||||||
|
|
||||||
|
if (cred->euid.val == 0) {
|
||||||
|
pr_warn("Already root, don't escape!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
|
||||||
|
|
||||||
|
cred->uid.val = profile->uid;
|
||||||
|
cred->suid.val = profile->uid;
|
||||||
|
cred->euid.val = profile->uid;
|
||||||
|
cred->fsuid.val = profile->uid;
|
||||||
|
|
||||||
|
cred->gid.val = profile->gid;
|
||||||
|
cred->fsgid.val = profile->gid;
|
||||||
|
cred->sgid.val = profile->gid;
|
||||||
|
cred->egid.val = profile->gid;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
|
||||||
|
sizeof(kernel_cap_t));
|
||||||
|
|
||||||
|
// setup capabilities
|
||||||
|
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
|
||||||
|
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
|
||||||
|
u64 cap_for_ksud =
|
||||||
|
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
||||||
|
memcpy(&cred->cap_effective, &cap_for_ksud,
|
||||||
|
sizeof(cred->cap_effective));
|
||||||
|
memcpy(&cred->cap_inheritable, &profile->capabilities.effective,
|
||||||
|
sizeof(cred->cap_inheritable));
|
||||||
|
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
|
||||||
|
sizeof(cred->cap_permitted));
|
||||||
|
memcpy(&cred->cap_bset, &profile->capabilities.effective,
|
||||||
|
sizeof(cred->cap_bset));
|
||||||
|
memcpy(&cred->cap_ambient, &profile->capabilities.effective,
|
||||||
|
sizeof(cred->cap_ambient));
|
||||||
|
|
||||||
|
// disable seccomp
|
||||||
|
#if defined(CONFIG_GENERIC_ENTRY) && \
|
||||||
|
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
||||||
|
current_thread_info()->syscall_work &= ~SYSCALL_WORK_SECCOMP;
|
||||||
|
#else
|
||||||
|
current_thread_info()->flags &= ~(TIF_SECCOMP | _TIF_SECCOMP);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SECCOMP
|
||||||
|
current->seccomp.mode = 0;
|
||||||
|
current->seccomp.filter = NULL;
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setup_groups(profile, cred);
|
||||||
|
|
||||||
|
setup_selinux(profile->selinux_domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
|
||||||
|
{
|
||||||
|
if (!current->mm) {
|
||||||
|
// skip kernel threads
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_uid().val != 1000) {
|
||||||
|
// skip non system uid
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!old_dentry || !new_dentry) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /data/system/packages.list.tmp -> /data/system/packages.list
|
||||||
|
if (strcmp(new_dentry->d_iname, "packages.list")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char path[128];
|
||||||
|
char *buf = dentry_path_raw(new_dentry, path, sizeof(path));
|
||||||
|
if (IS_ERR(buf)) {
|
||||||
|
pr_err("dentry_path_raw failed.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(buf, "/system/packages.list")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname,
|
||||||
|
new_dentry->d_iname, buf);
|
||||||
|
|
||||||
|
update_uid();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||||
|
unsigned long arg4, unsigned long arg5)
|
||||||
|
{
|
||||||
|
// if success, we modify the arg5 as result!
|
||||||
|
u32 *result = (u32 *)arg5;
|
||||||
|
u32 reply_ok = KERNEL_SU_OPTION;
|
||||||
|
|
||||||
|
if (KERNEL_SU_OPTION != option) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// always ignore isolated app uid
|
||||||
|
if (is_isolated_uid(current_uid().val)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uid_t last_failed_uid = -1;
|
||||||
|
if (last_failed_uid == current_uid().val) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
|
||||||
|
|
||||||
|
if (arg2 == CMD_BECOME_MANAGER) {
|
||||||
|
// quick check
|
||||||
|
if (is_manager()) {
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("become_manager: prctl reply error\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ksu_is_manager_uid_valid()) {
|
||||||
|
pr_info("manager already exist: %d\n",
|
||||||
|
ksu_get_manager_uid());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// someone wants to be root manager, just check it!
|
||||||
|
// arg3 should be `/data/user/<userId>/<manager_package_name>`
|
||||||
|
char param[128];
|
||||||
|
if (ksu_strncpy_from_user_nofault(param, arg3, sizeof(param)) ==
|
||||||
|
-EFAULT) {
|
||||||
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
|
pr_err("become_manager: copy param err\n");
|
||||||
|
#endif
|
||||||
|
goto block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for user 0, it is /data/data
|
||||||
|
// for user 999, it is /data/user/999
|
||||||
|
const char *prefix;
|
||||||
|
char prefixTmp[64];
|
||||||
|
int userId = current_uid().val / 100000;
|
||||||
|
if (userId == 0) {
|
||||||
|
prefix = "/data/data";
|
||||||
|
} else {
|
||||||
|
snprintf(prefixTmp, sizeof(prefixTmp), "/data/user/%d",
|
||||||
|
userId);
|
||||||
|
prefix = prefixTmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startswith(param, (char *)prefix) != 0) {
|
||||||
|
pr_info("become_manager: invalid param: %s\n", param);
|
||||||
|
goto block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stat the param, app must have permission to do this
|
||||||
|
// otherwise it may fake the path!
|
||||||
|
struct path path;
|
||||||
|
if (kern_path(param, LOOKUP_DIRECTORY, &path)) {
|
||||||
|
pr_err("become_manager: kern_path err\n");
|
||||||
|
goto block;
|
||||||
|
}
|
||||||
|
uid_t inode_uid = path.dentry->d_inode->i_uid.val;
|
||||||
|
path_put(&path);
|
||||||
|
if (inode_uid != current_uid().val) {
|
||||||
|
pr_err("become_manager: path uid != current uid\n");
|
||||||
|
goto block;
|
||||||
|
}
|
||||||
|
char *pkg = param + strlen(prefix);
|
||||||
|
pr_info("become_manager: param pkg: %s\n", pkg);
|
||||||
|
|
||||||
|
bool success = become_manager(pkg);
|
||||||
|
if (success) {
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("become_manager: prctl reply error\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
block:
|
||||||
|
last_failed_uid = current_uid().val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 == CMD_GRANT_ROOT) {
|
||||||
|
if (is_allow_su()) {
|
||||||
|
pr_info("allow root for: %d\n", current_uid().val);
|
||||||
|
escape_to_root();
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("grant_root: prctl reply error\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both root manager and root processes should be allowed to get version
|
||||||
|
if (arg2 == CMD_GET_VERSION) {
|
||||||
|
if (is_manager() || 0 == current_uid().val) {
|
||||||
|
u32 version = KERNEL_SU_VERSION;
|
||||||
|
if (copy_to_user(arg3, &version, sizeof(version))) {
|
||||||
|
pr_err("prctl reply error, cmd: %lu\n", arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 == CMD_REPORT_EVENT) {
|
||||||
|
if (0 != current_uid().val) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
switch (arg3) {
|
||||||
|
case EVENT_POST_FS_DATA: {
|
||||||
|
static bool post_fs_data_lock = false;
|
||||||
|
if (!post_fs_data_lock) {
|
||||||
|
post_fs_data_lock = true;
|
||||||
|
pr_info("post-fs-data triggered\n");
|
||||||
|
on_post_fs_data();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVENT_BOOT_COMPLETED: {
|
||||||
|
static bool boot_complete_lock = false;
|
||||||
|
if (!boot_complete_lock) {
|
||||||
|
boot_complete_lock = true;
|
||||||
|
pr_info("boot_complete triggered\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVENT_MODULE_MOUNTED: {
|
||||||
|
ksu_module_mounted = true;
|
||||||
|
pr_info("module mounted!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 == CMD_SET_SEPOLICY) {
|
||||||
|
if (0 != current_uid().val) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!handle_sepolicy(arg3, arg4)) {
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("sepolicy: prctl reply error\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 == CMD_CHECK_SAFEMODE) {
|
||||||
|
if (!is_manager() && 0 != current_uid().val) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ksu_is_safe_mode()) {
|
||||||
|
pr_warn("safemode enabled!\n");
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("safemode: prctl reply error\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) {
|
||||||
|
if (is_manager() || 0 == current_uid().val) {
|
||||||
|
u32 array[128];
|
||||||
|
u32 array_length;
|
||||||
|
bool success =
|
||||||
|
ksu_get_allow_list(array, &array_length,
|
||||||
|
arg2 == CMD_GET_ALLOW_LIST);
|
||||||
|
if (success) {
|
||||||
|
if (!copy_to_user(arg4, &array_length,
|
||||||
|
sizeof(array_length)) &&
|
||||||
|
!copy_to_user(arg3, array,
|
||||||
|
sizeof(u32) * array_length)) {
|
||||||
|
if (copy_to_user(result, &reply_ok,
|
||||||
|
sizeof(reply_ok))) {
|
||||||
|
pr_err("prctl reply error, cmd: %lu\n",
|
||||||
|
arg2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr_err("prctl copy allowlist error\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 == CMD_UID_GRANTED_ROOT || arg2 == CMD_UID_SHOULD_UMOUNT) {
|
||||||
|
if (is_manager() || 0 == current_uid().val) {
|
||||||
|
uid_t target_uid = (uid_t)arg3;
|
||||||
|
bool allow = false;
|
||||||
|
if (arg2 == CMD_UID_GRANTED_ROOT) {
|
||||||
|
allow = ksu_is_allow_uid(target_uid);
|
||||||
|
} else if (arg2 == CMD_UID_SHOULD_UMOUNT) {
|
||||||
|
allow = ksu_uid_should_umount(target_uid);
|
||||||
|
} else {
|
||||||
|
pr_err("unknown cmd: %lu\n", arg2);
|
||||||
|
}
|
||||||
|
if (!copy_to_user(arg4, &allow, sizeof(allow))) {
|
||||||
|
if (copy_to_user(result, &reply_ok,
|
||||||
|
sizeof(reply_ok))) {
|
||||||
|
pr_err("prctl reply error, cmd: %lu\n",
|
||||||
|
arg2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr_err("prctl copy err, cmd: %lu\n", arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all other cmds are for 'root manager'
|
||||||
|
if (!is_manager()) {
|
||||||
|
last_failed_uid = current_uid().val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are already manager
|
||||||
|
if (arg2 == CMD_GET_APP_PROFILE) {
|
||||||
|
struct app_profile profile;
|
||||||
|
if (copy_from_user(&profile, arg3, sizeof(profile))) {
|
||||||
|
pr_err("copy profile failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = ksu_get_app_profile(&profile);
|
||||||
|
if (success) {
|
||||||
|
if (copy_to_user(arg3, &profile, sizeof(profile))) {
|
||||||
|
pr_err("copy profile failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("prctl reply error, cmd: %lu\n", arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 == CMD_SET_APP_PROFILE) {
|
||||||
|
struct app_profile profile;
|
||||||
|
if (copy_from_user(&profile, arg3, sizeof(profile))) {
|
||||||
|
pr_err("copy profile failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: validate the params
|
||||||
|
if (ksu_set_app_profile(&profile, true)) {
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("prctl reply error, cmd: %lu\n", arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_appuid(kuid_t uid)
|
||||||
|
{
|
||||||
|
#define PER_USER_RANGE 100000
|
||||||
|
#define FIRST_APPLICATION_UID 10000
|
||||||
|
#define LAST_APPLICATION_UID 19999
|
||||||
|
|
||||||
|
uid_t appid = uid.val % PER_USER_RANGE;
|
||||||
|
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool should_umount(struct path *path)
|
||||||
|
{
|
||||||
|
if (!path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
|
||||||
|
pr_info("ignore global mnt namespace process: %d\n",
|
||||||
|
current_uid().val);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
|
||||||
|
const char *fstype = path->mnt->mnt_sb->s_type->name;
|
||||||
|
return strcmp(fstype, "overlay") == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ksu_umount_mnt(struct path *path, int flags)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
|
||||||
|
int err = path_umount(path, flags);
|
||||||
|
if (err) {
|
||||||
|
pr_info("umount %s failed: %d\n", path->dentry->d_iname, err);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// TODO: umount for non GKI kernel
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void try_umount(const char *mnt, bool check_mnt, int flags)
|
||||||
|
{
|
||||||
|
struct path path;
|
||||||
|
int err = kern_path(mnt, 0, &path);
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.dentry != path.mnt->mnt_root) {
|
||||||
|
// it is not root mountpoint, maybe umounted by others already.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are only interest in some specific mounts
|
||||||
|
if (check_mnt && !should_umount(&path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksu_umount_mnt(&path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_handle_setuid(struct cred *new, const struct cred *old)
|
||||||
|
{
|
||||||
|
// this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
|
||||||
|
if (!ksu_module_mounted) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new || !old) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kuid_t new_uid = new->uid;
|
||||||
|
kuid_t old_uid = old->uid;
|
||||||
|
|
||||||
|
if (0 != old_uid.val) {
|
||||||
|
// old process is not root, ignore it.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_appuid(new_uid) || is_isolated_uid(new_uid.val)) {
|
||||||
|
// pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ksu_is_allow_uid(new_uid.val)) {
|
||||||
|
// pr_info("handle setuid ignore allowed application: %d\n", new_uid.val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ksu_uid_should_umount(new_uid.val)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
|
pr_info("uid: %d should not umount!\n", current_uid().val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// check old process's selinux context, if it is not zygote, ignore it!
|
||||||
|
// because some su apps may setuid to untrusted_app but they are in global mount namespace
|
||||||
|
// when we umount for such process, that is a disaster!
|
||||||
|
bool is_zygote_child = is_zygote(old->security);
|
||||||
|
if (!is_zygote_child) {
|
||||||
|
pr_info("handle umount ignore non zygote child: %d\n",
|
||||||
|
current->pid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// umount the target mnt
|
||||||
|
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val,
|
||||||
|
current->pid);
|
||||||
|
|
||||||
|
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
|
||||||
|
// filter the mountpoint whose target is `/data/adb`
|
||||||
|
try_umount("/system", true, 0);
|
||||||
|
try_umount("/vendor", true, 0);
|
||||||
|
try_umount("/product", true, 0);
|
||||||
|
try_umount("/data/adb/modules", false, MNT_DETACH);
|
||||||
|
|
||||||
|
// try umount ksu temp path
|
||||||
|
try_umount("/debug_ramdisk", false, MNT_DETACH);
|
||||||
|
try_umount("/sbin", false, MNT_DETACH);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init functons
|
||||||
|
|
||||||
|
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
|
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
|
||||||
|
#else
|
||||||
|
struct pt_regs *real_regs = regs;
|
||||||
|
#endif
|
||||||
|
int option = (int)PT_REGS_PARM1(real_regs);
|
||||||
|
unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs);
|
||||||
|
unsigned long arg3 = (unsigned long)PT_REGS_PARM3(real_regs);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||||
|
// PRCTL_SYMBOL is the arch-specificed one, which receive raw pt_regs from syscall
|
||||||
|
unsigned long arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs);
|
||||||
|
#else
|
||||||
|
// PRCTL_SYMBOL is the common one, called by C convention in do_syscall_64
|
||||||
|
// https://elixir.bootlin.com/linux/v4.15.18/source/arch/x86/entry/common.c#L287
|
||||||
|
unsigned long arg4 = (unsigned long)PT_REGS_CCALL_PARM4(real_regs);
|
||||||
|
#endif
|
||||||
|
unsigned long arg5 = (unsigned long)PT_REGS_PARM5(real_regs);
|
||||||
|
|
||||||
|
return ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kprobe prctl_kp = {
|
||||||
|
.symbol_name = PRCTL_SYMBOL,
|
||||||
|
.pre_handler = handler_pre,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int renameat_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
|
||||||
|
// https://elixir.bootlin.com/linux/v5.12-rc1/source/include/linux/fs.h
|
||||||
|
struct renamedata *rd = PT_REGS_PARM1(regs);
|
||||||
|
struct dentry *old_entry = rd->old_dentry;
|
||||||
|
struct dentry *new_entry = rd->new_dentry;
|
||||||
|
#else
|
||||||
|
struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs);
|
||||||
|
struct dentry *new_entry = (struct dentry *)PT_REGS_CCALL_PARM4(regs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ksu_handle_rename(old_entry, new_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kprobe renameat_kp = {
|
||||||
|
.symbol_name = "vfs_rename",
|
||||||
|
.pre_handler = renameat_handler_pre,
|
||||||
|
};
|
||||||
|
|
||||||
|
__maybe_unused int ksu_kprobe_init(void)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
rc = register_kprobe(&prctl_kp);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
pr_info("prctl kprobe failed: %d.\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = register_kprobe(&renameat_kp);
|
||||||
|
pr_info("renameat kp: %d\n", rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
__maybe_unused int ksu_kprobe_exit(void)
|
||||||
|
{
|
||||||
|
unregister_kprobe(&prctl_kp);
|
||||||
|
unregister_kprobe(&renameat_kp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||||
|
unsigned long arg4, unsigned long arg5)
|
||||||
|
{
|
||||||
|
ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
// kernel 4.4 and 4.9
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
|
||||||
|
static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred,
|
||||||
|
unsigned perm)
|
||||||
|
{
|
||||||
|
if (init_session_keyring != NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (strcmp(current->comm, "init")) {
|
||||||
|
// we are only interested in `init` process
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
init_session_keyring = cred->session_keyring;
|
||||||
|
pr_info("kernel_compat: got init_session_keyring\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
|
||||||
|
struct inode *new_inode, struct dentry *new_dentry)
|
||||||
|
{
|
||||||
|
return ksu_handle_rename(old_dentry, new_dentry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ksu_task_fix_setuid(struct cred *new, const struct cred *old,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
return ksu_handle_setuid(new, old);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct security_hook_list ksu_hooks[] = {
|
||||||
|
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
|
||||||
|
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
|
||||||
|
LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid),
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
|
||||||
|
LSM_HOOK_INIT(key_permission, ksu_key_permission)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init ksu_lsm_hook_init(void)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
|
security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), "ksu");
|
||||||
|
#else
|
||||||
|
// https://elixir.bootlin.com/linux/v4.10.17/source/include/linux/lsm_hooks.h#L1892
|
||||||
|
security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init ksu_core_init(void)
|
||||||
|
{
|
||||||
|
#ifndef MODULE
|
||||||
|
pr_info("ksu_lsm_hook_init\n");
|
||||||
|
ksu_lsm_hook_init();
|
||||||
|
#else
|
||||||
|
pr_info("ksu_kprobe_init\n");
|
||||||
|
ksu_kprobe_init();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_core_exit(void)
|
||||||
|
{
|
||||||
|
#ifndef MODULE
|
||||||
|
pr_info("ksu_kprobe_exit\n");
|
||||||
|
ksu_kprobe_exit();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
9
kernel/core_hook.h
Normal file
9
kernel/core_hook.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef __KSU_H_KSU_CORE
|
||||||
|
#define __KSU_H_KSU_CORE
|
||||||
|
|
||||||
|
#include "linux/init.h"
|
||||||
|
|
||||||
|
void __init ksu_core_init(void);
|
||||||
|
void ksu_core_exit(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
5
kernel/embed_ksud.c
Normal file
5
kernel/embed_ksud.c
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// WARNING: THIS IS A STUB FILE
|
||||||
|
// This file will be regenerated by CI
|
||||||
|
|
||||||
|
unsigned int ksud_size = 0;
|
||||||
|
const char ksud[0] = {};
|
||||||
2
kernel/export_symbol.txt
Normal file
2
kernel/export_symbol.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
register_kprobe
|
||||||
|
unregister_kprobe
|
||||||
28
kernel/include/ksu_hook.h
Normal file
28
kernel/include/ksu_hook.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef __KSU_H_KSHOOK
|
||||||
|
#define __KSU_H_KSHOOK
|
||||||
|
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
|
||||||
|
// For sucompat
|
||||||
|
|
||||||
|
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||||
|
int *flags);
|
||||||
|
|
||||||
|
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
||||||
|
|
||||||
|
// For ksud
|
||||||
|
|
||||||
|
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||||
|
size_t *count_ptr, loff_t **pos);
|
||||||
|
|
||||||
|
// For ksud and sucompat
|
||||||
|
|
||||||
|
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||||
|
void *envp, int *flags);
|
||||||
|
|
||||||
|
// For volume button
|
||||||
|
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||||
|
int *value);
|
||||||
|
|
||||||
|
#endif
|
||||||
178
kernel/kernel_compat.c
Normal file
178
kernel/kernel_compat.c
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
#include "linux/version.h"
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/nsproxy.h"
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
|
||||||
|
#include "linux/sched/task.h"
|
||||||
|
#include "linux/uaccess.h"
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
|
||||||
|
#include "linux/uaccess.h"
|
||||||
|
#include "linux/sched.h"
|
||||||
|
#else
|
||||||
|
#include "linux/sched.h"
|
||||||
|
#endif
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
|
||||||
|
#include "linux/key.h"
|
||||||
|
#include "linux/errno.h"
|
||||||
|
#include "linux/cred.h"
|
||||||
|
struct key *init_session_keyring = NULL;
|
||||||
|
|
||||||
|
static inline int install_session_keyring(struct key *keyring)
|
||||||
|
{
|
||||||
|
struct cred *new;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
new = prepare_creds();
|
||||||
|
if (!new)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = install_session_keyring_to_cred(new, keyring);
|
||||||
|
if (ret < 0) {
|
||||||
|
abort_creds(new);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return commit_creds(new);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern struct task_struct init_task;
|
||||||
|
|
||||||
|
// mnt_ns context switch for environment that android_init->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns, such as WSA
|
||||||
|
struct ksu_ns_fs_saved {
|
||||||
|
struct nsproxy *ns;
|
||||||
|
struct fs_struct *fs;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ksu_save_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
|
||||||
|
{
|
||||||
|
ns_fs_saved->ns = current->nsproxy;
|
||||||
|
ns_fs_saved->fs = current->fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ksu_load_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
|
||||||
|
{
|
||||||
|
current->nsproxy = ns_fs_saved->ns;
|
||||||
|
current->fs = ns_fs_saved->fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool android_context_saved_checked = false;
|
||||||
|
static bool android_context_saved_enabled = false;
|
||||||
|
static struct ksu_ns_fs_saved android_context_saved;
|
||||||
|
|
||||||
|
void ksu_android_ns_fs_check()
|
||||||
|
{
|
||||||
|
if (android_context_saved_checked)
|
||||||
|
return;
|
||||||
|
android_context_saved_checked = true;
|
||||||
|
task_lock(current);
|
||||||
|
if (current->nsproxy && current->fs &&
|
||||||
|
current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) {
|
||||||
|
android_context_saved_enabled = true;
|
||||||
|
pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n",
|
||||||
|
current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns);
|
||||||
|
ksu_save_ns_fs(&android_context_saved);
|
||||||
|
} else {
|
||||||
|
pr_info("android context saved disabled\n");
|
||||||
|
}
|
||||||
|
task_unlock(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
|
||||||
|
if (init_session_keyring != NULL && !current_cred()->session_keyring &&
|
||||||
|
(current->flags & PF_WQ_WORKER)) {
|
||||||
|
pr_info("installing init session keyring for older kernel\n");
|
||||||
|
install_session_keyring(init_session_keyring);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns
|
||||||
|
struct ksu_ns_fs_saved saved;
|
||||||
|
if (android_context_saved_enabled) {
|
||||||
|
pr_info("start switch current nsproxy and fs to android context\n");
|
||||||
|
task_lock(current);
|
||||||
|
ksu_save_ns_fs(&saved);
|
||||||
|
ksu_load_ns_fs(&android_context_saved);
|
||||||
|
task_unlock(current);
|
||||||
|
}
|
||||||
|
struct file *fp = filp_open(filename, flags, mode);
|
||||||
|
if (android_context_saved_enabled) {
|
||||||
|
task_lock(current);
|
||||||
|
ksu_load_ns_fs(&saved);
|
||||||
|
task_unlock(current);
|
||||||
|
pr_info("switch current nsproxy and fs back to saved successfully\n");
|
||||||
|
}
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
|
||||||
|
loff_t *pos)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||||
|
return kernel_read(p, buf, count, pos);
|
||||||
|
#else
|
||||||
|
loff_t offset = pos ? *pos : 0;
|
||||||
|
ssize_t result = kernel_read(p, offset, (char *)buf, count);
|
||||||
|
if (pos && result > 0) {
|
||||||
|
*pos = offset + result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count,
|
||||||
|
loff_t *pos)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
||||||
|
return kernel_write(p, buf, count, pos);
|
||||||
|
#else
|
||||||
|
loff_t offset = pos ? *pos : 0;
|
||||||
|
ssize_t result = kernel_write(p, buf, count, offset);
|
||||||
|
if (pos && result > 0) {
|
||||||
|
*pos = offset + result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||||
|
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||||
|
long count)
|
||||||
|
{
|
||||||
|
return strncpy_from_user_nofault(dst, unsafe_addr, count);
|
||||||
|
}
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
|
||||||
|
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||||
|
long count)
|
||||||
|
{
|
||||||
|
return strncpy_from_unsafe_user(dst, unsafe_addr, count);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Copied from: https://elixir.bootlin.com/linux/v4.9.337/source/mm/maccess.c#L201
|
||||||
|
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||||
|
long count)
|
||||||
|
{
|
||||||
|
mm_segment_t old_fs = get_fs();
|
||||||
|
long ret;
|
||||||
|
|
||||||
|
if (unlikely(count <= 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
set_fs(USER_DS);
|
||||||
|
pagefault_disable();
|
||||||
|
ret = strncpy_from_user(dst, unsafe_addr, count);
|
||||||
|
pagefault_enable();
|
||||||
|
set_fs(old_fs);
|
||||||
|
|
||||||
|
if (ret >= count) {
|
||||||
|
ret = count;
|
||||||
|
dst[ret - 1] = '\0';
|
||||||
|
} else if (ret > 0) {
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
24
kernel/kernel_compat.h
Normal file
24
kernel/kernel_compat.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef __KSU_H_KERNEL_COMPAT
|
||||||
|
#define __KSU_H_KERNEL_COMPAT
|
||||||
|
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/key.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
|
||||||
|
extern long ksu_strncpy_from_user_nofault(char *dst,
|
||||||
|
const void __user *unsafe_addr,
|
||||||
|
long count);
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
|
||||||
|
extern struct key *init_session_keyring;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void ksu_android_ns_fs_check();
|
||||||
|
extern struct file *ksu_filp_open_compat(const char *filename, int flags,
|
||||||
|
umode_t mode);
|
||||||
|
extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
|
||||||
|
loff_t *pos);
|
||||||
|
extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf,
|
||||||
|
size_t count, loff_t *pos);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
#ifndef __KSU_H_KLOG
|
#ifndef __KSU_H_KLOG
|
||||||
#define __KSU_H_KLOG
|
#define __KSU_H_KLOG
|
||||||
|
|
||||||
|
#include <linux/printk.h>
|
||||||
|
|
||||||
#ifdef pr_fmt
|
#ifdef pr_fmt
|
||||||
#undef pr_fmt
|
#undef pr_fmt
|
||||||
#define pr_fmt(fmt) "KernelSU: " fmt
|
#define pr_fmt(fmt) "KernelSU: " fmt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
284
kernel/ksu.c
284
kernel/ksu.c
@@ -1,251 +1,77 @@
|
|||||||
#include "linux/uidgid.h"
|
#include "linux/fs.h"
|
||||||
#include <linux/cpu.h>
|
#include "linux/module.h"
|
||||||
#include <linux/memory.h>
|
#include "linux/workqueue.h"
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kprobes.h>
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <asm-generic/errno-base.h>
|
|
||||||
|
|
||||||
#include <linux/rcupdate.h>
|
|
||||||
#include <linux/fdtable.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/fs_struct.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
|
|
||||||
#include <linux/delay.h> // mslepp
|
|
||||||
|
|
||||||
#include "selinux/selinux.h"
|
|
||||||
#include "klog.h"
|
|
||||||
#include "apk_sign.h"
|
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
|
#include "core_hook.h"
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "ksu.h"
|
||||||
|
#include "uid_observer.h"
|
||||||
|
|
||||||
#define KERNEL_SU_VERSION 3
|
static struct workqueue_struct *ksu_workqueue;
|
||||||
|
|
||||||
#define KERNEL_SU_OPTION 0xDEADBEEF
|
bool ksu_queue_work(struct work_struct *work)
|
||||||
|
|
||||||
#define CMD_GRANT_ROOT 0
|
|
||||||
|
|
||||||
#define CMD_BECOME_MANAGER 1
|
|
||||||
#define CMD_GET_VERSION 2
|
|
||||||
#define CMD_ALLOW_SU 3
|
|
||||||
#define CMD_DENY_SU 4
|
|
||||||
#define CMD_GET_ALLOW_LIST 5
|
|
||||||
#define CMD_GET_DENY_LIST 6
|
|
||||||
|
|
||||||
void escape_to_root(bool disable_seccomp) {
|
|
||||||
struct cred* cred;
|
|
||||||
|
|
||||||
cred = (struct cred *)__task_cred(current);
|
|
||||||
|
|
||||||
memset(&cred->uid, 0, sizeof(cred->uid));
|
|
||||||
memset(&cred->gid, 0, sizeof(cred->gid));
|
|
||||||
memset(&cred->suid, 0, sizeof(cred->suid));
|
|
||||||
memset(&cred->euid, 0, sizeof(cred->euid));
|
|
||||||
memset(&cred->egid, 0, sizeof(cred->egid));
|
|
||||||
memset(&cred->fsuid, 0, sizeof(cred->fsuid));
|
|
||||||
memset(&cred->fsgid, 0, sizeof(cred->fsgid));
|
|
||||||
memset(&cred->cap_inheritable, 0xff, sizeof(cred->cap_inheritable));
|
|
||||||
memset(&cred->cap_permitted, 0xff, sizeof(cred->cap_permitted));
|
|
||||||
memset(&cred->cap_effective, 0xff, sizeof(cred->cap_effective));
|
|
||||||
memset(&cred->cap_bset, 0xff, sizeof(cred->cap_bset));
|
|
||||||
memset(&cred->cap_ambient, 0xff, sizeof(cred->cap_ambient));
|
|
||||||
|
|
||||||
if (disable_seccomp) {
|
|
||||||
current_thread_info()->flags = 0;
|
|
||||||
current->seccomp.mode = 0;
|
|
||||||
current->seccomp.filter = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_selinux();
|
|
||||||
}
|
|
||||||
|
|
||||||
int startswith(char* s, char* prefix) {
|
|
||||||
return strncmp(s, prefix, strlen(prefix));
|
|
||||||
}
|
|
||||||
|
|
||||||
int endswith(const char *s, const char *t)
|
|
||||||
{
|
{
|
||||||
size_t slen = strlen(s);
|
return queue_work(ksu_workqueue, work);
|
||||||
size_t tlen = strlen(t);
|
|
||||||
if (tlen > slen) return 1;
|
|
||||||
return strcmp(s + slen - tlen, t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uid_t __manager_uid;
|
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||||
|
void *argv, void *envp, int *flags);
|
||||||
|
|
||||||
static bool is_manager() {
|
extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||||
return __manager_uid == current_uid().val;
|
void *argv, void *envp, int *flags);
|
||||||
|
|
||||||
|
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||||
|
void *envp, int *flags)
|
||||||
|
{
|
||||||
|
ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags);
|
||||||
|
return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp,
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool become_manager() {
|
extern void ksu_enable_sucompat();
|
||||||
if (__manager_uid != 0) {
|
extern void ksu_enable_ksud();
|
||||||
pr_info("manager already exist: %d\n", __manager_uid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// list current process's files
|
|
||||||
struct files_struct *current_files;
|
|
||||||
struct fdtable *files_table;
|
|
||||||
int i = 0;
|
|
||||||
struct path files_path;
|
|
||||||
char *cwd;
|
|
||||||
char *buf = (char *)kmalloc(GFP_KERNEL, PATH_MAX);
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
current_files = current->files;
|
int __init kernelsu_init(void)
|
||||||
files_table = files_fdtable(current_files);
|
{
|
||||||
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
|
pr_alert("*************************************************************");
|
||||||
|
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||||
|
pr_alert("** **");
|
||||||
|
pr_alert("** You are running KernelSU in DEBUG mode **");
|
||||||
|
pr_alert("** **");
|
||||||
|
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||||
|
pr_alert("*************************************************************");
|
||||||
|
#endif
|
||||||
|
|
||||||
// todo: use iterate_fd
|
ksu_core_init();
|
||||||
while(files_table->fd[i] != NULL) {
|
|
||||||
files_path = files_table->fd[i]->f_path;
|
|
||||||
if (!d_is_reg(files_path.dentry)) {
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cwd = d_path(&files_path, buf, PATH_MAX);
|
|
||||||
if (startswith(cwd, "/data/app/") == 0 && endswith(cwd, "/base.apk") == 0) {
|
|
||||||
// we have found the apk!
|
|
||||||
pr_info("found apk: %s", cwd);
|
|
||||||
if (is_manager_apk(cwd) == 0) {
|
|
||||||
// check passed
|
|
||||||
uid_t uid = current_uid().val;
|
|
||||||
pr_info("manager uid: %d\n", uid);
|
|
||||||
|
|
||||||
__manager_uid = uid;
|
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
|
||||||
|
|
||||||
result = true;
|
|
||||||
goto clean;
|
|
||||||
} else {
|
|
||||||
pr_info("manager signature invalid!");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
clean:
|
|
||||||
kfree(buf);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_allow_su() {
|
|
||||||
uid_t uid = current_uid().val;
|
|
||||||
if (uid == __manager_uid) {
|
|
||||||
// we are manager, allow!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uid == 0) {
|
|
||||||
// we are already root, allow!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ksu_is_allow_uid(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void enable_sucompat();
|
|
||||||
|
|
||||||
static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
|
|
||||||
|
|
||||||
struct pt_regs* real_regs = (struct pt_regs*) PT_REGS_PARM1(regs);
|
|
||||||
int option = (int) PT_REGS_PARM1(real_regs);
|
|
||||||
unsigned long arg2 = (unsigned long) PT_REGS_PARM2(real_regs);
|
|
||||||
unsigned long arg3 = (unsigned long) PT_REGS_PARM3(real_regs);
|
|
||||||
unsigned long arg4 = (unsigned long) PT_REGS_PARM4(real_regs);
|
|
||||||
unsigned long arg5 = (unsigned long) PT_REGS_PARM5(real_regs);
|
|
||||||
|
|
||||||
// if success, we modify the arg5 as result!
|
|
||||||
u32* result = (u32*) arg5;
|
|
||||||
u32 reply_ok = KERNEL_SU_OPTION;
|
|
||||||
|
|
||||||
if (KERNEL_SU_OPTION != option) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
|
|
||||||
|
|
||||||
if (arg2 == CMD_BECOME_MANAGER) {
|
|
||||||
// someone wants to be root manager, just check it!
|
|
||||||
bool success = become_manager();
|
|
||||||
if (success) {
|
|
||||||
copy_to_user(result, &reply_ok, sizeof(reply_ok));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg2 == CMD_GRANT_ROOT) {
|
|
||||||
if (is_allow_su()) {
|
|
||||||
pr_info("allow root for: %d\n", current_uid());
|
|
||||||
escape_to_root(true);
|
|
||||||
} else {
|
|
||||||
pr_info("deny root for: %d\n", current_uid());
|
|
||||||
// add it to deny list!
|
|
||||||
ksu_allow_uid(current_uid().val, false);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// all other cmds are for 'root manager'
|
|
||||||
if (!is_manager()) {
|
|
||||||
pr_info("Only manager can do cmd: %d\n", arg2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we are already manager
|
|
||||||
if (arg2 == CMD_ALLOW_SU || arg2 == CMD_DENY_SU) {
|
|
||||||
bool allow = arg2 == CMD_ALLOW_SU;
|
|
||||||
bool success = false;
|
|
||||||
uid_t uid = (uid_t) arg3;
|
|
||||||
success = ksu_allow_uid(uid, allow);
|
|
||||||
if (success) {
|
|
||||||
copy_to_user(result, &reply_ok, sizeof(reply_ok));
|
|
||||||
}
|
|
||||||
} else if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) {
|
|
||||||
u32 array[128];
|
|
||||||
u32 array_length;
|
|
||||||
bool success = ksu_get_allow_list(array, &array_length, arg2 == CMD_GET_ALLOW_LIST);
|
|
||||||
if (success) {
|
|
||||||
copy_to_user(arg4, &array_length, sizeof(array_length));
|
|
||||||
copy_to_user(arg3, array, sizeof(u32) * array_length);
|
|
||||||
|
|
||||||
copy_to_user(result, &reply_ok, sizeof(reply_ok));
|
|
||||||
}
|
|
||||||
} else if (arg2 == CMD_GET_VERSION) {
|
|
||||||
u32 version = KERNEL_SU_VERSION;
|
|
||||||
copy_to_user(arg3, &version, sizeof(version));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct kprobe kp = {
|
|
||||||
.symbol_name = PRCTL_SYMBOL,
|
|
||||||
.pre_handler = handler_pre,
|
|
||||||
};
|
|
||||||
|
|
||||||
int kernelsu_init(void){
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
ksu_allowlist_init();
|
ksu_allowlist_init();
|
||||||
|
|
||||||
rc = register_kprobe(&kp);
|
ksu_uid_observer_init();
|
||||||
|
|
||||||
enable_sucompat();
|
#ifdef CONFIG_KPROBES
|
||||||
|
ksu_enable_sucompat();
|
||||||
|
ksu_enable_ksud();
|
||||||
|
#else
|
||||||
|
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
|
||||||
|
#endif
|
||||||
|
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kernelsu_exit(void){
|
void kernelsu_exit(void)
|
||||||
// should never happen...
|
{
|
||||||
unregister_kprobe(&kp);
|
|
||||||
|
|
||||||
ksu_allowlist_exit();
|
ksu_allowlist_exit();
|
||||||
|
|
||||||
|
ksu_uid_observer_exit();
|
||||||
|
|
||||||
|
destroy_workqueue(ksu_workqueue);
|
||||||
|
|
||||||
|
ksu_core_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(kernelsu_init);
|
module_init(kernelsu_init);
|
||||||
@@ -253,4 +79,8 @@ module_exit(kernelsu_exit);
|
|||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("weishu");
|
MODULE_AUTHOR("weishu");
|
||||||
MODULE_DESCRIPTION("Android GKI KernelSU");
|
MODULE_DESCRIPTION("Android KernelSU");
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
|
||||||
|
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
||||||
|
#endif
|
||||||
|
|||||||
99
kernel/ksu.h
Normal file
99
kernel/ksu.h
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#ifndef __KSU_H_KSU
|
||||||
|
#define __KSU_H_KSU
|
||||||
|
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/workqueue.h"
|
||||||
|
|
||||||
|
#define KERNEL_SU_VERSION KSU_VERSION
|
||||||
|
#define KERNEL_SU_OPTION 0xDEADBEEF
|
||||||
|
|
||||||
|
#define CMD_GRANT_ROOT 0
|
||||||
|
#define CMD_BECOME_MANAGER 1
|
||||||
|
#define CMD_GET_VERSION 2
|
||||||
|
#define CMD_ALLOW_SU 3
|
||||||
|
#define CMD_DENY_SU 4
|
||||||
|
#define CMD_GET_ALLOW_LIST 5
|
||||||
|
#define CMD_GET_DENY_LIST 6
|
||||||
|
#define CMD_REPORT_EVENT 7
|
||||||
|
#define CMD_SET_SEPOLICY 8
|
||||||
|
#define CMD_CHECK_SAFEMODE 9
|
||||||
|
#define CMD_GET_APP_PROFILE 10
|
||||||
|
#define CMD_SET_APP_PROFILE 11
|
||||||
|
#define CMD_UID_GRANTED_ROOT 12
|
||||||
|
#define CMD_UID_SHOULD_UMOUNT 13
|
||||||
|
|
||||||
|
#define EVENT_POST_FS_DATA 1
|
||||||
|
#define EVENT_BOOT_COMPLETED 2
|
||||||
|
#define EVENT_MODULE_MOUNTED 3
|
||||||
|
|
||||||
|
#define KSU_APP_PROFILE_VER 2
|
||||||
|
#define KSU_MAX_PACKAGE_NAME 256
|
||||||
|
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
|
||||||
|
#define KSU_MAX_GROUPS 32
|
||||||
|
#define KSU_SELINUX_DOMAIN 64
|
||||||
|
|
||||||
|
struct root_profile {
|
||||||
|
int32_t uid;
|
||||||
|
int32_t gid;
|
||||||
|
|
||||||
|
int32_t groups_count;
|
||||||
|
int32_t groups[KSU_MAX_GROUPS];
|
||||||
|
|
||||||
|
// kernel_cap_t is u32[2] for capabilities v3
|
||||||
|
struct {
|
||||||
|
u64 effective;
|
||||||
|
u64 permitted;
|
||||||
|
u64 inheritable;
|
||||||
|
} capabilities;
|
||||||
|
|
||||||
|
char selinux_domain[KSU_SELINUX_DOMAIN];
|
||||||
|
|
||||||
|
int32_t namespaces;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct non_root_profile {
|
||||||
|
bool umount_modules;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct app_profile {
|
||||||
|
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
|
||||||
|
u32 version;
|
||||||
|
|
||||||
|
// this is usually the package of the app, but can be other value for special apps
|
||||||
|
char key[KSU_MAX_PACKAGE_NAME];
|
||||||
|
int32_t current_uid;
|
||||||
|
bool allow_su;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
bool use_default;
|
||||||
|
char template_name[KSU_MAX_PACKAGE_NAME];
|
||||||
|
|
||||||
|
struct root_profile profile;
|
||||||
|
} rp_config;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool use_default;
|
||||||
|
|
||||||
|
struct non_root_profile profile;
|
||||||
|
} nrp_config;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ksu_queue_work(struct work_struct *work);
|
||||||
|
|
||||||
|
static inline int startswith(char *s, char *prefix)
|
||||||
|
{
|
||||||
|
return strncmp(s, prefix, strlen(prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int endswith(const char *s, const char *t)
|
||||||
|
{
|
||||||
|
size_t slen = strlen(s);
|
||||||
|
size_t tlen = strlen(t);
|
||||||
|
if (tlen > slen)
|
||||||
|
return 1;
|
||||||
|
return strcmp(s + slen - tlen, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
567
kernel/ksud.c
Normal file
567
kernel/ksud.c
Normal file
@@ -0,0 +1,567 @@
|
|||||||
|
#include "asm/current.h"
|
||||||
|
#include "linux/compat.h"
|
||||||
|
#include "linux/dcache.h"
|
||||||
|
#include "linux/err.h"
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/input-event-codes.h"
|
||||||
|
#include "linux/kprobes.h"
|
||||||
|
#include "linux/printk.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/uaccess.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
#include "linux/workqueue.h"
|
||||||
|
|
||||||
|
#include "allowlist.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "ksud.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
#include "selinux/selinux.h"
|
||||||
|
|
||||||
|
static const char KERNEL_SU_RC[] =
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
"on post-fs-data\n"
|
||||||
|
" start logd\n"
|
||||||
|
// We should wait for the post-fs-data finish
|
||||||
|
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
"on nonencrypted\n"
|
||||||
|
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
"on property:vold.decrypt=trigger_restart_framework\n"
|
||||||
|
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
"on property:sys.boot_completed=1\n"
|
||||||
|
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
"\n";
|
||||||
|
|
||||||
|
static void stop_vfs_read_hook();
|
||||||
|
static void stop_execve_hook();
|
||||||
|
static void stop_input_hook();
|
||||||
|
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
static struct work_struct stop_vfs_read_work;
|
||||||
|
static struct work_struct stop_execve_hook_work;
|
||||||
|
static struct work_struct stop_input_hook_work;
|
||||||
|
#else
|
||||||
|
bool ksu_vfs_read_hook __read_mostly = true;
|
||||||
|
bool ksu_execveat_hook __read_mostly = true;
|
||||||
|
bool ksu_input_hook __read_mostly = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void on_post_fs_data(void)
|
||||||
|
{
|
||||||
|
static bool done = false;
|
||||||
|
if (done) {
|
||||||
|
pr_info("on_post_fs_data already done\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
pr_info("on_post_fs_data!\n");
|
||||||
|
ksu_load_allow_list();
|
||||||
|
// sanity check, this may influence the performance
|
||||||
|
stop_input_hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_ARG_STRINGS 0x7FFFFFFF
|
||||||
|
struct user_arg_ptr {
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
bool is_compat;
|
||||||
|
#endif
|
||||||
|
union {
|
||||||
|
const char __user *const __user *native;
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
const compat_uptr_t __user *compat;
|
||||||
|
#endif
|
||||||
|
} ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
|
||||||
|
{
|
||||||
|
const char __user *native;
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
if (unlikely(argv.is_compat)) {
|
||||||
|
compat_uptr_t compat;
|
||||||
|
|
||||||
|
if (get_user(compat, argv.ptr.compat + nr))
|
||||||
|
return ERR_PTR(-EFAULT);
|
||||||
|
|
||||||
|
return compat_ptr(compat);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (get_user(native, argv.ptr.native + nr))
|
||||||
|
return ERR_PTR(-EFAULT);
|
||||||
|
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* count() counts the number of strings in array ARGV.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure old GCC compiler can use __maybe_unused,
|
||||||
|
* Test passed in 4.4.x ~ 4.9.x when use GCC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int __maybe_unused count(struct user_arg_ptr argv, int max)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (argv.ptr.native != NULL) {
|
||||||
|
for (;;) {
|
||||||
|
const char __user *p = get_user_arg_ptr(argv, i);
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (IS_ERR(p))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (i >= max)
|
||||||
|
return -E2BIG;
|
||||||
|
++i;
|
||||||
|
|
||||||
|
if (fatal_signal_pending(current))
|
||||||
|
return -ERESTARTNOHAND;
|
||||||
|
cond_resched();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version
|
||||||
|
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||||
|
struct user_arg_ptr *argv, struct user_arg_ptr *envp, int *flags)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_KPROBES
|
||||||
|
if (!ksu_execveat_hook) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
struct filename *filename;
|
||||||
|
|
||||||
|
static const char app_process[] = "/system/bin/app_process";
|
||||||
|
static bool first_app_process = true;
|
||||||
|
|
||||||
|
/* This applies to versions Android 10+ */
|
||||||
|
static const char system_bin_init[] = "/system/bin/init";
|
||||||
|
/* This applies to versions between Android 6 ~ 9 */
|
||||||
|
static const char old_system_init[] = "/init";
|
||||||
|
static bool init_second_stage_executed = false;
|
||||||
|
|
||||||
|
if (!filename_ptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
filename = *filename_ptr;
|
||||||
|
if (IS_ERR(filename)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(!memcmp(filename->name, system_bin_init,
|
||||||
|
sizeof(system_bin_init) - 1) && argv)) {
|
||||||
|
// /system/bin/init executed
|
||||||
|
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||||
|
pr_info("/system/bin/init argc: %d\n", argc);
|
||||||
|
if (argc > 1 && !init_second_stage_executed) {
|
||||||
|
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||||
|
if (p && !IS_ERR(p)) {
|
||||||
|
char first_arg[16];
|
||||||
|
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
|
||||||
|
pr_info("/system/bin/init first arg: %s\n", first_arg);
|
||||||
|
if (!strcmp(first_arg, "second_stage")) {
|
||||||
|
pr_info("/system/bin/init second_stage executed\n");
|
||||||
|
apply_kernelsu_rules();
|
||||||
|
init_second_stage_executed = true;
|
||||||
|
ksu_android_ns_fs_check();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr_err("/system/bin/init parse args err!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (unlikely(!memcmp(filename->name, old_system_init,
|
||||||
|
sizeof(old_system_init) - 1) && argv)) {
|
||||||
|
// /init executed
|
||||||
|
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||||
|
pr_info("/init argc: %d\n", argc);
|
||||||
|
if (argc > 1 && !init_second_stage_executed) {
|
||||||
|
/* This applies to versions between Android 6 ~ 7 */
|
||||||
|
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||||
|
if (p && !IS_ERR(p)) {
|
||||||
|
char first_arg[16];
|
||||||
|
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
|
||||||
|
pr_info("/init first arg: %s\n", first_arg);
|
||||||
|
if (!strcmp(first_arg, "--second-stage")) {
|
||||||
|
pr_info("/init second_stage executed\n");
|
||||||
|
apply_kernelsu_rules();
|
||||||
|
init_second_stage_executed = true;
|
||||||
|
ksu_android_ns_fs_check();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr_err("/init parse args err!\n");
|
||||||
|
}
|
||||||
|
} else if (argc == 1 && !init_second_stage_executed && envp) {
|
||||||
|
/* This applies to versions between Android 8 ~ 9 */
|
||||||
|
int envc = count(*envp, MAX_ARG_STRINGS);
|
||||||
|
if (envc > 0) {
|
||||||
|
int n;
|
||||||
|
for (n = 1; n <= envc; n++) {
|
||||||
|
const char __user *p = get_user_arg_ptr(*envp, n);
|
||||||
|
if (!p || IS_ERR(p)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char env[256];
|
||||||
|
// Reading environment variable strings from user space
|
||||||
|
if (ksu_strncpy_from_user_nofault(env, p, sizeof(env)) < 0)
|
||||||
|
continue;
|
||||||
|
// Parsing environment variable names and values
|
||||||
|
char *env_name = env;
|
||||||
|
char *env_value = strchr(env, '=');
|
||||||
|
if (env_value == NULL)
|
||||||
|
continue;
|
||||||
|
// Replace equal sign with string terminator
|
||||||
|
*env_value = '\0';
|
||||||
|
env_value++;
|
||||||
|
// Check if the environment variable name and value are matching
|
||||||
|
if (!strcmp(env_name, "INIT_SECOND_STAGE") && (!strcmp(env_value, "1") || !strcmp(env_value, "true"))) {
|
||||||
|
pr_info("/init second_stage executed\n");
|
||||||
|
apply_kernelsu_rules();
|
||||||
|
init_second_stage_executed = true;
|
||||||
|
ksu_android_ns_fs_check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(first_app_process &&
|
||||||
|
!memcmp(filename->name, app_process, sizeof(app_process) - 1))) {
|
||||||
|
first_app_process = false;
|
||||||
|
pr_info("exec app_process, /data prepared, second_stage: %d\n", init_second_stage_executed);
|
||||||
|
on_post_fs_data(); // we keep this for old ksud
|
||||||
|
stop_execve_hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *);
|
||||||
|
static ssize_t (*orig_read_iter)(struct kiocb *, struct iov_iter *);
|
||||||
|
static struct file_operations fops_proxy;
|
||||||
|
static ssize_t read_count_append = 0;
|
||||||
|
|
||||||
|
static ssize_t read_proxy(struct file *file, char __user *buf, size_t count,
|
||||||
|
loff_t *pos)
|
||||||
|
{
|
||||||
|
bool first_read = file->f_pos == 0;
|
||||||
|
ssize_t ret = orig_read(file, buf, count, pos);
|
||||||
|
if (first_read) {
|
||||||
|
pr_info("read_proxy append %ld + %ld\n", ret, read_count_append);
|
||||||
|
ret += read_count_append;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to)
|
||||||
|
{
|
||||||
|
bool first_read = iocb->ki_pos == 0;
|
||||||
|
ssize_t ret = orig_read_iter(iocb, to);
|
||||||
|
if (first_read) {
|
||||||
|
pr_info("read_iter_proxy append %ld + %ld\n", ret,
|
||||||
|
read_count_append);
|
||||||
|
ret += read_count_append;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||||
|
size_t *count_ptr, loff_t **pos)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_KPROBES
|
||||||
|
if (!ksu_vfs_read_hook) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
struct file *file;
|
||||||
|
char __user *buf;
|
||||||
|
size_t count;
|
||||||
|
|
||||||
|
if (strcmp(current->comm, "init")) {
|
||||||
|
// we are only interest in `init` process
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = *file_ptr;
|
||||||
|
if (IS_ERR(file)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d_is_reg(file->f_path.dentry)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *short_name = file->f_path.dentry->d_name.name;
|
||||||
|
if (strcmp(short_name, "atrace.rc")) {
|
||||||
|
// we are only interest `atrace.rc` file name file
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char path[256];
|
||||||
|
char *dpath = d_path(&file->f_path, path, sizeof(path));
|
||||||
|
|
||||||
|
if (IS_ERR(dpath)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(dpath, "/system/etc/init/atrace.rc")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we only process the first read
|
||||||
|
static bool rc_inserted = false;
|
||||||
|
if (rc_inserted) {
|
||||||
|
// we don't need this kprobe, unregister it!
|
||||||
|
stop_vfs_read_hook();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rc_inserted = true;
|
||||||
|
|
||||||
|
// now we can sure that the init process is reading
|
||||||
|
// `/system/etc/init/atrace.rc`
|
||||||
|
buf = *buf_ptr;
|
||||||
|
count = *count_ptr;
|
||||||
|
|
||||||
|
size_t rc_count = strlen(KERNEL_SU_RC);
|
||||||
|
|
||||||
|
pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath,
|
||||||
|
current->comm, count, rc_count);
|
||||||
|
|
||||||
|
if (count < rc_count) {
|
||||||
|
pr_err("count: %zu < rc_count: %zu\n", count, rc_count);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("copy ksud.rc failed: %zu\n", ret);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we've succeed to insert ksud.rc, now we need to proxy the read and modify the result!
|
||||||
|
// But, we can not modify the file_operations directly, because it's in read-only memory.
|
||||||
|
// We just replace the whole file_operations with a proxy one.
|
||||||
|
memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations));
|
||||||
|
orig_read = file->f_op->read;
|
||||||
|
if (orig_read) {
|
||||||
|
fops_proxy.read = read_proxy;
|
||||||
|
}
|
||||||
|
orig_read_iter = file->f_op->read_iter;
|
||||||
|
if (orig_read_iter) {
|
||||||
|
fops_proxy.read_iter = read_iter_proxy;
|
||||||
|
}
|
||||||
|
// replace the file_operations
|
||||||
|
file->f_op = &fops_proxy;
|
||||||
|
read_count_append = rc_count;
|
||||||
|
|
||||||
|
*buf_ptr = buf + rc_count;
|
||||||
|
*count_ptr = count - rc_count;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int volumedown_pressed_count = 0;
|
||||||
|
|
||||||
|
static bool is_volumedown_enough(unsigned int count)
|
||||||
|
{
|
||||||
|
return count >= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||||
|
int *value)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_KPROBES
|
||||||
|
if (!ksu_input_hook) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) {
|
||||||
|
int val = *value;
|
||||||
|
pr_info("KEY_VOLUMEDOWN val: %d\n", val);
|
||||||
|
if (val) {
|
||||||
|
// key pressed, count it
|
||||||
|
volumedown_pressed_count += 1;
|
||||||
|
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||||
|
stop_input_hook();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ksu_is_safe_mode()
|
||||||
|
{
|
||||||
|
static bool safe_mode = false;
|
||||||
|
if (safe_mode) {
|
||||||
|
// don't need to check again, userspace may call multiple times
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop hook first!
|
||||||
|
stop_input_hook();
|
||||||
|
|
||||||
|
pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count);
|
||||||
|
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||||
|
// pressed over 3 times
|
||||||
|
pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n");
|
||||||
|
safe_mode = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
|
||||||
|
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
|
||||||
|
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int *fd = (int *)&PT_REGS_PARM1(regs);
|
||||||
|
struct filename **filename_ptr =
|
||||||
|
(struct filename **)&PT_REGS_PARM2(regs);
|
||||||
|
struct user_arg_ptr argv;
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
argv.is_compat = PT_REGS_PARM3(regs);
|
||||||
|
if (unlikely(argv.is_compat)) {
|
||||||
|
argv.ptr.compat = PT_REGS_CCALL_PARM4(regs);
|
||||||
|
} else {
|
||||||
|
argv.ptr.native = PT_REGS_CCALL_PARM4(regs);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
argv.ptr.native = PT_REGS_PARM3(regs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs);
|
||||||
|
char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs);
|
||||||
|
size_t *count_ptr = (size_t *)&PT_REGS_PARM3(regs);
|
||||||
|
loff_t **pos_ptr = (loff_t **)&PT_REGS_CCALL_PARM4(regs);
|
||||||
|
|
||||||
|
return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int input_handle_event_handler_pre(struct kprobe *p,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs);
|
||||||
|
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs);
|
||||||
|
int *value = (int *)&PT_REGS_CCALL_PARM4(regs);
|
||||||
|
return ksu_handle_input_handle_event(type, code, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kprobe execve_kp = {
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
|
||||||
|
.symbol_name = "do_execveat_common",
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
|
||||||
|
.symbol_name = "__do_execve_file",
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
|
||||||
|
.symbol_name = "do_execveat_common",
|
||||||
|
#endif
|
||||||
|
.pre_handler = execve_handler_pre,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kprobe vfs_read_kp = {
|
||||||
|
.symbol_name = "vfs_read",
|
||||||
|
.pre_handler = read_handler_pre,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kprobe input_handle_event_kp = {
|
||||||
|
.symbol_name = "input_handle_event",
|
||||||
|
.pre_handler = input_handle_event_handler_pre,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void do_stop_vfs_read_hook(struct work_struct *work)
|
||||||
|
{
|
||||||
|
unregister_kprobe(&vfs_read_kp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_stop_execve_hook(struct work_struct *work)
|
||||||
|
{
|
||||||
|
unregister_kprobe(&execve_kp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_stop_input_hook(struct work_struct *work)
|
||||||
|
{
|
||||||
|
unregister_kprobe(&input_handle_event_kp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void stop_vfs_read_hook()
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
bool ret = schedule_work(&stop_vfs_read_work);
|
||||||
|
pr_info("unregister vfs_read kprobe: %d!\n", ret);
|
||||||
|
#else
|
||||||
|
ksu_vfs_read_hook = false;
|
||||||
|
pr_info("stop vfs_read_hook\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop_execve_hook()
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
bool ret = schedule_work(&stop_execve_hook_work);
|
||||||
|
pr_info("unregister execve kprobe: %d!\n", ret);
|
||||||
|
#else
|
||||||
|
ksu_execveat_hook = false;
|
||||||
|
pr_info("stop execve_hook\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop_input_hook()
|
||||||
|
{
|
||||||
|
static bool input_hook_stopped = false;
|
||||||
|
if (input_hook_stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
input_hook_stopped = true;
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
bool ret = schedule_work(&stop_input_hook_work);
|
||||||
|
pr_info("unregister input kprobe: %d!\n", ret);
|
||||||
|
#else
|
||||||
|
ksu_input_hook = false;
|
||||||
|
pr_info("stop input_hook\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// ksud: module support
|
||||||
|
void ksu_enable_ksud()
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = register_kprobe(&execve_kp);
|
||||||
|
pr_info("ksud: execve_kp: %d\n", ret);
|
||||||
|
|
||||||
|
ret = register_kprobe(&vfs_read_kp);
|
||||||
|
pr_info("ksud: vfs_read_kp: %d\n", ret);
|
||||||
|
|
||||||
|
ret = register_kprobe(&input_handle_event_kp);
|
||||||
|
pr_info("ksud: input_handle_event_kp: %d\n", ret);
|
||||||
|
|
||||||
|
INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
|
||||||
|
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
|
||||||
|
INIT_WORK(&stop_input_hook_work, do_stop_input_hook);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
10
kernel/ksud.h
Normal file
10
kernel/ksud.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __KSU_H_KSUD
|
||||||
|
#define __KSU_H_KSUD
|
||||||
|
|
||||||
|
#define KSUD_PATH "/data/adb/ksud"
|
||||||
|
|
||||||
|
void on_post_fs_data(void);
|
||||||
|
|
||||||
|
bool ksu_is_safe_mode(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
102
kernel/manager.c
Normal file
102
kernel/manager.c
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include "linux/cred.h"
|
||||||
|
#include "linux/gfp.h"
|
||||||
|
#include "linux/slab.h"
|
||||||
|
#include "linux/uidgid.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
|
||||||
|
#include "linux/fdtable.h"
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/rcupdate.h"
|
||||||
|
|
||||||
|
#include "apk_sign.h"
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "ksu.h"
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
|
uid_t ksu_manager_uid = KSU_INVALID_UID;
|
||||||
|
|
||||||
|
bool become_manager(char *pkg)
|
||||||
|
{
|
||||||
|
struct fdtable *files_table;
|
||||||
|
int i = 0;
|
||||||
|
struct path files_path;
|
||||||
|
char *cwd;
|
||||||
|
char *buf;
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
#ifdef KSU_MANAGER_PACKAGE
|
||||||
|
// pkg is `/<real package>`
|
||||||
|
if (strncmp(pkg + 1, KSU_MANAGER_PACKAGE,
|
||||||
|
sizeof(KSU_MANAGER_PACKAGE)) != 0) {
|
||||||
|
pr_info("manager package is inconsistent with kernel build: %s\n",
|
||||||
|
KSU_MANAGER_PACKAGE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// must be zygote's direct child, otherwise any app can fork a new process and
|
||||||
|
// open manager's apk
|
||||||
|
if (task_uid(current->real_parent).val != 0) {
|
||||||
|
pr_info("parent is not zygote!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = (char *)kmalloc(PATH_MAX, GFP_ATOMIC);
|
||||||
|
if (!buf) {
|
||||||
|
pr_err("kalloc path failed.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
files_table = files_fdtable(current->files);
|
||||||
|
|
||||||
|
int pkg_len = strlen(pkg);
|
||||||
|
// todo: use iterate_fd
|
||||||
|
for (i = 0; files_table->fd[i] != NULL; i++) {
|
||||||
|
files_path = files_table->fd[i]->f_path;
|
||||||
|
if (!d_is_reg(files_path.dentry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cwd = d_path(&files_path, buf, PATH_MAX);
|
||||||
|
if (startswith(cwd, "/data/app/") != 0 ||
|
||||||
|
endswith(cwd, "==/base.apk") != 0) {
|
||||||
|
// AOSP generate ramdom base64 with 16bit, without NO_PADDING, so it must have two "="
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// we have found the apk!
|
||||||
|
pr_info("found apk: %s\n", cwd);
|
||||||
|
char *pkg_index = strstr(cwd, pkg);
|
||||||
|
if (!pkg_index) {
|
||||||
|
pr_info("apk path not match package name!\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char *next_char = pkg_index + pkg_len;
|
||||||
|
// because we ensure the cwd must startswith `/data/app` and endswith `base.apk`
|
||||||
|
// we don't need to check if the pointer is out of bounds
|
||||||
|
if (*next_char != '-') {
|
||||||
|
// from android 8.1: http://aospxref.com/android-8.1.0_r81/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#17612
|
||||||
|
// to android 13: http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java#1208
|
||||||
|
// /data/app/~~[randomStringA]/[packageName]-[randomStringB]
|
||||||
|
// the previous char must be `/` and the next char must be `-`
|
||||||
|
// because we use strstr instead of equals, this is a strong verfication.
|
||||||
|
pr_info("invalid pkg: %s\n", pkg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_manager_apk(cwd)) {
|
||||||
|
// check passed
|
||||||
|
uid_t uid = current_uid().val;
|
||||||
|
pr_info("manager uid: %d\n", uid);
|
||||||
|
|
||||||
|
ksu_set_manager_uid(uid);
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
goto clean;
|
||||||
|
} else {
|
||||||
|
pr_info("manager signature invalid!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
kfree(buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
38
kernel/manager.h
Normal file
38
kernel/manager.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __KSU_H_KSU_MANAGER
|
||||||
|
#define __KSU_H_KSU_MANAGER
|
||||||
|
|
||||||
|
#include "linux/cred.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
|
||||||
|
#define KSU_INVALID_UID -1
|
||||||
|
|
||||||
|
extern uid_t ksu_manager_uid; // DO NOT DIRECT USE
|
||||||
|
|
||||||
|
static inline bool ksu_is_manager_uid_valid()
|
||||||
|
{
|
||||||
|
return ksu_manager_uid != KSU_INVALID_UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_manager()
|
||||||
|
{
|
||||||
|
return unlikely(ksu_manager_uid == current_uid().val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uid_t ksu_get_manager_uid()
|
||||||
|
{
|
||||||
|
return ksu_manager_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ksu_set_manager_uid(uid_t uid)
|
||||||
|
{
|
||||||
|
ksu_manager_uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ksu_invalidate_manager_uid()
|
||||||
|
{
|
||||||
|
ksu_manager_uid = KSU_INVALID_UID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool become_manager(char *pkg);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
#include <linux/kallsyms.h>
|
#include "linux/kallsyms.h"
|
||||||
#include <linux/kprobes.h>
|
|
||||||
|
|
||||||
#define RE_EXPORT_SYMBOL1(ret, func, t1, v1) \
|
#define RE_EXPORT_SYMBOL1(ret, func, t1, v1) \
|
||||||
ret ksu_##func(t1 v1) { \
|
ret ksu_##func(t1 v1) \
|
||||||
return func(v1); \
|
{ \
|
||||||
} \
|
return func(v1); \
|
||||||
EXPORT_SYMBOL(ksu_##func); \
|
} \
|
||||||
|
EXPORT_SYMBOL(ksu_##func);
|
||||||
|
|
||||||
#define RE_EXPORT_SYMBOL2(ret, func, t1, v1, t2, v2) \
|
#define RE_EXPORT_SYMBOL2(ret, func, t1, v1, t2, v2) \
|
||||||
ret ksu_##func(t1 v1, t2 v2) { \
|
ret ksu_##func(t1 v1, t2 v2) \
|
||||||
return func(v1, v2); \
|
{ \
|
||||||
} \
|
return func(v1, v2); \
|
||||||
EXPORT_SYMBOL(ksu_##func); \
|
} \
|
||||||
|
EXPORT_SYMBOL(ksu_##func);
|
||||||
|
|
||||||
|
RE_EXPORT_SYMBOL1(unsigned long, kallsyms_lookup_name, const char *, name)
|
||||||
RE_EXPORT_SYMBOL1(unsigned long, kallsyms_lookup_name, const char*, name)
|
|
||||||
|
|
||||||
// RE_EXPORT_SYMBOL2(int, register_kprobe, struct kprobe *, p)
|
// RE_EXPORT_SYMBOL2(int, register_kprobe, struct kprobe *, p)
|
||||||
// RE_EXPORT_SYMBOL2(void, unregister_kprobe, struct kprobe *, p)
|
// RE_EXPORT_SYMBOL2(void, unregister_kprobe, struct kprobe *, p)
|
||||||
@@ -30,4 +30,4 @@ RE_EXPORT_SYMBOL1(unsigned long, kallsyms_lookup_name, const char*, name)
|
|||||||
// int ksu_register_kretprobe(struct kretprobe *rp);
|
// int ksu_register_kretprobe(struct kretprobe *rp);
|
||||||
// void unregister_kretprobe(struct kretprobe *rp);
|
// void unregister_kretprobe(struct kretprobe *rp);
|
||||||
// int register_kretprobes(struct kretprobe **rps, int num);
|
// int register_kretprobes(struct kretprobe **rps, int num);
|
||||||
// void unregister_kretprobes(struct kretprobe **rps, int num);
|
// void unregister_kretprobes(struct kretprobe **rps, int num);
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
obj-y += selinux.o
|
obj-y += selinux.o
|
||||||
|
obj-y += sepolicy.o
|
||||||
|
obj-y += rules.o
|
||||||
|
|
||||||
|
ifeq ($(shell grep -q " current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||||
|
ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0)
|
||||||
|
ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE
|
||||||
|
endif
|
||||||
|
|
||||||
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion
|
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion
|
||||||
|
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
||||||
|
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
||||||
|
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#include "../../../security/selinux/av_permissions.h"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include "../../../security/selinux/flask.h"
|
|
||||||
477
kernel/selinux/rules.c
Normal file
477
kernel/selinux/rules.c
Normal file
@@ -0,0 +1,477 @@
|
|||||||
|
#include "linux/uaccess.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
|
||||||
|
#include "../klog.h" // IWYU pragma: keep
|
||||||
|
#include "selinux.h"
|
||||||
|
#include "sepolicy.h"
|
||||||
|
#include "ss/services.h"
|
||||||
|
#include "linux/lsm_audit.h"
|
||||||
|
#include "xfrm.h"
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
#define SELINUX_POLICY_INSTEAD_SELINUX_SS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define KERNEL_SU_DOMAIN "su"
|
||||||
|
#define KERNEL_SU_FILE "ksu_file"
|
||||||
|
#define KERNEL_EXEC_TYPE "ksu_exec"
|
||||||
|
#define ALL NULL
|
||||||
|
|
||||||
|
static struct policydb *get_policydb(void)
|
||||||
|
{
|
||||||
|
struct policydb *db;
|
||||||
|
// selinux_state does not exists before 4.19
|
||||||
|
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
|
#ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS
|
||||||
|
struct selinux_policy *policy = rcu_dereference(selinux_state.policy);
|
||||||
|
db = &policy->policydb;
|
||||||
|
#else
|
||||||
|
struct selinux_ss *ss = rcu_dereference(selinux_state.ss);
|
||||||
|
db = &ss->policydb;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
db = &policydb;
|
||||||
|
#endif
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_kernelsu_rules()
|
||||||
|
{
|
||||||
|
if (!getenforce()) {
|
||||||
|
pr_info("SELinux permissive or disabled, apply rules!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
struct policydb *db = get_policydb();
|
||||||
|
|
||||||
|
ksu_permissive(db, KERNEL_SU_DOMAIN);
|
||||||
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
|
||||||
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain");
|
||||||
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain");
|
||||||
|
|
||||||
|
// Create unconstrained file type
|
||||||
|
ksu_type(db, KERNEL_SU_FILE, "file_type");
|
||||||
|
ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject");
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL);
|
||||||
|
|
||||||
|
// allow all!
|
||||||
|
ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL);
|
||||||
|
|
||||||
|
// allow us do any ioctl
|
||||||
|
if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) {
|
||||||
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL);
|
||||||
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL);
|
||||||
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL);
|
||||||
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to save allowlist in /data/adb/ksu
|
||||||
|
ksu_allow(db, "kernel", "adb_data_file", "dir", ALL);
|
||||||
|
ksu_allow(db, "kernel", "adb_data_file", "file", ALL);
|
||||||
|
// we may need to do mount on shell
|
||||||
|
ksu_allow(db, "kernel", "shell_data_file", "file", ALL);
|
||||||
|
// we need to read /data/system/packages.list
|
||||||
|
ksu_allow(db, "kernel", "kernel", "capability", "dac_override");
|
||||||
|
// Android 10+:
|
||||||
|
// http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512
|
||||||
|
ksu_allow(db, "kernel", "packages_list_file", "file", ALL);
|
||||||
|
// Kernel 4.4
|
||||||
|
ksu_allow(db, "kernel", "packages_list_file", "dir", ALL);
|
||||||
|
// Android 9-:
|
||||||
|
// http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360
|
||||||
|
ksu_allow(db, "kernel", "system_data_file", "file", ALL);
|
||||||
|
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
|
||||||
|
// our ksud triggered by init
|
||||||
|
ksu_allow(db, "init", "adb_data_file", "file", ALL);
|
||||||
|
ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289
|
||||||
|
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);
|
||||||
|
// we need to umount modules in zygote
|
||||||
|
ksu_allow(db, "zygote", "adb_data_file", "dir", "search");
|
||||||
|
|
||||||
|
// copied from Magisk rules
|
||||||
|
// suRights
|
||||||
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read");
|
||||||
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr");
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld");
|
||||||
|
|
||||||
|
// allowLog
|
||||||
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr");
|
||||||
|
|
||||||
|
// dumpsys
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use");
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write");
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read");
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open");
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr");
|
||||||
|
|
||||||
|
// bootctl
|
||||||
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process",
|
||||||
|
"getattr");
|
||||||
|
|
||||||
|
// For mounting loop devices, mirrors, tmpfs
|
||||||
|
ksu_allow(db, "kernel", ALL, "file", "read");
|
||||||
|
ksu_allow(db, "kernel", ALL, "file", "write");
|
||||||
|
|
||||||
|
// Allow all binder transactions
|
||||||
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
|
||||||
|
|
||||||
|
// Allow system server devpts
|
||||||
|
ksu_allow(db, "system_server", "untrusted_app_all_devpts", "chr_file",
|
||||||
|
"read");
|
||||||
|
ksu_allow(db, "system_server", "untrusted_app_all_devpts", "chr_file",
|
||||||
|
"write");
|
||||||
|
|
||||||
|
// Allow system server kill su process
|
||||||
|
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
|
||||||
|
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_SEPOL_LEN 128
|
||||||
|
|
||||||
|
#define CMD_NORMAL_PERM 1
|
||||||
|
#define CMD_XPERM 2
|
||||||
|
#define CMD_TYPE_STATE 3
|
||||||
|
#define CMD_TYPE 4
|
||||||
|
#define CMD_TYPE_ATTR 5
|
||||||
|
#define CMD_ATTR 6
|
||||||
|
#define CMD_TYPE_TRANSITION 7
|
||||||
|
#define CMD_TYPE_CHANGE 8
|
||||||
|
#define CMD_GENFSCON 9
|
||||||
|
|
||||||
|
struct sepol_data {
|
||||||
|
u32 cmd;
|
||||||
|
u32 subcmd;
|
||||||
|
char __user *sepol1;
|
||||||
|
char __user *sepol2;
|
||||||
|
char __user *sepol3;
|
||||||
|
char __user *sepol4;
|
||||||
|
char __user *sepol5;
|
||||||
|
char __user *sepol6;
|
||||||
|
char __user *sepol7;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int get_object(char *buf, char __user *user_object, size_t buf_sz,
|
||||||
|
char **object)
|
||||||
|
{
|
||||||
|
if (!user_object) {
|
||||||
|
*object = ALL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncpy_from_user(buf, user_object, buf_sz) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*object = buf;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset avc cache table, otherwise the new rules will not take effect if already denied
|
||||||
|
static void reset_avc_cache()
|
||||||
|
{
|
||||||
|
#if ((!defined(KSU_COMPAT_USE_SELINUX_STATE)) || \
|
||||||
|
LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0))
|
||||||
|
avc_ss_reset(0);
|
||||||
|
selnl_notify_policyload(0);
|
||||||
|
selinux_status_update_policyload(0);
|
||||||
|
#else
|
||||||
|
struct selinux_avc *avc = selinux_state.avc;
|
||||||
|
avc_ss_reset(avc, 0);
|
||||||
|
selnl_notify_policyload(0);
|
||||||
|
selinux_status_update_policyload(&selinux_state, 0);
|
||||||
|
#endif
|
||||||
|
selinux_xfrm_notify_policyload();
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||||
|
{
|
||||||
|
if (!arg4) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getenforce()) {
|
||||||
|
pr_info("SELinux permissive or disabled when handle policy!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sepol_data data;
|
||||||
|
if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
|
||||||
|
pr_err("sepol: copy sepol_data failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 cmd = data.cmd;
|
||||||
|
u32 subcmd = data.subcmd;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
struct policydb *db = get_policydb();
|
||||||
|
|
||||||
|
int ret = -1;
|
||||||
|
if (cmd == CMD_NORMAL_PERM) {
|
||||||
|
char src_buf[MAX_SEPOL_LEN];
|
||||||
|
char tgt_buf[MAX_SEPOL_LEN];
|
||||||
|
char cls_buf[MAX_SEPOL_LEN];
|
||||||
|
char perm_buf[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
char *s, *t, *c, *p;
|
||||||
|
if (get_object(src_buf, data.sepol1, sizeof(src_buf), &s) < 0) {
|
||||||
|
pr_err("sepol: copy src failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_object(tgt_buf, data.sepol2, sizeof(tgt_buf), &t) < 0) {
|
||||||
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_object(cls_buf, data.sepol3, sizeof(cls_buf), &c) < 0) {
|
||||||
|
pr_err("sepol: copy cls failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_object(perm_buf, data.sepol4, sizeof(perm_buf), &p) <
|
||||||
|
0) {
|
||||||
|
pr_err("sepol: copy perm failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
if (subcmd == 1) {
|
||||||
|
success = ksu_allow(db, s, t, c, p);
|
||||||
|
} else if (subcmd == 2) {
|
||||||
|
success = ksu_deny(db, s, t, c, p);
|
||||||
|
} else if (subcmd == 3) {
|
||||||
|
success = ksu_auditallow(db, s, t, c, p);
|
||||||
|
} else if (subcmd == 4) {
|
||||||
|
success = ksu_dontaudit(db, s, t, c, p);
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
|
}
|
||||||
|
ret = success ? 0 : -1;
|
||||||
|
|
||||||
|
} else if (cmd == CMD_XPERM) {
|
||||||
|
char src_buf[MAX_SEPOL_LEN];
|
||||||
|
char tgt_buf[MAX_SEPOL_LEN];
|
||||||
|
char cls_buf[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
char __maybe_unused
|
||||||
|
operation[MAX_SEPOL_LEN]; // it is always ioctl now!
|
||||||
|
char perm_set[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
char *s, *t, *c;
|
||||||
|
if (get_object(src_buf, data.sepol1, sizeof(src_buf), &s) < 0) {
|
||||||
|
pr_err("sepol: copy src failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (get_object(tgt_buf, data.sepol2, sizeof(tgt_buf), &t) < 0) {
|
||||||
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (get_object(cls_buf, data.sepol3, sizeof(cls_buf), &c) < 0) {
|
||||||
|
pr_err("sepol: copy cls failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(operation, data.sepol4,
|
||||||
|
sizeof(operation)) < 0) {
|
||||||
|
pr_err("sepol: copy operation failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(perm_set, data.sepol5, sizeof(perm_set)) <
|
||||||
|
0) {
|
||||||
|
pr_err("sepol: copy perm_set failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
if (subcmd == 1) {
|
||||||
|
success = ksu_allowxperm(db, s, t, c, perm_set);
|
||||||
|
} else if (subcmd == 2) {
|
||||||
|
success = ksu_auditallowxperm(db, s, t, c, perm_set);
|
||||||
|
} else if (subcmd == 3) {
|
||||||
|
success = ksu_dontauditxperm(db, s, t, c, perm_set);
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
|
}
|
||||||
|
ret = success ? 0 : -1;
|
||||||
|
} else if (cmd == CMD_TYPE_STATE) {
|
||||||
|
char src[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) {
|
||||||
|
pr_err("sepol: copy src failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
if (subcmd == 1) {
|
||||||
|
success = ksu_permissive(db, src);
|
||||||
|
} else if (subcmd == 2) {
|
||||||
|
success = ksu_enforce(db, src);
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
|
}
|
||||||
|
if (success)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
} else if (cmd == CMD_TYPE || cmd == CMD_TYPE_ATTR) {
|
||||||
|
char type[MAX_SEPOL_LEN];
|
||||||
|
char attr[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
if (strncpy_from_user(type, data.sepol1, sizeof(type)) < 0) {
|
||||||
|
pr_err("sepol: copy type failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(attr, data.sepol2, sizeof(attr)) < 0) {
|
||||||
|
pr_err("sepol: copy attr failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
if (cmd == CMD_TYPE) {
|
||||||
|
success = ksu_type(db, type, attr);
|
||||||
|
} else {
|
||||||
|
success = ksu_typeattribute(db, type, attr);
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
} else if (cmd == CMD_ATTR) {
|
||||||
|
char attr[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
if (strncpy_from_user(attr, data.sepol1, sizeof(attr)) < 0) {
|
||||||
|
pr_err("sepol: copy attr failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (!ksu_attribute(db, attr)) {
|
||||||
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
} else if (cmd == CMD_TYPE_TRANSITION) {
|
||||||
|
char src[MAX_SEPOL_LEN];
|
||||||
|
char tgt[MAX_SEPOL_LEN];
|
||||||
|
char cls[MAX_SEPOL_LEN];
|
||||||
|
char default_type[MAX_SEPOL_LEN];
|
||||||
|
char object[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) {
|
||||||
|
pr_err("sepol: copy src failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(tgt, data.sepol2, sizeof(tgt)) < 0) {
|
||||||
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(cls, data.sepol3, sizeof(cls)) < 0) {
|
||||||
|
pr_err("sepol: copy cls failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(default_type, data.sepol4,
|
||||||
|
sizeof(default_type)) < 0) {
|
||||||
|
pr_err("sepol: copy default_type failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
char *real_object;
|
||||||
|
if (data.sepol5 == NULL) {
|
||||||
|
real_object = NULL;
|
||||||
|
} else {
|
||||||
|
if (strncpy_from_user(object, data.sepol5,
|
||||||
|
sizeof(object)) < 0) {
|
||||||
|
pr_err("sepol: copy object failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
real_object = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = ksu_type_transition(db, src, tgt, cls,
|
||||||
|
default_type, real_object);
|
||||||
|
if (success)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
} else if (cmd == CMD_TYPE_CHANGE) {
|
||||||
|
char src[MAX_SEPOL_LEN];
|
||||||
|
char tgt[MAX_SEPOL_LEN];
|
||||||
|
char cls[MAX_SEPOL_LEN];
|
||||||
|
char default_type[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
|
if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) {
|
||||||
|
pr_err("sepol: copy src failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(tgt, data.sepol2, sizeof(tgt)) < 0) {
|
||||||
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(cls, data.sepol3, sizeof(cls)) < 0) {
|
||||||
|
pr_err("sepol: copy cls failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(default_type, data.sepol4,
|
||||||
|
sizeof(default_type)) < 0) {
|
||||||
|
pr_err("sepol: copy default_type failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
bool success = false;
|
||||||
|
if (subcmd == 1) {
|
||||||
|
success = ksu_type_change(db, src, tgt, cls,
|
||||||
|
default_type);
|
||||||
|
} else if (subcmd == 2) {
|
||||||
|
success = ksu_type_member(db, src, tgt, cls,
|
||||||
|
default_type);
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
|
}
|
||||||
|
if (success)
|
||||||
|
ret = 0;
|
||||||
|
} else if (cmd == CMD_GENFSCON) {
|
||||||
|
char name[MAX_SEPOL_LEN];
|
||||||
|
char path[MAX_SEPOL_LEN];
|
||||||
|
char context[MAX_SEPOL_LEN];
|
||||||
|
if (strncpy_from_user(name, data.sepol1, sizeof(name)) < 0) {
|
||||||
|
pr_err("sepol: copy name failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(path, data.sepol2, sizeof(path)) < 0) {
|
||||||
|
pr_err("sepol: copy path failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(context, data.sepol3, sizeof(context)) <
|
||||||
|
0) {
|
||||||
|
pr_err("sepol: copy context failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ksu_genfscon(db, name, path, context)) {
|
||||||
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown cmd: %d\n", cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
// only allow and xallow needs to reset avc cache, but we cannot do that because
|
||||||
|
// we are in atomic context. so we just reset it every time.
|
||||||
|
reset_avc_cache();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include "../../../security/selinux/include/security.h"
|
|
||||||
@@ -1,100 +1,132 @@
|
|||||||
#include <linux/cpu.h>
|
|
||||||
#include <linux/memory.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kprobes.h>
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
|
|
||||||
#include "../../../security/selinux/ss/sidtab.h"
|
|
||||||
#include "../../../security/selinux/ss/services.h"
|
|
||||||
#include "../../../security/selinux/include/objsec.h"
|
|
||||||
|
|
||||||
#include "selinux.h"
|
#include "selinux.h"
|
||||||
#include "../klog.h"
|
#include "objsec.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
#include "../klog.h" // IWYU pragma: keep
|
||||||
|
#ifndef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
|
#include "avc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define KERNEL_SU_DOMAIN "u:r:su:s0"
|
#define KERNEL_SU_DOMAIN "u:r:su:s0"
|
||||||
|
|
||||||
static int transive_to_domain(const char* domain) {
|
static int transive_to_domain(const char *domain)
|
||||||
struct cred* cred;
|
{
|
||||||
struct task_security_struct* tsec;
|
struct cred *cred;
|
||||||
|
struct task_security_struct *tsec;
|
||||||
u32 sid;
|
u32 sid;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
cred = (struct cred *)__task_cred(current);
|
cred = (struct cred *)__task_cred(current);
|
||||||
|
|
||||||
tsec = cred->security;
|
tsec = cred->security;
|
||||||
if (!tsec) {
|
if (!tsec) {
|
||||||
pr_err("tsec == NULL!\n");
|
pr_err("tsec == NULL!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = security_secctx_to_secid(domain, strlen(domain), &sid);
|
error = security_secctx_to_secid(domain, strlen(domain), &sid);
|
||||||
pr_info("error: %d, sid: %d\n", error, sid);
|
if (error) {
|
||||||
|
pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n",
|
||||||
|
domain, sid, error);
|
||||||
|
}
|
||||||
if (!error) {
|
if (!error) {
|
||||||
tsec->sid = sid;
|
tsec->sid = sid;
|
||||||
tsec->create_sid = 0;
|
tsec->create_sid = 0;
|
||||||
tsec->keycreate_sid = 0;
|
tsec->keycreate_sid = 0;
|
||||||
tsec->sockcreate_sid = 0;
|
tsec->sockcreate_sid = 0;
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_domain_permissive() {
|
void setup_selinux(const char *domain)
|
||||||
u32 sid;
|
{
|
||||||
struct selinux_policy *policy;
|
if (transive_to_domain(domain)) {
|
||||||
struct sidtab_entry *entry;
|
pr_err("transive domain failed.\n");
|
||||||
struct ebitmap *permissive;
|
return;
|
||||||
|
}
|
||||||
sid = current_sid();
|
|
||||||
pr_info("set sid (%d) to permissive", sid);
|
|
||||||
|
|
||||||
rcu_read_lock();
|
/* we didn't need this now, we have change selinux rules when boot!
|
||||||
policy = rcu_dereference(selinux_state.policy);
|
if (!is_domain_permissive) {
|
||||||
|
if (set_domain_permissive() == 0) {
|
||||||
entry = sidtab_search_entry(policy->sidtab, sid);
|
is_domain_permissive = true;
|
||||||
if (entry == NULL){
|
}
|
||||||
pr_info("entry == NULL");
|
}*/
|
||||||
rcu_read_unlock();
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
// FIXME: keep mls
|
|
||||||
permissive = &(policy->policydb.permissive_map);
|
|
||||||
ebitmap_set_bit(permissive, entry->context.type, 1);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_domain_permissive;
|
void setenforce(bool enforce)
|
||||||
|
{
|
||||||
void setup_selinux() {
|
|
||||||
|
|
||||||
if (transive_to_domain(KERNEL_SU_DOMAIN)) {
|
|
||||||
pr_err("transive domain failed.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_domain_permissive) {
|
|
||||||
if (set_domain_permissive() == 0) {
|
|
||||||
is_domain_permissive = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setenforce(bool enforce) {
|
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
||||||
|
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
selinux_state.enforcing = enforce;
|
selinux_state.enforcing = enforce;
|
||||||
|
#else
|
||||||
|
selinux_enforcing = enforce;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getenforce() {
|
bool getenforce()
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
|
||||||
|
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
|
if (selinux_state.disabled) {
|
||||||
|
#else
|
||||||
|
if (selinux_disabled) {
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
||||||
|
#ifdef KSU_COMPAT_USE_SELINUX_STATE
|
||||||
return selinux_state.enforcing;
|
return selinux_state.enforcing;
|
||||||
#else
|
#else
|
||||||
return false;
|
return selinux_enforcing;
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \
|
||||||
|
!defined(KSU_COMPAT_HAS_CURRENT_SID)
|
||||||
|
/*
|
||||||
|
* get the subjective security ID of the current task
|
||||||
|
*/
|
||||||
|
static inline u32 current_sid(void)
|
||||||
|
{
|
||||||
|
const struct task_security_struct *tsec = current_security();
|
||||||
|
|
||||||
|
return tsec->sid;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool is_ksu_domain()
|
||||||
|
{
|
||||||
|
char *domain;
|
||||||
|
u32 seclen;
|
||||||
|
bool result;
|
||||||
|
int err = security_secid_to_secctx(current_sid(), &domain, &seclen);
|
||||||
|
if (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0;
|
||||||
|
security_release_secctx(domain, seclen);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_zygote(void *sec)
|
||||||
|
{
|
||||||
|
struct task_security_struct *tsec = (struct task_security_struct *)sec;
|
||||||
|
if (!tsec) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char *domain;
|
||||||
|
u32 seclen;
|
||||||
|
bool result;
|
||||||
|
int err = security_secid_to_secctx(tsec->sid, &domain, &seclen);
|
||||||
|
if (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result = strncmp("u:r:zygote:s0", domain, seclen) == 0;
|
||||||
|
security_release_secctx(domain, seclen);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,23 @@
|
|||||||
#ifndef __KSU_H_SELINUX
|
#ifndef __KSU_H_SELINUX
|
||||||
#define __KSU_H_SELINUX
|
#define __KSU_H_SELINUX
|
||||||
|
|
||||||
void setup_selinux();
|
#include "linux/types.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || defined(KSU_COMPAT_HAS_SELINUX_STATE)
|
||||||
|
#define KSU_COMPAT_USE_SELINUX_STATE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup_selinux(const char *);
|
||||||
|
|
||||||
void setenforce(bool);
|
void setenforce(bool);
|
||||||
|
|
||||||
bool getenforce();
|
bool getenforce();
|
||||||
|
|
||||||
#endif
|
bool is_ksu_domain();
|
||||||
|
|
||||||
|
bool is_zygote(void *cred);
|
||||||
|
|
||||||
|
void apply_kernelsu_rules();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
1064
kernel/selinux/sepolicy.c
Normal file
1064
kernel/selinux/sepolicy.c
Normal file
File diff suppressed because it is too large
Load Diff
46
kernel/selinux/sepolicy.h
Normal file
46
kernel/selinux/sepolicy.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef __KSU_H_SEPOLICY
|
||||||
|
#define __KSU_H_SEPOLICY
|
||||||
|
|
||||||
|
#include "linux/types.h"
|
||||||
|
|
||||||
|
#include "ss/policydb.h"
|
||||||
|
|
||||||
|
// Operation on types
|
||||||
|
bool ksu_type(struct policydb *db, const char *name, const char *attr);
|
||||||
|
bool ksu_attribute(struct policydb *db, const char *name);
|
||||||
|
bool ksu_permissive(struct policydb *db, const char *type);
|
||||||
|
bool ksu_enforce(struct policydb *db, const char *type);
|
||||||
|
bool ksu_typeattribute(struct policydb *db, const char *type, const char *attr);
|
||||||
|
bool ksu_exists(struct policydb *db, const char *type);
|
||||||
|
|
||||||
|
// Access vector rules
|
||||||
|
bool ksu_allow(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *perm);
|
||||||
|
bool ksu_deny(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *perm);
|
||||||
|
bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *perm);
|
||||||
|
bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *perm);
|
||||||
|
|
||||||
|
// Extended permissions access vector rules
|
||||||
|
bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *range);
|
||||||
|
bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *range);
|
||||||
|
bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *range);
|
||||||
|
|
||||||
|
// Type rules
|
||||||
|
bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *def, const char *obj);
|
||||||
|
bool ksu_type_change(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *def);
|
||||||
|
bool ksu_type_member(struct policydb *db, const char *src, const char *tgt,
|
||||||
|
const char *cls, const char *def);
|
||||||
|
|
||||||
|
// File system labeling
|
||||||
|
bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path,
|
||||||
|
const char *ctx);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,19 +1,50 @@
|
|||||||
#! /bin/bash
|
#!/bin/sh
|
||||||
|
set -eux
|
||||||
set -x
|
|
||||||
|
|
||||||
git clone https://github.com/tiann/KernelSU
|
|
||||||
|
|
||||||
GKI_ROOT=$(pwd)
|
GKI_ROOT=$(pwd)
|
||||||
|
|
||||||
echo "[+] GKI_ROOT: $GKI_ROOT"
|
echo "[+] GKI_ROOT: $GKI_ROOT"
|
||||||
echo "[+] Copy kernel su driver to $GKI_ROOT/common/drivers"
|
|
||||||
|
|
||||||
ln -sf $(pwd)/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
|
if test -d "$GKI_ROOT/common/drivers"; then
|
||||||
|
DRIVER_DIR="$GKI_ROOT/common/drivers"
|
||||||
|
elif test -d "$GKI_ROOT/drivers"; then
|
||||||
|
DRIVER_DIR="$GKI_ROOT/drivers"
|
||||||
|
else
|
||||||
|
echo '[ERROR] "drivers/" directory is not found.'
|
||||||
|
echo '[+] You should modify this script by yourself.'
|
||||||
|
exit 127
|
||||||
|
fi
|
||||||
|
|
||||||
echo "[+] Add kernel su driver to Makefile"
|
test -d "$GKI_ROOT/KernelSU" || git clone https://github.com/tiann/KernelSU
|
||||||
|
cd "$GKI_ROOT/KernelSU"
|
||||||
|
git stash
|
||||||
|
if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then
|
||||||
|
git checkout main
|
||||||
|
fi
|
||||||
|
git pull
|
||||||
|
if [ -z "${1-}" ]; then
|
||||||
|
git checkout "$(git describe --abbrev=0 --tags)"
|
||||||
|
else
|
||||||
|
git checkout "$1"
|
||||||
|
fi
|
||||||
|
cd "$GKI_ROOT"
|
||||||
|
|
||||||
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
|
echo "[+] GKI_ROOT: $GKI_ROOT"
|
||||||
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
|
echo "[+] Copy kernel su driver to $DRIVER_DIR"
|
||||||
|
|
||||||
echo "[+] Done."
|
cd "$DRIVER_DIR"
|
||||||
|
if test -d "$GKI_ROOT/common/drivers"; then
|
||||||
|
ln -sf "../../KernelSU/kernel" "kernelsu"
|
||||||
|
elif test -d "$GKI_ROOT/drivers"; then
|
||||||
|
ln -sf "../KernelSU/kernel" "kernelsu"
|
||||||
|
fi
|
||||||
|
cd "$GKI_ROOT"
|
||||||
|
|
||||||
|
echo '[+] Add kernel su driver to Makefile'
|
||||||
|
|
||||||
|
DRIVER_MAKEFILE=$DRIVER_DIR/Makefile
|
||||||
|
DRIVER_KCONFIG=$DRIVER_DIR/Kconfig
|
||||||
|
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
|
||||||
|
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
|
||||||
|
|
||||||
|
echo '[+] Done.'
|
||||||
|
|||||||
@@ -1,139 +1,213 @@
|
|||||||
|
#include "asm/current.h"
|
||||||
|
#include "linux/cred.h"
|
||||||
|
#include "linux/err.h"
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/kprobes.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/uaccess.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
|
#include "linux/sched/task_stack.h"
|
||||||
|
#else
|
||||||
|
#include "linux/sched.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <linux/cpu.h>
|
|
||||||
#include <linux/memory.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kprobes.h>
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <asm-generic/errno-base.h>
|
|
||||||
|
|
||||||
#include <linux/rcupdate.h>
|
|
||||||
#include <linux/fdtable.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/fs_struct.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
|
|
||||||
#include "klog.h"
|
|
||||||
#include "arch.h"
|
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
|
#include "arch.h"
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "ksud.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
#define SU_PATH "/system/bin/su"
|
#define SU_PATH "/system/bin/su"
|
||||||
#define SH_PATH "/system/bin/sh"
|
#define SH_PATH "/system/bin/sh"
|
||||||
|
|
||||||
extern void escape_to_root(bool);
|
extern void escape_to_root();
|
||||||
|
|
||||||
static void __user *userspace_stack_buffer(const void *d, size_t len) {
|
static void __user *userspace_stack_buffer(const void *d, size_t len)
|
||||||
/* To avoid having to mmap a page in userspace, just write below the stack pointer. */
|
{
|
||||||
|
/* To avoid having to mmap a page in userspace, just write below the stack
|
||||||
|
* pointer. */
|
||||||
char __user *p = (void __user *)current_user_stack_pointer() - len;
|
char __user *p = (void __user *)current_user_stack_pointer() - len;
|
||||||
|
|
||||||
return copy_to_user(p, d, len) ? NULL : p;
|
return copy_to_user(p, d, len) ? NULL : p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char __user *sh_user_path(void) {
|
static char __user *sh_user_path(void)
|
||||||
|
{
|
||||||
static const char sh_path[] = "/system/bin/sh";
|
static const char sh_path[] = "/system/bin/sh";
|
||||||
|
|
||||||
return userspace_stack_buffer(sh_path, sizeof(sh_path));
|
return userspace_stack_buffer(sh_path, sizeof(sh_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs) {
|
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||||
struct filename* filename;
|
int *flags)
|
||||||
const char su[] = SU_PATH;
|
{
|
||||||
|
const char su[] = SU_PATH;
|
||||||
|
|
||||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = getname(PT_REGS_PARM2(regs));
|
char path[sizeof(su) + 1];
|
||||||
|
memset(path, 0, sizeof(path));
|
||||||
|
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||||
|
|
||||||
if (IS_ERR(filename)) {
|
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
||||||
return 0;
|
pr_info("faccessat su->sh!\n");
|
||||||
}
|
*filename_user = sh_user_path();
|
||||||
if (!memcmp(filename->name, su, sizeof(su))) {
|
}
|
||||||
pr_info("faccessat su->sh!\n");
|
|
||||||
PT_REGS_PARM2(regs) = sh_user_path();
|
|
||||||
}
|
|
||||||
|
|
||||||
putname(filename);
|
return 0;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs) {
|
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
|
||||||
// const char sh[] = SH_PATH;
|
{
|
||||||
struct filename* filename;
|
// const char sh[] = SH_PATH;
|
||||||
const char su[] = SU_PATH;
|
const char su[] = SU_PATH;
|
||||||
|
|
||||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = getname(PT_REGS_PARM2(regs));
|
if (unlikely(!filename_user)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ERR(filename)) {
|
char path[sizeof(su) + 1];
|
||||||
return 0;
|
memset(path, 0, sizeof(path));
|
||||||
}
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
|
||||||
if (!memcmp(filename->name, su, sizeof(su))) {
|
// it becomes a `struct filename *` after 5.18
|
||||||
pr_info("newfstatat su->sh!\n");
|
// https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216
|
||||||
PT_REGS_PARM2(regs) = sh_user_path();
|
const char sh[] = SH_PATH;
|
||||||
}
|
struct filename *filename = * ((struct filename **) filename_user);
|
||||||
|
if (IS_ERR(filename)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (likely(memcmp(filename->name, su, sizeof(su))))
|
||||||
|
return 0;
|
||||||
|
pr_info("vfs_statx su->sh!\n");
|
||||||
|
memcpy((void *)filename->name, sh, sizeof(sh));
|
||||||
|
#else
|
||||||
|
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||||
|
|
||||||
putname(filename);
|
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
||||||
|
pr_info("newfstatat su->sh!\n");
|
||||||
|
*filename_user = sh_user_path();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code
|
||||||
|
int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||||
|
void *__never_use_argv, void *__never_use_envp, int *__never_use_flags)
|
||||||
|
{
|
||||||
|
struct filename *filename;
|
||||||
|
const char sh[] = KSUD_PATH;
|
||||||
|
const char su[] = SU_PATH;
|
||||||
|
|
||||||
|
if (unlikely(!filename_ptr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
filename = *filename_ptr;
|
||||||
|
if (IS_ERR(filename)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likely(memcmp(filename->name, su, sizeof(su))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!ksu_is_allow_uid(current_uid().val))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pr_info("do_execveat_common su found\n");
|
||||||
|
memcpy((void *)filename->name, sh, sizeof(sh));
|
||||||
|
|
||||||
|
escape_to_root();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
|
||||||
|
static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int *dfd = (int *)PT_REGS_PARM1(regs);
|
||||||
|
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
|
||||||
|
int *mode = (int *)&PT_REGS_PARM3(regs);
|
||||||
|
// Both sys_ and do_ is C function
|
||||||
|
int *flags = (int *)&PT_REGS_CCALL_PARM4(regs);
|
||||||
|
|
||||||
|
return ksu_handle_faccessat(dfd, filename_user, mode, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int *dfd = (int *)&PT_REGS_PARM1(regs);
|
||||||
|
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
|
// static int vfs_statx(int dfd, const char __user *filename, int flags, struct kstat *stat, u32 request_mask)
|
||||||
|
int *flags = (int *)&PT_REGS_PARM3(regs);
|
||||||
|
#else
|
||||||
|
// int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,int flag)
|
||||||
|
int *flags = (int *)&PT_REGS_CCALL_PARM4(regs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ksu_handle_stat(dfd, filename_user, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
|
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
|
||||||
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) {
|
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
struct filename* filename;
|
{
|
||||||
const char sh[] = SH_PATH;
|
int *fd = (int *)&PT_REGS_PARM1(regs);
|
||||||
const char su[] = SU_PATH;
|
struct filename **filename_ptr =
|
||||||
|
(struct filename **)&PT_REGS_PARM2(regs);
|
||||||
|
|
||||||
if (!ksu_is_allow_uid(current_uid().val)) {
|
return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = PT_REGS_PARM2(regs);
|
|
||||||
if (IS_ERR(filename)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(filename->name, su, sizeof(su))) {
|
|
||||||
pr_info("do_execveat_common su found\n");
|
|
||||||
memcpy((void*) filename->name, sh, sizeof(sh));
|
|
||||||
|
|
||||||
escape_to_root(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kprobe faccessat_kp = {
|
static struct kprobe faccessat_kp = {
|
||||||
.symbol_name = "do_faccessat",
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
|
||||||
.pre_handler = faccessat_handler_pre,
|
.symbol_name = "do_faccessat",
|
||||||
|
#else
|
||||||
|
.symbol_name = "sys_faccessat",
|
||||||
|
#endif
|
||||||
|
.pre_handler = faccessat_handler_pre,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct kprobe newfstatat_kp = {
|
static struct kprobe newfstatat_kp = {
|
||||||
.symbol_name = "vfs_statx",
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
.pre_handler = newfstatat_handler_pre,
|
.symbol_name = "vfs_statx",
|
||||||
|
#else
|
||||||
|
.symbol_name = "vfs_fstatat",
|
||||||
|
#endif
|
||||||
|
.pre_handler = newfstatat_handler_pre,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct kprobe execve_kp = {
|
static struct kprobe execve_kp = {
|
||||||
.symbol_name = "do_execveat_common",
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
|
||||||
.pre_handler = execve_handler_pre,
|
.symbol_name = "do_execveat_common",
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
|
||||||
|
.symbol_name = "__do_execve_file",
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
|
||||||
|
.symbol_name = "do_execveat_common",
|
||||||
|
#endif
|
||||||
|
.pre_handler = execve_handler_pre,
|
||||||
};
|
};
|
||||||
|
|
||||||
// sucompat: permited process can execute 'su' to gain root access.
|
#endif
|
||||||
void enable_sucompat() {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = register_kprobe(&execve_kp);
|
// sucompat: permited process can execute 'su' to gain root access.
|
||||||
pr_info("execve_kp: %d\n", ret);
|
void ksu_enable_sucompat()
|
||||||
ret = register_kprobe(&newfstatat_kp);
|
{
|
||||||
pr_info("newfstatat_kp: %d\n", ret);
|
#ifdef CONFIG_KPROBES
|
||||||
ret = register_kprobe(&faccessat_kp);
|
int ret;
|
||||||
pr_info("faccessat_kp: %d\n", ret);
|
ret = register_kprobe(&execve_kp);
|
||||||
}
|
pr_info("sucompat: execve_kp: %d\n", ret);
|
||||||
|
ret = register_kprobe(&newfstatat_kp);
|
||||||
|
pr_info("sucompat: newfstatat_kp: %d\n", ret);
|
||||||
|
ret = register_kprobe(&faccessat_kp);
|
||||||
|
pr_info("sucompat: faccessat_kp: %d\n", ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
144
kernel/uid_observer.c
Normal file
144
kernel/uid_observer.c
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
#include "linux/err.h"
|
||||||
|
#include "linux/fs.h"
|
||||||
|
#include "linux/list.h"
|
||||||
|
#include "linux/slab.h"
|
||||||
|
#include "linux/string.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
#include "linux/workqueue.h"
|
||||||
|
|
||||||
|
#include "allowlist.h"
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "ksu.h"
|
||||||
|
#include "manager.h"
|
||||||
|
#include "uid_observer.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
|
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
|
||||||
|
static struct work_struct ksu_update_uid_work;
|
||||||
|
|
||||||
|
struct uid_data {
|
||||||
|
struct list_head list;
|
||||||
|
u32 uid;
|
||||||
|
char package[KSU_MAX_PACKAGE_NAME];
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool is_uid_exist(uid_t uid, char *package, void *data)
|
||||||
|
{
|
||||||
|
struct list_head *list = (struct list_head *)data;
|
||||||
|
struct uid_data *np;
|
||||||
|
|
||||||
|
bool exist = false;
|
||||||
|
list_for_each_entry (np, list, list) {
|
||||||
|
if (np->uid == uid % 100000 &&
|
||||||
|
strncmp(np->package, package, KSU_MAX_PACKAGE_NAME) == 0) {
|
||||||
|
exist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exist;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_update_uid(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct file *fp =
|
||||||
|
ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
|
||||||
|
if (IS_ERR(fp)) {
|
||||||
|
pr_err("do_update_uid, open " SYSTEM_PACKAGES_LIST_PATH
|
||||||
|
" failed: %ld\n",
|
||||||
|
PTR_ERR(fp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct list_head uid_list;
|
||||||
|
INIT_LIST_HEAD(&uid_list);
|
||||||
|
|
||||||
|
char chr = 0;
|
||||||
|
loff_t pos = 0;
|
||||||
|
loff_t line_start = 0;
|
||||||
|
char buf[KSU_MAX_PACKAGE_NAME];
|
||||||
|
for (;;) {
|
||||||
|
ssize_t count =
|
||||||
|
ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos);
|
||||||
|
if (count != sizeof(chr))
|
||||||
|
break;
|
||||||
|
if (chr != '\n')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
count = ksu_kernel_read_compat(fp, buf, sizeof(buf),
|
||||||
|
&line_start);
|
||||||
|
|
||||||
|
struct uid_data *data =
|
||||||
|
kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
|
||||||
|
if (!data) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tmp = buf;
|
||||||
|
const char *delim = " ";
|
||||||
|
char *package = strsep(&tmp, delim);
|
||||||
|
char *uid = strsep(&tmp, delim);
|
||||||
|
if (!uid || !package) {
|
||||||
|
pr_err("update_uid: package or uid is NULL!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 res;
|
||||||
|
if (kstrtou32(uid, 10, &res)) {
|
||||||
|
pr_err("update_uid: uid parse err\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data->uid = res;
|
||||||
|
strncpy(data->package, package, KSU_MAX_PACKAGE_NAME);
|
||||||
|
list_add_tail(&data->list, &uid_list);
|
||||||
|
// reset line start
|
||||||
|
line_start = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now update uid list
|
||||||
|
struct uid_data *np;
|
||||||
|
struct uid_data *n;
|
||||||
|
|
||||||
|
// first, check if manager_uid exist!
|
||||||
|
bool manager_exist = false;
|
||||||
|
list_for_each_entry (np, &uid_list, list) {
|
||||||
|
// if manager is installed in work profile, the uid in packages.list is still equals main profile
|
||||||
|
// don't delete it in this case!
|
||||||
|
int manager_uid = ksu_get_manager_uid() % 100000;
|
||||||
|
if (np->uid == manager_uid) {
|
||||||
|
manager_exist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!manager_exist && ksu_is_manager_uid_valid()) {
|
||||||
|
pr_info("manager is uninstalled, invalidate it!\n");
|
||||||
|
ksu_invalidate_manager_uid();
|
||||||
|
}
|
||||||
|
|
||||||
|
// then prune the allowlist
|
||||||
|
ksu_prune_allowlist(is_uid_exist, &uid_list);
|
||||||
|
out:
|
||||||
|
// free uid_list
|
||||||
|
list_for_each_entry_safe (np, n, &uid_list, list) {
|
||||||
|
list_del(&np->list);
|
||||||
|
kfree(np);
|
||||||
|
}
|
||||||
|
filp_close(fp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_uid()
|
||||||
|
{
|
||||||
|
ksu_queue_work(&ksu_update_uid_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_uid_observer_init()
|
||||||
|
{
|
||||||
|
INIT_WORK(&ksu_update_uid_work, do_update_uid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_uid_observer_exit()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
kernel/uid_observer.h
Normal file
10
kernel/uid_observer.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __KSU_H_UID_OBSERVER
|
||||||
|
#define __KSU_H_UID_OBSERVER
|
||||||
|
|
||||||
|
int ksu_uid_observer_init();
|
||||||
|
|
||||||
|
int ksu_uid_observer_exit();
|
||||||
|
|
||||||
|
void update_uid();
|
||||||
|
|
||||||
|
#endif
|
||||||
18
manager/.gitignore
vendored
18
manager/.gitignore
vendored
@@ -1,15 +1,9 @@
|
|||||||
*.iml
|
*.iml
|
||||||
.gradle
|
.gradle
|
||||||
/local.properties
|
|
||||||
/.idea/caches
|
|
||||||
/.idea/libraries
|
|
||||||
/.idea/modules.xml
|
|
||||||
/.idea/workspace.xml
|
|
||||||
/.idea/navEditor.xml
|
|
||||||
/.idea/assetWizardSettings.xml
|
|
||||||
.DS_Store
|
|
||||||
/build
|
|
||||||
/captures
|
|
||||||
.externalNativeBuild
|
|
||||||
.cxx
|
|
||||||
local.properties
|
local.properties
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
build
|
||||||
|
captures
|
||||||
|
.cxx
|
||||||
|
key.jks
|
||||||
|
|||||||
3
manager/.idea/.gitignore
generated
vendored
3
manager/.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
1
manager/.idea/.name
generated
1
manager/.idea/.name
generated
@@ -1 +0,0 @@
|
|||||||
KernelSU
|
|
||||||
6
manager/.idea/compiler.xml
generated
6
manager/.idea/compiler.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<bytecodeTargetLevel target="11" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
21
manager/.idea/gradle.xml
generated
21
manager/.idea/gradle.xml
generated
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="GRADLE" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleHome" value="/usr/local/Cellar/gradle/6.4/libexec" />
|
|
||||||
<option name="gradleJvm" value="11" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
37
manager/.idea/inspectionProfiles/Project_Default.xml
generated
37
manager/.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,37 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="composableFile" value="true" />
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
10
manager/.idea/misc.xml
generated
10
manager/.idea/misc.xml
generated
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
manager/.idea/vcs.xml
generated
6
manager/.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'com.android.application'
|
|
||||||
id 'org.jetbrains.kotlin.android'
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace 'me.weishu.kernelsu'
|
|
||||||
compileSdk 33
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "me.weishu.kernelsu"
|
|
||||||
minSdk 26
|
|
||||||
targetSdk 32
|
|
||||||
versionCode 10013
|
|
||||||
versionName "0.1.3"
|
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
vectorDrawables {
|
|
||||||
useSupportLibrary true
|
|
||||||
}
|
|
||||||
externalNativeBuild {
|
|
||||||
cmake {
|
|
||||||
cppFlags ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
minifyEnabled true
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = '1.8'
|
|
||||||
}
|
|
||||||
buildFeatures {
|
|
||||||
compose true
|
|
||||||
}
|
|
||||||
composeOptions {
|
|
||||||
kotlinCompilerExtensionVersion '1.1.1'
|
|
||||||
}
|
|
||||||
packagingOptions {
|
|
||||||
resources {
|
|
||||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
externalNativeBuild {
|
|
||||||
cmake {
|
|
||||||
path file('src/main/cpp/CMakeLists.txt')
|
|
||||||
version '3.18.1'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
|
|
||||||
implementation 'androidx.core:core-ktx:1.9.0'
|
|
||||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
|
|
||||||
implementation 'androidx.activity:activity-compose:1.6.1'
|
|
||||||
implementation "androidx.compose.ui:ui:$compose_ui_version"
|
|
||||||
implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version"
|
|
||||||
|
|
||||||
implementation "androidx.compose.material3:material3:1.0.1"
|
|
||||||
implementation "androidx.compose.material3:material3-window-size-class:1.0.1"
|
|
||||||
|
|
||||||
def nav_version = "2.5.3"
|
|
||||||
implementation "androidx.navigation:navigation-compose:$nav_version"
|
|
||||||
|
|
||||||
implementation "com.google.accompanist:accompanist-drawablepainter:0.28.0"
|
|
||||||
implementation "com.google.accompanist:accompanist-systemuicontroller:0.28.0"
|
|
||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
|
|
||||||
|
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.2'
|
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
|
||||||
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version"
|
|
||||||
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
|
|
||||||
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
|
|
||||||
}
|
|
||||||
119
manager/app/build.gradle.kts
Normal file
119
manager/app/build.gradle.kts
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.agp.app)
|
||||||
|
alias(libs.plugins.kotlin)
|
||||||
|
alias(libs.plugins.ksp)
|
||||||
|
alias(libs.plugins.lsplugin.apksign)
|
||||||
|
id("kotlin-parcelize")
|
||||||
|
}
|
||||||
|
|
||||||
|
val managerVersionCode: Int by rootProject.extra
|
||||||
|
val managerVersionName: String by rootProject.extra
|
||||||
|
|
||||||
|
apksign {
|
||||||
|
storeFileProperty = "KEYSTORE_FILE"
|
||||||
|
storePasswordProperty = "KEYSTORE_PASSWORD"
|
||||||
|
keyAliasProperty = "KEY_ALIAS"
|
||||||
|
keyPasswordProperty = "KEY_PASSWORD"
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "me.weishu.kernelsu"
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = true
|
||||||
|
isShrinkResources = true
|
||||||
|
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
aidl = true
|
||||||
|
buildConfig = true
|
||||||
|
compose = true
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "17"
|
||||||
|
}
|
||||||
|
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.4.3"
|
||||||
|
}
|
||||||
|
|
||||||
|
packaging {
|
||||||
|
jniLibs {
|
||||||
|
useLegacyPackaging = true
|
||||||
|
}
|
||||||
|
resources {
|
||||||
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path("src/main/cpp/CMakeLists.txt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationVariants.all {
|
||||||
|
outputs.forEach {
|
||||||
|
val output = it as BaseVariantOutputImpl
|
||||||
|
output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk"
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin.sourceSets {
|
||||||
|
getByName(name) {
|
||||||
|
kotlin.srcDir("build/generated/ksp/$name/kotlin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(libs.androidx.activity.compose)
|
||||||
|
implementation(libs.androidx.navigation.compose)
|
||||||
|
|
||||||
|
implementation(platform(libs.androidx.compose.bom))
|
||||||
|
implementation(libs.androidx.compose.material.icons.extended)
|
||||||
|
implementation(libs.androidx.compose.material)
|
||||||
|
implementation(libs.androidx.compose.material3)
|
||||||
|
implementation(libs.androidx.compose.ui)
|
||||||
|
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||||
|
|
||||||
|
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||||
|
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||||
|
|
||||||
|
implementation(libs.androidx.lifecycle.runtime.compose)
|
||||||
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
|
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
||||||
|
|
||||||
|
implementation(libs.com.google.accompanist.drawablepainter)
|
||||||
|
implementation(libs.com.google.accompanist.navigation.animation)
|
||||||
|
implementation(libs.com.google.accompanist.systemuicontroller)
|
||||||
|
implementation(libs.com.google.accompanist.webview)
|
||||||
|
|
||||||
|
implementation(libs.compose.destinations.animations.core)
|
||||||
|
ksp(libs.compose.destinations.ksp)
|
||||||
|
|
||||||
|
implementation(libs.com.github.topjohnwu.libsu.core)
|
||||||
|
implementation(libs.com.github.topjohnwu.libsu.service)
|
||||||
|
implementation(libs.com.github.topjohnwu.libsu.io)
|
||||||
|
|
||||||
|
implementation(libs.dev.rikka.rikkax.parcelablelist)
|
||||||
|
|
||||||
|
implementation(libs.io.coil.kt.coil.compose)
|
||||||
|
|
||||||
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
|
|
||||||
|
implementation(libs.me.zhanghai.android.appiconloader.coil)
|
||||||
|
|
||||||
|
implementation(libs.sheet.compose.dialogs.core)
|
||||||
|
implementation(libs.sheet.compose.dialogs.list)
|
||||||
|
implementation(libs.sheet.compose.dialogs.input)
|
||||||
|
|
||||||
|
implementation(libs.markdown)
|
||||||
|
implementation(libs.androidx.webkit)
|
||||||
|
}
|
||||||
30
manager/app/proguard-rules.pro
vendored
30
manager/app/proguard-rules.pro
vendored
@@ -1,21 +1,9 @@
|
|||||||
# Add project specific ProGuard rules here.
|
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
||||||
# You can control the set of applied configuration files using the
|
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
||||||
# proguardFiles setting in build.gradle.
|
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
|
||||||
#
|
-dontwarn org.conscrypt.Conscrypt$Version
|
||||||
# For more details, see
|
-dontwarn org.conscrypt.Conscrypt
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
-dontwarn org.conscrypt.ConscryptHostnameVerifier
|
||||||
|
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
|
||||||
# If your project uses WebView with JS, uncomment the following
|
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
-dontwarn org.openjsse.net.ssl.OpenJSSE
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Uncomment this to preserve the line number information for
|
|
||||||
# debugging stack traces.
|
|
||||||
#-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
|
||||||
# hide the original source file name.
|
|
||||||
#-renamesourcefileattribute SourceFile
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package me.weishu.kernelsu
|
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
||||||
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumented test, which will execute on an Android device.
|
|
||||||
*
|
|
||||||
* See [testing documentation](http://d.android.com/tools/testing).
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
|
||||||
class ExampleInstrumentedTest {
|
|
||||||
@Test
|
|
||||||
fun useAppContext() {
|
|
||||||
// Context of the app under test.
|
|
||||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
|
||||||
assertEquals("me.weishu.kernelsu", appContext.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,25 +2,23 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<queries>
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<intent>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".KernelSUApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:theme="@style/Theme.KernelSU"
|
android:theme="@style/Theme.KernelSU"
|
||||||
tools:targetApi="31">
|
tools:targetApi="33">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".ui.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/Theme.KernelSU">
|
android:theme="@style/Theme.KernelSU">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@@ -32,6 +30,16 @@
|
|||||||
android:name="android.app.lib_name"
|
android:name="android.app.lib_name"
|
||||||
android:value="" />
|
android:value="" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/filepaths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// IKsuInterface.aidl
|
||||||
|
package me.weishu.kernelsu;
|
||||||
|
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import rikka.parcelablelist.ParcelableListSlice;
|
||||||
|
|
||||||
|
interface IKsuInterface {
|
||||||
|
ParcelableListSlice<PackageInfo> getPackages(int flags);
|
||||||
|
}
|
||||||
@@ -15,4 +15,4 @@ add_library(kernelsu
|
|||||||
|
|
||||||
find_library(log-lib log)
|
find_library(log-lib log)
|
||||||
|
|
||||||
target_link_libraries(kernelsu ${log-lib})
|
target_link_libraries(kernelsu ${log-lib})
|
||||||
@@ -3,27 +3,31 @@
|
|||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "ksu.h"
|
#include "ksu.h"
|
||||||
|
|
||||||
#define LOG_TAG "KernelSu"
|
#define LOG_TAG "KernelSU"
|
||||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jclass clazz) {
|
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jobject, jstring pkg) {
|
||||||
return become_manager();
|
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
|
||||||
|
auto result = become_manager(cpkg);
|
||||||
|
env->ReleaseStringUTFChars(pkg, cpkg);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jclass clazz) {
|
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jobject) {
|
||||||
return get_version();
|
return get_version();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jintArray JNICALL
|
JNIEXPORT jintArray JNICALL
|
||||||
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jclass clazz) {
|
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jobject) {
|
||||||
int uids[1024];
|
int uids[1024];
|
||||||
int size = 0;
|
int size = 0;
|
||||||
bool result = get_allow_list(uids, &size);
|
bool result = get_allow_list(uids, &size);
|
||||||
@@ -37,24 +41,252 @@ Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jclass clazz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jintArray JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_me_weishu_kernelsu_Natives_getDenyList(JNIEnv *env, jclass clazz) {
|
Java_me_weishu_kernelsu_Natives_isSafeMode(JNIEnv *env, jclass clazz) {
|
||||||
int uids[1024];
|
return is_safe_mode();
|
||||||
int size = 0;
|
}
|
||||||
bool result = get_deny_list(uids, &size);
|
|
||||||
if (result) {
|
static void fillIntArray(JNIEnv *env, jobject list, int *data, int count) {
|
||||||
// success!
|
auto cls = env->GetObjectClass(list);
|
||||||
auto array = env->NewIntArray(size);
|
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
|
||||||
env->SetIntArrayRegion(array, 0, size, uids);
|
auto integerCls = env->FindClass("java/lang/Integer");
|
||||||
return array;
|
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
auto integer = env->NewObject(integerCls, constructor, data[i]);
|
||||||
|
env->CallBooleanMethod(list, add, integer);
|
||||||
}
|
}
|
||||||
return env->NewIntArray(0);
|
}
|
||||||
|
|
||||||
|
static void addIntToList(JNIEnv *env, jobject list, int ele) {
|
||||||
|
auto cls = env->GetObjectClass(list);
|
||||||
|
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
|
||||||
|
auto integerCls = env->FindClass("java/lang/Integer");
|
||||||
|
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
|
||||||
|
auto integer = env->NewObject(integerCls, constructor, ele);
|
||||||
|
env->CallBooleanMethod(list, add, integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t capListToBits(JNIEnv *env, jobject list) {
|
||||||
|
auto cls = env->GetObjectClass(list);
|
||||||
|
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
|
||||||
|
auto size = env->GetMethodID(cls, "size", "()I");
|
||||||
|
auto listSize = env->CallIntMethod(list, size);
|
||||||
|
auto integerCls = env->FindClass("java/lang/Integer");
|
||||||
|
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
|
||||||
|
uint64_t result = 0;
|
||||||
|
for (int i = 0; i < listSize; ++i) {
|
||||||
|
auto integer = env->CallObjectMethod(list, get, i);
|
||||||
|
int data = env->CallIntMethod(integer, intValue);
|
||||||
|
|
||||||
|
if (cap_valid(data)) {
|
||||||
|
result |= (1ULL << data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getListSize(JNIEnv *env, jobject list) {
|
||||||
|
auto cls = env->GetObjectClass(list);
|
||||||
|
auto size = env->GetMethodID(cls, "size", "()I");
|
||||||
|
return env->CallIntMethod(list, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fillArrayWithList(JNIEnv *env, jobject list, int *data, int count) {
|
||||||
|
auto cls = env->GetObjectClass(list);
|
||||||
|
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
|
||||||
|
auto integerCls = env->FindClass("java/lang/Integer");
|
||||||
|
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
auto integer = env->CallObjectMethod(list, get, i);
|
||||||
|
data[i] = env->CallIntMethod(integer, intValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg, jint uid) {
|
||||||
|
if (env->GetStringLength(pkg) > KSU_MAX_PACKAGE_NAME) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_key_t key = {};
|
||||||
|
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
|
||||||
|
strcpy(key, cpkg);
|
||||||
|
env->ReleaseStringUTFChars(pkg, cpkg);
|
||||||
|
|
||||||
|
app_profile profile = {};
|
||||||
|
profile.version = KSU_APP_PROFILE_VER;
|
||||||
|
|
||||||
|
strcpy(profile.key, key);
|
||||||
|
profile.current_uid = uid;
|
||||||
|
|
||||||
|
bool useDefaultProfile = !get_app_profile(key, &profile);
|
||||||
|
|
||||||
|
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
|
||||||
|
auto constructor = env->GetMethodID(cls, "<init>", "()V");
|
||||||
|
auto obj = env->NewObject(cls, constructor);
|
||||||
|
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
|
||||||
|
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
|
||||||
|
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
|
||||||
|
|
||||||
|
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
|
||||||
|
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
|
||||||
|
|
||||||
|
auto uidField = env->GetFieldID(cls, "uid", "I");
|
||||||
|
auto gidField = env->GetFieldID(cls, "gid", "I");
|
||||||
|
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
|
||||||
|
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
||||||
|
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
|
||||||
|
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
|
||||||
|
|
||||||
|
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
|
||||||
|
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
|
||||||
|
|
||||||
|
env->SetObjectField(obj, keyField, env->NewStringUTF(profile.key));
|
||||||
|
env->SetIntField(obj, currentUidField, profile.current_uid);
|
||||||
|
|
||||||
|
if (useDefaultProfile) {
|
||||||
|
// no profile found, so just use default profile:
|
||||||
|
// don't allow root and use default profile!
|
||||||
|
LOGD("use default profile for: %s, %d", key, uid);
|
||||||
|
|
||||||
|
// allow_su = false
|
||||||
|
// non root use default = true
|
||||||
|
env->SetBooleanField(obj, allowSuField, false);
|
||||||
|
env->SetBooleanField(obj, nonRootUseDefaultField, true);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto allowSu = profile.allow_su;
|
||||||
|
|
||||||
|
if (allowSu) {
|
||||||
|
env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default);
|
||||||
|
if (strlen(profile.rp_config.template_name) > 0) {
|
||||||
|
env->SetObjectField(obj, rootTemplateField,
|
||||||
|
env->NewStringUTF(profile.rp_config.template_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
env->SetIntField(obj, uidField, profile.rp_config.profile.uid);
|
||||||
|
env->SetIntField(obj, gidField, profile.rp_config.profile.gid);
|
||||||
|
|
||||||
|
jobject groupList = env->GetObjectField(obj, groupsField);
|
||||||
|
int groupCount = profile.rp_config.profile.groups_count;
|
||||||
|
if (groupCount > KSU_MAX_GROUPS) {
|
||||||
|
LOGD("kernel group count too large: %d???", groupCount);
|
||||||
|
groupCount = KSU_MAX_GROUPS;
|
||||||
|
}
|
||||||
|
fillIntArray(env, groupList, profile.rp_config.profile.groups, groupCount);
|
||||||
|
|
||||||
|
jobject capList = env->GetObjectField(obj, capabilitiesField);
|
||||||
|
for (int i = 0; i <= CAP_LAST_CAP; i++) {
|
||||||
|
if (profile.rp_config.profile.capabilities.effective & (1ULL << i)) {
|
||||||
|
addIntToList(env, capList, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
env->SetObjectField(obj, domainField,
|
||||||
|
env->NewStringUTF(profile.rp_config.profile.selinux_domain));
|
||||||
|
env->SetIntField(obj, namespacesField, profile.rp_config.profile.namespaces);
|
||||||
|
env->SetBooleanField(obj, allowSuField, profile.allow_su);
|
||||||
|
} else {
|
||||||
|
env->SetBooleanField(obj, nonRootUseDefaultField,
|
||||||
|
(jboolean) profile.nrp_config.use_default);
|
||||||
|
env->SetBooleanField(obj, umountModulesField, profile.nrp_config.profile.umount_modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_me_weishu_kernelsu_Natives_allowRoot(JNIEnv *env, jclass clazz, jint uid, jboolean allow) {
|
Java_me_weishu_kernelsu_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobject profile) {
|
||||||
return allow_su(uid, allow);
|
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
|
||||||
|
|
||||||
|
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
|
||||||
|
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
|
||||||
|
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
|
||||||
|
|
||||||
|
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
|
||||||
|
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
|
||||||
|
|
||||||
|
auto uidField = env->GetFieldID(cls, "uid", "I");
|
||||||
|
auto gidField = env->GetFieldID(cls, "gid", "I");
|
||||||
|
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
|
||||||
|
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
||||||
|
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
|
||||||
|
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
|
||||||
|
|
||||||
|
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
|
||||||
|
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
|
||||||
|
|
||||||
|
auto key = env->GetObjectField(profile, keyField);
|
||||||
|
if (!key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (env->GetStringLength((jstring) key) > KSU_MAX_PACKAGE_NAME) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cpkg = env->GetStringUTFChars((jstring) key, nullptr);
|
||||||
|
p_key_t p_key = {};
|
||||||
|
strcpy(p_key, cpkg);
|
||||||
|
env->ReleaseStringUTFChars((jstring) key, cpkg);
|
||||||
|
|
||||||
|
auto currentUid = env->GetIntField(profile, currentUidField);
|
||||||
|
|
||||||
|
auto uid = env->GetIntField(profile, uidField);
|
||||||
|
auto gid = env->GetIntField(profile, gidField);
|
||||||
|
auto groups = env->GetObjectField(profile, groupsField);
|
||||||
|
auto capabilities = env->GetObjectField(profile, capabilitiesField);
|
||||||
|
auto domain = env->GetObjectField(profile, domainField);
|
||||||
|
auto allowSu = env->GetBooleanField(profile, allowSuField);
|
||||||
|
auto umountModules = env->GetBooleanField(profile, umountModulesField);
|
||||||
|
|
||||||
|
app_profile p = {};
|
||||||
|
p.version = KSU_APP_PROFILE_VER;
|
||||||
|
|
||||||
|
strcpy(p.key, p_key);
|
||||||
|
p.allow_su = allowSu;
|
||||||
|
p.current_uid = currentUid;
|
||||||
|
|
||||||
|
if (allowSu) {
|
||||||
|
p.rp_config.use_default = env->GetBooleanField(profile, rootUseDefaultField);
|
||||||
|
auto templateName = env->GetObjectField(profile, rootTemplateField);
|
||||||
|
if (templateName) {
|
||||||
|
auto ctemplateName = env->GetStringUTFChars((jstring) templateName, nullptr);
|
||||||
|
strcpy(p.rp_config.template_name, ctemplateName);
|
||||||
|
env->ReleaseStringUTFChars((jstring) templateName, ctemplateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.rp_config.profile.uid = uid;
|
||||||
|
p.rp_config.profile.gid = gid;
|
||||||
|
|
||||||
|
int groups_count = getListSize(env, groups);
|
||||||
|
if (groups_count > KSU_MAX_GROUPS) {
|
||||||
|
LOGD("groups count too large: %d", groups_count);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
p.rp_config.profile.groups_count = groups_count;
|
||||||
|
fillArrayWithList(env, groups, p.rp_config.profile.groups, groups_count);
|
||||||
|
|
||||||
|
p.rp_config.profile.capabilities.effective = capListToBits(env, capabilities);
|
||||||
|
|
||||||
|
auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr);
|
||||||
|
strcpy(p.rp_config.profile.selinux_domain, cdomain);
|
||||||
|
env->ReleaseStringUTFChars((jstring) domain, cdomain);
|
||||||
|
|
||||||
|
p.rp_config.profile.namespaces = env->GetIntField(profile, namespacesField);
|
||||||
|
} else {
|
||||||
|
p.nrp_config.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
|
||||||
|
p.nrp_config.profile.umount_modules = umountModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set_app_profile(&p);
|
||||||
}
|
}
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_me_weishu_kernelsu_Natives_uidShouldUmount(JNIEnv *env, jobject thiz, jint uid) {
|
||||||
|
return uid_should_umount(uid);
|
||||||
|
}
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "ksu.h"
|
#include "ksu.h"
|
||||||
|
|
||||||
@@ -15,8 +18,15 @@
|
|||||||
#define CMD_GET_VERSION 2
|
#define CMD_GET_VERSION 2
|
||||||
#define CMD_ALLOW_SU 3
|
#define CMD_ALLOW_SU 3
|
||||||
#define CMD_DENY_SU 4
|
#define CMD_DENY_SU 4
|
||||||
#define CMD_GET_ALLOW_LIST 5
|
#define CMD_GET_SU_LIST 5
|
||||||
#define CMD_GET_DENY_LIST 6
|
#define CMD_GET_DENY_LIST 6
|
||||||
|
#define CMD_CHECK_SAFEMODE 9
|
||||||
|
|
||||||
|
#define CMD_GET_APP_PROFILE 10
|
||||||
|
#define CMD_SET_APP_PROFILE 11
|
||||||
|
|
||||||
|
#define CMD_IS_UID_GRANTED_ROOT 12
|
||||||
|
#define CMD_IS_UID_SHOULD_UMOUNT 13
|
||||||
|
|
||||||
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
||||||
int32_t result = 0;
|
int32_t result = 0;
|
||||||
@@ -24,8 +34,17 @@ static bool ksuctl(int cmd, void* arg1, void* arg2) {
|
|||||||
return result == KERNEL_SU_OPTION;
|
return result == KERNEL_SU_OPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool become_manager() {
|
bool become_manager(const char* pkg) {
|
||||||
return ksuctl(CMD_BECOME_MANAGER, nullptr, nullptr);
|
char param[128];
|
||||||
|
uid_t uid = getuid();
|
||||||
|
uint32_t userId = uid / 100000;
|
||||||
|
if (userId == 0) {
|
||||||
|
sprintf(param, "/data/data/%s", pkg);
|
||||||
|
} else {
|
||||||
|
snprintf(param, sizeof(param), "/data/user/%d/%s", userId, pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ksuctl(CMD_BECOME_MANAGER, param, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_version() {
|
int get_version() {
|
||||||
@@ -36,15 +55,23 @@ int get_version() {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allow_su(int uid, bool allow) {
|
|
||||||
int cmd = allow ? CMD_ALLOW_SU : CMD_DENY_SU;
|
|
||||||
return ksuctl(cmd, (void*) uid, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_allow_list(int *uids, int *size) {
|
bool get_allow_list(int *uids, int *size) {
|
||||||
return ksuctl(CMD_GET_ALLOW_LIST, uids, size);
|
return ksuctl(CMD_GET_SU_LIST, uids, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_deny_list(int *uids, int *size) {
|
bool is_safe_mode() {
|
||||||
return ksuctl(CMD_GET_DENY_LIST, uids, size);
|
return ksuctl(CMD_CHECK_SAFEMODE, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool uid_should_umount(int uid) {
|
||||||
|
bool should;
|
||||||
|
return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, reinterpret_cast<void*>(uid), &should) && should;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_app_profile(const app_profile *profile) {
|
||||||
|
return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_app_profile(p_key_t key, app_profile *profile) {
|
||||||
|
return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr);
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user