While trying to gain root access, I experimented a lot with mounting rcfs images and noticed one peculiarity of QNX. If the file system image and the directory where it is mounted do not contain any subdirectories, the image is mounted as an OverlayFS. This means that if the original directory contains files with names that also exist in the image, those files are overwritten by the image’s files, while the others remain unchanged. This feature can be used to enable autostart. Since PathTrust won't allow our file to run with root privileges, we need to find a service that runs with non-root privileges and install the impersonation package first. One such candidate is /bin/racd.
SERVICE_racd_HANDLER_start ()
{
[ "${VAR_PROTECT_DISABLED}" == "1" ] && return 0 # don't start protect service if policy_block_blackberry_protect is set to 1
ADD_GROUP_ACL racd rx /var/javadevicemigration
ADD_GROUP_ACL racd rwx /var/javadevicemigration/databases
CMN_ON -d -u 399:399,427,1005,368 ${BASEFS}/bin/racd
}
Based on a quick analysis of the strings found within this file, it appears to be related to BlackBerry Protect, which is no longer relevant, so there likely won’t be any issues after replacing it(It turns out that racd stands for Remote Admin Command daemon). Although nothing prevents us from saving the original file elsewhere or under a different name and running it. For complete certainty, we can also set the corresponding policy to 0.
@policy
policy_block_blackberry_protect::0
To test the hypothesis, we can use this simple code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
system("/accounts/devuser/rootdata/install.sh >> /tmp/root.log");
return EXIT_SUCCESS;
}
Add this compiled file to the directory containing the impersonation files, and create an rcfs image. We can also replace /sbin/blupdater, but to do so, we need to set the file owner to someone other than root and enable the suid bit. This will also prevent the list of blocked OS versions from being updated.
If we are replacing more than one service, make sure our script isn't run multiple times simultaneously. For example, like this:
readonly LOCK_FILE="/tmp/root_update.lock"
cleanup() {
log "Cleaning up and performing safety checks..."
if [ -f "${BACKUP_DIR}${START_SCRIPT}" ]; then
log "Auto-restoring original script from backup for safety..."
run_as __apps "cp -f \"${BACKUP_DIR}${START_SCRIPT}\" \"${SCRIPT_PATH}${START_SCRIPT}\""
fi
rm -f "$LOCK_FILE"
log "Process finished. Lock file removed."
}
#----------[ other functions ]----------
if [[ -f "$LOCK_FILE" ]]; then
log "CRITICAL ERROR: Lock file exists. Aborting to prevent concurrent execution."
exit 1
fi
touch "$LOCK_FILE"
# Trap to ensure cleanup on exit, interrupt or termination
trap cleanup EXIT INT TERM
#----------[ main logic ]----------
Or by adding the appropriate logic to the C code.
Making changes to assets/links
mount:assets/data/fs1.rcfs:/base/bin:rcfs
mount:assets/data/fs2.rcfs:/base/sbin:rcfs