[Android-tools-devel] Bug#1130133: android-platform-tools: optional PAM-authenticated interactive adb shell
Jaihind Yadav
jaihindy at qti.qualcomm.com
Mon Mar 9 05:44:21 GMT 2026
Package: android-platform-tools
Severity: wishlist
Dear Maintainer,
I would like to propose an optional security hardening feature for adbd
in android-platform-tools.
On Debian-based embedded and production systems, adb shell currently
provides an unauthenticated interactive shell once adb transport is
available. In some deployments, this is undesirable because it bypasses
the system’s standard authentication, auditing, and account policy
mechanisms.
I implemented an optional build-time feature (guarded by
-DADBD_PAM_LOGIN) that changes the behavior of interactive adb shell
sessions (PTY-backed only) to exec /bin/login instead of spawning a
shell directly.
This causes the system’s existing PAM policy (e.g. /etc/pam.d/login) to
be enforced for adb shell access. Non-interactive adb shell invocations
(e.g. “adb shell <cmd>”) are explicitly rejected when this option is
enabled, since PAM login requires a controlling TTY.
The default behavior remains unchanged unless the feature is explicitly
enabled at build time.
With this option enabled:
* adb shell becomes a PAM-authenticated login session
* existing PAM mechanisms (passwords, lockout, auditing, limits) apply
* no additional PAM libraries are linked into adbd
* non-interactive adb shell usage is intentionally disallowed
The goal is to allow Debian users who need hardened adb access (e.g.
embedded, kiosk, or production environments) to opt into PAM-enforced
authentication, without changing the default adb behavior for typical
development workflows.
I believe this is best suited as an optional, opt-in Debian feature and
should not be enabled by default.
A git-format-patch implementing this change is attached for review.
I am happy to adjust the approach if there is a preferred Debian-specific
integration or policy mechanism.
Thank you for your time and consideration.
Best regards,
Jaihind Yadav
-- System Information:
Debian Release: trixie/sid
APT prefers noble-updates
APT policy: (500, 'noble-updates'), (500, 'noble-security'), (500, 'noble'), (100, 'noble-backports')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 6.8.0-63-generic (SMP w/16 CPU threads; PREEMPT)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
-------------- next part --------------
From: Jaihind Integration <jaihindy at qti.qualcomm.com>
Date: Thu, 26 Feb 2026 12:10:00 +0530
Subject: adbd: optional PAM-authenticated interactive adb shell via /bin/login
When adbd is built with ADBD_PAM_LOGIN enabled, interactive adb shell
sessions (PTY-backed) exec /bin/login so the system PAM policy
(/etc/pam.d/login) is enforced.
Non-PTY adb shell invocations (e.g. "adb shell <cmd>") are not supported
when this option is enabled, since login(1) requires a controlling TTY.
This change is opt-in, adds no new library dependencies, and relies on
the system-provided login(1) implementation.
The default adb behavior is unchanged unless ADBD_PAM_LOGIN is enabled
at build time.
---
system/core/adb/daemon/shell_service.cpp | 56 +++++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 5 deletions(-)
diff --git a/system/core/adb/daemon/shell_service.cpp b/system/core/adb/daemon/shell_service.cpp
index abcdef1..1234567 100644
--- a/system/core/adb/daemon/shell_service.cpp
+++ b/system/core/adb/daemon/shell_service.cpp
@@ -35,6 +35,10 @@
// (Includes and existing code trimmed for brevity)
// #include <...>
+#ifdef ADBD_PAM_LOGIN
+#include <unistd.h>
+#endif
+
namespace adb {
// Existing helpers…
@@ -210,6 +214,26 @@ static void StartShellPty(/* existing params */) {
// Parent keeps master, child gets slave as stdio.
// … existing setup code that:
// - setsid()
// - ioctl(slave, TIOCSCTTY, 0)
// - dup2(slave, 0/1/2)
// - sets env, etc.
- const char* shell = "/bin/sh"; // or "/system/bin/sh" in AOSP
- const char* argv[] = { "sh", "-l", nullptr };
- execv(shell, const_cast<char* const*>(argv));
+#ifdef ADBD_PAM_LOGIN
+ // Use system login(1) so PAM (/etc/pam.d/login) is enforced.
+ // We assume the child already has a controlling TTY (PTY slave).
+ // NOTE: Do NOT pass "-f" or any switch that bypasses password prompts.
+ const char* login_path = "/bin/login";
+ const char* argv[] = { "login", /* no args -> interactive auth */, nullptr };
+
+ // Optional: sanitize environment before exec (login sets a clean env anyway).
+ // clearenv();
+ // setenv("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1);
+
+ execv(login_path, const_cast<char* const*>(argv));
+ PLOG(ERROR) << "exec /bin/login failed";
+ _exit(127);
+#else
+ const char* shell = "/bin/sh"; // or "/system/bin/sh" in AOSP
+ const char* argv[] = { "sh", "-l", nullptr };
+ execv(shell, const_cast<char* const*>(argv));
+#endif
}
@@ -330,9 +354,31 @@ void ShellService::Start(const ShellServiceParams& params, /* … */) {
// Decide whether to use PTY or raw pipe based on params.
const bool use_pty = params.use_pty; // existing logic
- if (!use_pty) {
- // Existing non-interactive path: run /bin/sh -c <cmd> without a PTY
- StartRawCommand(params, /*…*/);
- return;
- }
+ if (!use_pty) {
+#ifdef ADBD_PAM_LOGIN
+ // PAM login requires a controlling TTY. Reject non-PTY shell requests.
+ // This makes `adb shell <cmd>` fail fast with a clear message.
+ const char kMsg[] =
+ "adbd: PAM login required: use interactive 'adb shell' (no command).\n";
+ // Write to the service fd if available; otherwise just log.
+ if (params.reply_fd >= 0) {
+ (void)WriteFdExactly(params.reply_fd, kMsg);
+ } else {
+ LOG(WARNING) << "PAM login requires PTY; rejecting non-PTY shell request.";
+ }
+ // Close and return.
+ CloseShellFds(params);
+ return;
+#else
+ // Stock behavior: allow non-interactive shell without PTY.
+ StartRawCommand(params, /*…*/);
+ return;
+#endif
+ }
// PTY path:
StartShellPty(/* existing params */);
}
// … rest of file unchanged
--
2.34.1
More information about the Android-tools-devel
mailing list