Skip to content

Commit 595eefc

Browse files
committed
Use a real root 'whoami' test script when detecting root via ADB
The old old test command was just 'whoami', which works for the basics, but doesn't confirm whether quotes around multi-part commands are required or required-missing, which matters in some niche cases. The fix for that was 'sh -c whoami' but it turns out that seems to fails in some cases equivalent to 'su root sh -c whoami' because the -c is consumed by the 'su' rather than 'sh', and then subsequent commands don't seem to behave as expected. The new fix is to push and run a script with 'sh $script' which should be much more effective, primarily because that's exactly what most of the subsequent root-powered commands need to be able to do anyway.
1 parent 57d024f commit 595eefc

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

src/interceptors/android/adb-commands.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,27 @@ const runAsRootCommands = [
164164
type RootCmd = (...cmd: string[]) => string[];
165165

166166
export async function getRootCommand(adbClient: Adb.DeviceClient): Promise<RootCmd | undefined> {
167-
// Run whoami with each of the possible root commands
167+
// Just running 'whoami' doesn't fully check certain tricky cases around how the root commands
168+
// handle multiple arguments etc. Pushing & running this script is an accurate test of which
169+
// root mechanisms will actually work on this device:
170+
const rootTestScriptPath = `${ANDROID_TEMP}/htk-root-test.sh`;
171+
let rootTestCommand = ['sh', rootTestScriptPath];
172+
try {
173+
await pushFile(adbClient, stringAsStream(`
174+
set -e # Fail on error
175+
whoami # Log the current user name, to confirm if we're root
176+
`), rootTestScriptPath, 0o444);
177+
} catch (e) {
178+
console.log(`Couldn't write root test script to ${rootTestScriptPath}`, e);
179+
// Ok, so we can't write the test script, but let's still test for root via whoami directly,
180+
// because maybe if we get root then that won't be a problem
181+
rootTestCommand = ['whoami'];
182+
}
183+
184+
// Run our whoami script with each of the possible root commands
168185
const rootCheckResults = await Promise.all(
169186
runAsRootCommands.map((runAsRoot) =>
170-
run(adbClient, runAsRoot('sh', '-c', 'whoami'), { timeout: 1000 }).catch(console.log)
187+
run(adbClient, runAsRoot(...rootTestCommand), { timeout: 1000 }).catch(console.log)
171188
.then((whoami) => ({ cmd: runAsRoot, whoami }))
172189
)
173190
)
@@ -192,7 +209,7 @@ export async function getRootCommand(adbClient: Adb.DeviceClient): Promise<RootC
192209

193210
await delay(500); // Wait, since they may not disconnect immediately
194211
const whoami = await waitUntil(250, 10, (): Promise<string | false> => {
195-
return run(adbClient, ['whoami'], { timeout: 1000 }).catch(() => false)
212+
return run(adbClient, rootTestCommand, { timeout: 1000 }).catch(() => false)
196213
}).catch(console.log);
197214

198215
return (whoami || '').trim() === 'root'

0 commit comments

Comments
 (0)