feat: Interactive User Confirmation for Privilege Escalation#64
Conversation
…tion Adds require_confirmation to pam_config to prevent silent privilege escalation by background scripts. Requires interactive user confirmation (e.g. <Enter>) to proceed with facial authentication for non-exempt services.
Modernizes codebase by using std::exchange, UniqueFd for RAII, and std::filesystem. Extends unit tests to 100% coverage for hardware modules including HardwareManager, Ite8353Parser, PresenceTripwire, ScopedWorker, and SensorFactory.
…ion instructions for interactive confirmation Documents the new require_confirmation configuration option, updates security analysis with new threat vectors regarding silent privilege escalation, and updates README with usage instructions for the interactive confirmation prompt.
|
Hey @techhotspot, |
|
Sure, want to add me? |
|
you have to accept the collaboration invite for that first. I've sent it just as I've asked you to join. |
…kground sensor initialization, and memory leak fixes
techhotspot
left a comment
There was a problem hiding this comment.
pam_set_item return value ignored
src/pam/pam_linuxcampam.cpp
pam_set_item can fail. If it does you still return PAM_IGNORE, the downstream module never sees the token, and the user gets a silent failure or double-prompt.
if (pam_set_item(pamh, PAM_AUTHTOK, resp_pam[0].resp) != PAM_SUCCESS) {
syslog(LOG_ERR, "Failed to relay password token to PAM stack");
return PAM_AUTH_ERR;
}
return PAM_IGNORE;Unknown service bypasses confirmation
src/pam/pam_linuxcampam.cpp
If pam_get_item(PAM_SERVICE) fails or returns null, the entire confirmation block is skipped and face auth proceeds silently — which is exactly what this feature is trying to prevent. Should default to requiring confirmation and only skip it for positively-identified exempt services.
bool needs_confirmation = true;
const void *service_ptr = nullptr;
if (pam_get_item(pamh, PAM_SERVICE, &service_ptr) == PAM_SUCCESS && service_ptr != nullptr) {
// check exempt list, set needs_confirmation = false if matched
} else {
syslog(LOG_WARNING, "PAM_SERVICE unavailable; applying confirmation prompt as fallback");
}
if (needs_confirmation) { ... }Quoted value silently breaks service matching
src/pam/pam_config.hpp
The commented example in config.ini wraps the value in quotes. If a user copies it verbatim, split() yields "gdm-password with a leading quote and nothing matches. welcome_message already handles this — same fix needed here.
if (auto ces_opt = get_value("confirmation_exempt_services")) {
std::string ces_str = *ces_opt;
if (ces_str.size() >= 2 && ces_str.front() == '"' && ces_str.back() == '"')
ces_str = ces_str.substr(1, ces_str.size() - 2);
config.confirmation_exempt_services = split(ces_str, ',');
}Fixed temp path causes parallel test races
tests/test_hardware_manager.cpp
Two processes in CI will collide on the hardcoded path.
temp_dir_ = fs::temp_directory_path() / ("linuxcampam_hw_test_" + std::to_string(getpid()));
techhotspot
left a comment
There was a problem hiding this comment.
pam_set_item return value ignored
src/pam/pam_linuxcampam.cpp — inside pam_sm_authenticate, password fallback block
pam_set_item can fail. If it does you still return PAM_IGNORE, the downstream module never sees the token, and the user gets a silent failure or double-prompt.
Fix:
if (pam_set_item(pamh, PAM_AUTHTOK, resp_pam[0].resp) != PAM_SUCCESS) {
syslog(LOG_ERR, "Failed to relay password token to PAM stack");
return PAM_AUTH_ERR;
}
return PAM_IGNORE;Unknown service bypasses confirmation
src/pam/pam_linuxcampam.cpp — inside pam_sm_authenticate, require_confirmation block
If pam_get_item(PAM_SERVICE) fails or returns null, the entire confirmation block is skipped and face auth proceeds silently — which is exactly what this feature is trying to prevent. Should default to requiring confirmation and only skip it for positively-identified exempt services.
Fix:
bool needs_confirmation = true;
const void *service_ptr = nullptr;
if (pam_get_item(pamh, PAM_SERVICE, &service_ptr) == PAM_SUCCESS && service_ptr != nullptr) {
// check exempt list, set needs_confirmation = false if matched
} else {
syslog(LOG_WARNING, "PAM_SERVICE unavailable; applying confirmation prompt as fallback");
}
if (needs_confirmation) { ... }
Quoted value silently breaks service matching
src/pam/pam_config.hpp — resolve_pam_config, confirmation_exempt_services parsing
The commented example in config.ini wraps the value in quotes. If a user copies it verbatim, split() yields "gdm-password with a leading quote and nothing matches. welcome_message already handles this — same fix needed here.
Fix:
if (auto ces_opt = get_value("confirmation_exempt_services")) {
std::string ces_str = *ces_opt;
if (ces_str.size() >= 2 && ces_str.front() == '"' && ces_str.back() == '"')
ces_str = ces_str.substr(1, ces_str.size() - 2);
config.confirmation_exempt_services = split(ces_str, ',');
}
Fixed temp path causes parallel test races
tests/test_hardware_manager.cpp — HardwareManagerTest::SetUp
Two processes in CI will collide on the hardcoded path.
Fix:
temp_dir_ = fs::temp_directory_path() / ("linuxcampam_hw_test_" + std::to_string(getpid()));
|
Sorry, didnt mean to post that twice |
…logic, and prevent temporary directory collisions in tests
|
Hey @techhotspot, |
|
@techhotspot Thank you for CR! |
Description
This PR adds an interactive user confirmation prompt (
require_confirmation) for privilege escalation, preventing silent exploitation by background scripts.Behavior Change:
By default,
require_confirmationis now set totrue. This means LinuxCamPAM will no longer silently authenticate for all services upon human presence detection. Instead, for privilege escalation services (likesudoorsu), users will be interactively prompted to press Enter to explicitly confirm authentication.A default whitelist (
confirmation_exempt_services) containinggdm-password,login,sddm,swaylock,kscreenlocker, etc., ensures that screen lockers and display managers continue to authenticate silently as before.It also applies modern C++17 refactorings (such as
std::exchange,UniqueFd, andstd::filesystem) and brings hardware module unit test coverage up to 100%. Relevant security and configuration documentation have been updated accordingly.Closes #62
Type of change
How Has This Been Tested?
Please describe the tests that you ran to verify your changes.
require_confirmationlogic viapam_testerto ensure interactive prompt blocks background tasks while authenticating interactive tasks when configured.test_hardware_manager.cpp,test_ite8353_parser.cpp,test_presence_tripwire.cpp,test_scoped_worker.cpp, andtest_sensor_factory.cpp.HardwareManager,Ite8353Parser,PresenceTripwire,ScopedWorker, andSensorFactory.Checklist