Linux evo.fastest-server.com 5.14.0-284.1101.el9.tuxcare.11.els11.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Aug 14 13:30:35 UTC 2026 x86_64
LiteSpeed
Server IP : 103.249.112.113 & Your IP : 216.73.217.135
Domains : 988 Domain
User : tanishks
Terminal
Auto Root
Create File
Create Folder
Localroot Suggester
Backdoor Destroyer
Readme
/
usr /
share /
lve /
dbgovernor /
scripts /
Delete
Unzip
Name
Size
Permission
Date
Action
__pycache__
[ DIR ]
drwxr-xr-x
2026-09-04 11:34
chek_mysql_rpms_local
1.79
KB
-rwxr-xr-x
2026-08-06 17:01
cpanel-common-lve
2.16
KB
-rwxr-xr-x
2026-08-06 17:01
cpanel-delete-hooks
1.98
KB
-rwxr-xr-x
2026-08-06 17:01
cpanel-install-hooks
3.48
KB
-rwxr-xr-x
2026-08-06 17:01
cpanel-mysql-url-detect.pm
1.6
KB
-rwxr-xr-x
2026-08-06 17:01
cpanel_map_rebuilder
1.5
KB
-rwxr-xr-x
2026-08-06 17:01
dbgovernor_map
4.15
KB
-rwxr-xr-x
2026-08-06 17:01
dbgovernor_map.py
3.16
KB
-rwxr-xr-x
2026-08-06 17:01
dbgovernor_map_plesk.py
4.21
KB
-rwxr-xr-x
2026-08-06 17:01
dbgovernor_version.py
28
B
-rw-r--r--
2026-08-06 17:01
dbgovernor_watchdog.py
7.03
KB
-rwxr-xr-x
2026-08-06 17:01
detect-cpanel-mysql-version.pm
4.83
KB
-rwxr-xr-x
2026-08-06 17:01
map_hook
664
B
-rwxr-xr-x
2026-08-06 17:01
merge_logs.py
984
B
-rwxr-xr-x
2026-08-06 17:01
mysql_backup.sh
24.38
KB
-rwxr-xr-x
2026-08-06 17:01
mysql_hook
42
B
-rwxr-xr-x
2026-08-06 17:01
sentry_cleaner.sh
1.21
KB
-rwxr-xr-x
2026-08-06 17:01
sentry_daemon.py
19.72
KB
-rwxr-xr-x
2026-08-06 17:01
sentry_sdk_wrapper.py
7.14
KB
-rwxr-xr-x
2026-08-06 17:01
set_cpanel_mysql_version.pm
381
B
-rwxr-xr-x
2026-08-06 17:01
sync_hook
501
B
-rwxr-xr-x
2026-08-06 17:01
Save
Rename
#!/usr/bin/bash RED='\033[0;31m' # Red Color GR='\033[0;32m' # Green Color YW='\033[0;33m' # Yellow Color PR='\033[0;35m' # Purple Color CY='\033[0;36m' # Cyan Color NC='\033[0m' # No Color # Waning: Using username and password in the command line is insecure! # This option is only for testing purposes! auto_arg_pass="" auto_arg_user="" default_backup_dir="/backup/mysqlbkp_$(date +%Y%m%d%H%M)" auto_arg_yes=false # Waning: Using username and password in the command line is insecure! # This option is only for testing purposes! for arg in "$@"; do if [[ $arg == "--yes" ]]; then auto_arg_yes=true fi if [[ $arg == --user=* ]]; then auto_arg_user="${arg#*=}" fi if [[ $arg == --pass=* ]]; then auto_arg_pass="${arg#*=}" fi if [[ $arg == --dir=* ]]; then default_backup_dir="${arg#*=}" fi done # Waning: Using username and password in the command line is insecure! # This option is only for testing purposes! if [ "$auto_arg_yes" = true ]; then echo -e $YW" The script will run in the auto mode!"$NC echo -e $RED "Warning: Using username and password in the command line is insecure!"$NC echo -e $RED "Warning: This option is only for testing purposes!"$NC if [ -z "$auto_arg_user" ] || [ -z "$auto_arg_pass" ]; then echo -e $RED" !!!Please provide the MySQL username and password for the auto mode!!!"$NC echo -e $YW" Example: $PR--user=root --pass=123456"$NC exit 1 fi fi set -e # Path to the temporary MySQL credentials (--defaults-extra-file) created by # write_credentials_file. Removed on exit so the secret never lingers on disk. cred_file="" cleanup_cred_file() { if [ -n "$cred_file" ] && [ -f "$cred_file" ]; then rm "$cred_file" || true fi return 0 } trap cleanup_cred_file EXIT echo -e $PR" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"$NC echo -e $CY" This script will perform the backup process of the MySQL databases!"$NC echo -e $CY" and install the \"pv\" package to show the progress bar during backup process"$NC if [ "$auto_arg_yes" = false ]; then echo -e $CY" Do you want to proceed?"$NC echo -e $PR" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"$NC echo -n -e $YW" Please choose"$NC $PR"[Y/y"$NC $RED"| N/n]:"$NC read -r input if [[ $input != y ]] && [[ $input != Y ]] && [[ $input != yes ]] && [[ $input != Yes ]]; then echo -e "" echo -e $CY" Thanks for using the script!"$NC echo -e $GR" Bye!Bye!"$NC exit fi fi if [ -e /etc/redhat-release ]; then #Check Operating system OS_VERSION=$(cat /etc/redhat-release | awk {'print $3'} | sed 's/\..*//') else echo -e $RED" !!!!!!!!/etc/redhat-release file is absent!!!!!!!!"$NC echo -e $YW" Please make sure that the \"cloudlinux-release\" package is installed"$NC exit fi package_name="pv" if ! rpm -q "$package_name"; then echo "" echo -e $YW" Installing the \"pv\" package via the system package manager (signature-verified)..."$NC echo "" sleep 2 # Install through the package manager so the RPM's GPG signature is verified # against the imported repo keys. We deliberately do NOT fetch and `rpm -ivh` # an RPM straight from a URL: `rpm -ivh URL` installs even unsigned/NOKEY # packages, which would let a poisoned mirror or intercepted download run # arbitrary code as root. if command -v dnf >/dev/null 2>&1; then pkg_mgr="dnf" else pkg_mgr="yum" fi # 'pv' lives in EPEL. Make sure the EPEL repo definition + GPG key are present # (epel-release is itself a signed package from the base repo), then install pv # with the EPEL repo explicitly enabled so dnf/yum verifies its GPG signature # (gpgcheck=1 in the EPEL repo). We never pass --nogpgcheck and never rpm -ivh # an unsigned URL, so a poisoned mirror cannot run unsigned code as root. "$pkg_mgr" install -y epel-release >/dev/null 2>&1 || true if ! "$pkg_mgr" install -y --enablerepo=epel pv; then echo -e "" echo -e $RED" !!! Could not install \"pv\" from EPEL (signature-verified). Enable the"$NC echo -e $RED" EPEL repository (e.g. install epel-release) or install \"pv\""$NC echo -e $RED" manually, then re-run the backup. !!!"$NC exit 1 fi if rpm -q "$package_name"; then echo -e "" echo -e $GR" Package \"pv\" has been installed successfully!"$NC else echo -e "" echo -e $RED" !!!The package \"pv\" wasn't installed! Please contact support!!!"$NC exit 1 fi else echo -e "" echo -e $GR" The $package_name package has already installed!"$NC fi # Create a variable with the default path value first_prompt=true while true; do if [ "$auto_arg_yes" = true ]; then backup_dir=$default_backup_dir break fi if [[ $first_prompt == true ]]; then echo -e "" echo -e " Would you like to use the following path $GR($default_backup_dir)$NC?$PR[yes/y]$NC for confirmation, $CY[n/no]$NC to set own path or $RED'exit'$NC to interrupt the script: \c" read use_default first_prompt=false else echo -e "" if [[ -n $use_default && $use_default != "exit" ]]; then if [[ $use_default =~ ^/ ]]; then if [ -d "$use_default" ]; then echo -e "" echo -e $YW" The directory $use_default already exists!"$NC echo -e $CY" Do you want to use this directory? [$GR(yes/y)$CY] for confirmation, [$RED'n/no'$CY] to set a new path or '$RED'exit'$CY' to interrupt the script: \c"$NC read use_existing if [[ $use_existing =~ ^[Yy](es)?$ ]]; then backup_dir=$use_default break elif [[ $use_existing =~ ^[Nn](o)?$ ]]; then use_default="exit" elif [[ $use_existing == "exit" ]]; then echo -e "" echo -e "" echo -e $CY" Thank you for using the script!"$NC echo -e $GR" Bye!Bye!"$NC exit 0 else echo -e "" echo -e $RED" !!!Input not recognized. Please enter 'exit' to exit, 'yes'/'y' to use the default path, 'no'/'n' to set a new path!!!"$NC fi else backup_dir=$use_default break fi fi fi echo -e "$CY Please enter the absolute path to creating the new backup directory example:$NC $GR/backup/testbackupdir$NC" echo -e " or enter $RED'exit'$NC to close the script or you can enter $PR'yes'/'y'$NC to use the default path: \c" read use_default fi if [[ $use_default =~ ^[Yy](es)?$ ]]; then backup_dir=$default_backup_dir break elif [[ $use_default == "exit" ]]; then echo -e "" echo -e "" echo -e $CY" Thank you for using the script!"$NC echo -e $GR" Bye!Bye!"$NC exit 0 elif [[ -n $use_default && $use_default != "exit" ]]; then if [[ $use_default =~ ^/ ]]; then if [ -d "$use_default" ]; then echo -e "" echo -e $YW" The directory $use_default already exists!"$NC echo -e $CY" Do you want to use this directory? [$GR(yes/y)$CY] for confirmation, [$RED'n/no'$CY] to set a new path or '$RED'exit'$CY' to interrupt the script: \c"$NC read use_existing if [[ $use_existing =~ ^[Yy](es)?$ ]]; then backup_dir=$use_default break elif [[ $use_existing =~ ^[Nn](o)?$ ]]; then use_default="exit" elif [[ $use_existing == "exit" ]]; then echo -e "" echo -e "" echo -e $CY" Thank you for using the script!"$NC echo -e $GR" Bye!Bye!"$NC exit 0 else echo -e "" echo -e $RED" !!!Input not recognized. Please enter 'exit' to exit, 'yes'/'y' to use the default path, 'no'/'n' to set a new path!!!"$NC fi else backup_dir=$use_default break fi fi else echo -e "" echo -e $RED" !!!Input not recognized. Please enter 'exit' to exit or 'yes'/'y' to use the default path!!!"$NC fi done # Dumps contain every tenant's database; keep the dir and files root-only. # umask 077 makes mkdir create the dir 0700 and the dump redirections create # files 0600 under the default (022) umask root would otherwise inherit. umask 077 # Checking if the directory exists if [ ! -d "$backup_dir" ]; then echo -e "" echo -e $YW" !The directory is absent!"$NC echo -e $GR" Creating the new directory!"$NC sleep 1 mkdir -p "$backup_dir" fi # Checking if the new directory was created successfully if [ -d "$backup_dir" ]; then echo -e "" echo -e $GR" The directory to store backup files has been created successfully: $backup_dir"$NC else echo -e "" echo -e $RED"!Oh no! Something went wrong. The directory wasn't created! Please try to create it manually to see the result!"$NC exit 1 fi # Harden the destination before root writes (sensitive) DB dumps into it. # Refuse a backup_dir that is a symlink, not root-owned, or group/world-writable: # otherwise a less-privileged user who can write the dir (or any parent component) # could plant a symlink for "$db.sql" and have root truncate/capture the dump. if [ -L "$backup_dir" ]; then echo -e $RED" !!!Refusing to use a symlinked backup directory: $backup_dir!!!"$NC exit 1 fi dir_owner=$(stat -c '%u' "$backup_dir") dir_perm=$(stat -c '%a' "$backup_dir") if [ "$dir_owner" != "0" ]; then echo -e $RED" !!!Refusing to use backup directory not owned by root: $backup_dir!!!"$NC exit 1 fi # %a may be 3 or 4 digits; the group/other-write bits are the last two octal digits. if [ $(( 0$dir_perm & 022 )) -ne 0 ]; then echo -e $RED" !!!Refusing to use group/world-writable backup directory: $backup_dir (mode $dir_perm)!!!"$NC echo -e $YW" Tighten its permissions (e.g. chmod 700 $backup_dir) and re-run."$NC exit 1 fi # A pre-existing root-owned 0755 dir passes the world-writable check above but is # still world-readable/traversable; tighten it so the dumps stay root-only. chmod 700 "$backup_dir" check_mysql_cnf_file() { if [ -f "/etc/.my.cnf" ]; then echo -e $GR" Found /etc/.my.cnf file. Using credentials from it."$NC return 0 else echo -e $YW" None control panel has been detected and the /etc/.my.cnf file not found. Please enter MySQL credentials manually."$NC return 1 fi } # Securely store the given user/password in a mode-0600 defaults-extra-file so # the credentials are never exposed on the command line (/proc/PID/cmdline). # Sets mysql_arg_credentials / pv_arg_credentials to a one-element array # holding "--defaults-extra-file=...", so a $TMPDIR-derived cred_file path # containing whitespace/glob metacharacters can't word-split or glob-expand # into extra mysql/mysqldump arguments at the call sites. # The created file path is recorded in cred_file so the EXIT trap can remove it. write_credentials_file() { local _user="$1" local _pass="$2" local _old_umask _old_umask=$(umask) umask 077 cred_file=$(mktemp) umask "$_old_umask" chmod 600 "$cred_file" printf '[client]\nuser=%s\npassword=%s\n' "$_user" "$_pass" > "$cred_file" mysql_arg_credentials=(--defaults-extra-file="$cred_file") pv_arg_credentials=("${mysql_arg_credentials[@]}") } get_user_credentials() { local userdb="" local userpw="" if [[ $PANEL == "plesk" ]]; then userdb="admin" userpw=$(cat /etc/psa/.psa.shadow) write_credentials_file "$userdb" "$userpw" elif [[ $PANEL == "cpanel" || $PANEL == "directadmin" ]]; then mysql_arg_credentials=() elif ! check_mysql_cnf_file; then if [ "$auto_arg_yes" = false ]; then echo -n -e $YW" Enter MySQL username (or type 'exit' to cancel): "$NC read userdb if [[ $userdb == "exit" ]]; then echo -e "" echo -e $CY" Thank you for using the script!"$NC echo -e $GR" Bye!Bye!"$NC exit 0 fi echo -n -e $YW" Enter MySQL password: "$NC read -s userpw echo -e "" else userdb=$auto_arg_user userpw=$auto_arg_pass fi write_credentials_file "$userdb" "$userpw" fi } check_panel () { ROOT_PLESK_DIR="/usr/local/psa/admin/" ROOT_CPANEL_DIR="/usr/local/cpanel/whostmgr/docroot/" ROOT_DA_DIR="/usr/local/directadmin/" if [ -d "$ROOT_PLESK_DIR" ]; then PANEL="plesk" elif [ -d "$ROOT_CPANEL_DIR" ]; then PANEL="cpanel" elif [ -d "$ROOT_DA_DIR" ]; then PANEL="directadmin" else PANEL="unknown" fi } do_backup() { local -a mysql_arg_credentials=() local -a pv_arg_credentials=() local total_databases=0 local backup_count=0 local dir_owner="" local dir_perm="" local dir_nlink="" local size="" local backup_dirfd local backup_dir_pinned=false local backup_dir_became_invalid=false local backup_dir_display="" local db_display="" local out_fd check_panel get_user_credentials # Pin backup_dir's identity to a directory file descriptor ONCE, right # before the per-database loop, instead of re-resolving the "$backup_dir" # path on every iteration. A directory fd's "/proc/self/fd/<fd>" magic # symlink is dentry-based -- bound to the actual inode that got opened -- # not a fresh walk of the original path string. Verified empirically in # this environment (bash 5.1 on Linux): after opening a directory this way, # renaming it away and planting an attacker-owned symlink at the old name # does not redirect writes made through the already-open fd; they still # land in the original directory every time, and `stat -L` on the fd still # reports the original directory's real owner/mode, never the swapped-in # target's. Once pinned below, no later rename/symlink-swap of whatever # "$backup_dir" currently names can steer a per-database check or write # elsewhere -- this removes the repeated re-resolution of "$backup_dir" as # a string that left a residual window in the previous design (a swap # landing between the last check and the readlink that captured the # expected identity), rather than merely narrowing that window further. # # A single check-then-open is still unavoidable right here: opening a # symlink via a plain "<" redirect follows it like any other read, so a # swap completed before this point (e.g. during the credentials prompt # above, which can block on interactive input) must still be caught before # this fd is trusted for the rest of the run. if [ -L "$backup_dir" ]; then echo -e $RED" !!!Refusing to back up: backup directory became a symlink: $backup_dir!!!"$NC elif [ ! -d "$backup_dir" ]; then echo -e $RED" !!!Refusing to back up: backup directory is missing: $backup_dir!!!"$NC elif ! dir_owner=$(stat -c '%u' "$backup_dir" 2>/dev/null); then echo -e $RED" !!!Refusing to back up: failed to verify backup directory: $backup_dir!!!"$NC elif ! dir_perm=$(stat -c '%a' "$backup_dir" 2>/dev/null); then echo -e $RED" !!!Refusing to back up: failed to verify backup directory: $backup_dir!!!"$NC elif [ "$dir_owner" != "0" ]; then echo -e $RED" !!!Refusing to back up: backup directory no longer owned by root: $backup_dir!!!"$NC elif [ $(( 0$dir_perm & 022 )) -ne 0 ]; then echo -e $RED" !!!Refusing to back up: backup directory became group/world-writable: $backup_dir (mode $dir_perm)!!!"$NC elif ! exec {backup_dirfd}<"$backup_dir"; then echo -e $RED" !!!Refusing to back up: failed to open backup directory: $backup_dir!!!"$NC else backup_dir_pinned=true fi if [ "$backup_dir_pinned" = true ]; then total_databases=$(mysql "${mysql_arg_credentials[@]}" -e "show databases;" | awk '{print $1}' | egrep -v "Database|information_schema|performance_schema|sys" | wc -l) for db in $(mysql "${mysql_arg_credentials[@]}" -e "show databases;" | awk '{print $1}' | egrep -v "Database|information_schema|performance_schema|sys"); do # A MySQL database name can carry a raw embedded newline (or other # control) byte -- CREATE DATABASE imposes no restriction on # identifier bytes -- which `mysql -e "show databases;"` re-serialises # as literal escape-sequence text (e.g. "\n") that survives the # awk/egrep filter above intact. Sanitize once, right after $db is # read, into a dedicated display copy -- mirroring backup_dir_display's # own defence -- so $db itself stays the raw, untouched identifier for # every actual mysqldump/file-path use below. # Allowlist to printable ASCII rather than blocklisting control bytes: # LC_ALL=C makes tr operate byte-wise, so '[:print:]' means exactly # 0x20-0x7E, stripping control bytes AND every multi-byte UTF-8 # codepoint (e.g. U+202E RTL-override, U+200B zero-width space) that # could otherwise spoof how the announcement renders on a terminal. db_display=$(LC_ALL=C tr -cd '[:print:]' <<<"$db") echo -e "" # printf's %s (unlike `echo -e`) never reinterprets escape sequences in # the substituted value, so even a literal "\n"/ESC-style two-character # sequence surviving the control-byte strip above can't be turned back # into a real newline/control byte here; %b still expands $GR/$NC's own # \033-style color codes as before. printf '%b Dumping database: %s%b\n' "$GR" "$db_display" "$NC" # Sanity-check the PINNED directory's own current state, dereferenced # through the fd rather than a re-resolution of the "$backup_dir" # path. This catches only the narrower, legitimate case of the # original directory's own permissions being loosened in place after # it was pinned -- it cannot observe (and does not need to: see above) # a rename/symlink-swap of "$backup_dir" itself, since the fd stays # bound to the original dentry regardless of what that path names now. if ! dir_owner=$(stat -L -c '%u' "/proc/self/fd/$backup_dirfd" 2>/dev/null); then echo -e $RED" !!!Refusing to write dump: failed to verify pinned backup directory: $backup_dir!!!"$NC backup_dir_became_invalid=true continue fi if ! dir_perm=$(stat -L -c '%a' "/proc/self/fd/$backup_dirfd" 2>/dev/null); then echo -e $RED" !!!Refusing to write dump: failed to verify pinned backup directory: $backup_dir!!!"$NC backup_dir_became_invalid=true continue fi if [ "$dir_owner" != "0" ]; then echo -e $RED" !!!Refusing to write dump: backup directory no longer owned by root: $backup_dir!!!"$NC backup_dir_became_invalid=true continue fi if [ $(( 0$dir_perm & 022 )) -ne 0 ]; then echo -e $RED" !!!Refusing to write dump: backup directory became group/world-writable: $backup_dir (mode $dir_perm)!!!"$NC backup_dir_became_invalid=true continue fi # Refuse a pre-existing symlink leaf, checked through the pinned # directory fd rather than the mutable "$backup_dir" path: bash # redirection follows symlinks (no O_NOFOLLOW), so a planted # "$db.sql" symlink would let root truncate/overwrite its target or # leak the dump outside the pinned directory. Resolving the leaf via # the fd means a swap of "$backup_dir" itself cannot steer this check # at some other (attacker) directory instead of the pinned one. if [ -L "/proc/self/fd/$backup_dirfd/$db.sql" ]; then printf '%b !!!Refusing to write dump through a symlink: %s/%s.sql!!!%b\n' "$RED" "$backup_dir" "$db_display" "$NC" continue fi size=$(mysqldump "${pv_arg_credentials[@]}" -- "$db" | wc -c) # Open the destination via the pinned directory fd: # "/proc/self/fd/<dirfd>/<name>" resolves relative to that fd's own # dentry, so this open is unaffected by anything done to the # "$backup_dir" path after the fd above was opened -- including a # rename-then-symlink swap completed while the size probe above was # running. if ! exec {out_fd}>"/proc/self/fd/$backup_dirfd/$db.sql"; then printf '%b !!!Refusing to write dump: failed to open %s/%s.sql for writing!!!%b\n' "$RED" "$backup_dir" "$db_display" "$NC" # A directory that just accepted the stat -L checks above but now # refuses to let us create a file in it (ENOENT) has typically been # removed out from under the pinned fd (rmdir leaves an open fd's # stat/owner/mode intact but breaks further name creation inside # it) -- treat this the same as any other pinned-directory failure. backup_dir_became_invalid=true continue fi if mysqldump "${mysql_arg_credentials[@]}" --routines --events --triggers -- "$db" | pv --progress --size "$size" >&$out_fd; then backup_count=$((backup_count + 1)) echo -e " Backup progress: $backup_count out of $total_databases databases backed up." else printf '%b !!!Failed to backup database: %s!!!%b\n' "$RED" "$db_display" "$NC" fi exec {out_fd}>&- done # Capture the pinned directory's OWN current path -- dentry-based, so it # reflects a rename performed at any point during the loop -- while # backup_dirfd is still open, so the completion message below reports # where the dumps actually landed instead of re-printing the possibly # now-stale "$backup_dir" string, which a mid-run rename+symlink swap # could have repointed at an attacker-controlled location. # The per-iteration checks above only run before the NEXT database's # dump -- if backup_dir vanishes right after the LAST iteration's write # (or there were zero databases to loop over), no further iteration is # left to observe it and backup_dir_became_invalid would stay false. # Close that gap with one last fd-based liveness probe, using the same # stat -L mechanism as the per-iteration checks (never readlink-output # parsing): once a directory has been unlinked, its own link count # drops to 0, even though the already-open fd keeps reporting the same # owner/mode. Checking nlink through the pinned fd queries that fd's own # inode metadata directly, so it cannot be spoofed by any sibling # directory an attacker plants next to backup_dir -- unlike testing a # string readlink returns. if ! dir_nlink=$(stat -L -c '%h' "/proc/self/fd/$backup_dirfd" 2>/dev/null) || [ "$dir_nlink" -eq 0 ]; then backup_dir_became_invalid=true fi # Do not decide "is the pinned directory still good" by re-parsing # readlink's output (e.g. testing for "-d" on it, or matching a # "(deleted)" suffix): an attacker who holds this finding's own # precondition -- write access to backup_dir's parent -- can pre-plant a # directory literally named "<name> (deleted)" next to backup_dir before # removing it, making any such string-based test pass against the decoy # even though the real directory is gone. Instead trust # backup_dir_became_invalid, which the checks above already set at the # exact moments they observed the pinned directory fail -- metadata/ # open-syscall signals an attacker's sibling filename cannot spoof. if [ "$backup_dir_became_invalid" = true ]; then backup_dir_display="the originally-validated backup directory (its current path could not be resolved)" else backup_dir_display=$(readlink "/proc/self/fd/$backup_dirfd" 2>/dev/null) || backup_dir_display="the originally-validated backup directory (its current path could not be resolved)" # backup_dir can be rename()'d to any byte string (except NUL/'/') # while backup_dirfd stays pinned and valid, so readlink's raw output # here is attacker-influenceable even though backup_dir_became_invalid # correctly stayed false. Allowlist to printable ASCII rather than # blocklisting control bytes: LC_ALL=C makes tr operate byte-wise, so # '[:print:]' means exactly 0x20-0x7E, stripping control bytes AND # every multi-byte UTF-8 codepoint (e.g. U+202E RTL-override, U+200B # zero-width space) before this value ever reaches the banner below. backup_dir_display=$(LC_ALL=C tr -cd '[:print:]' <<<"$backup_dir_display") fi exec {backup_dirfd}<&- else echo -e $RED" !!!Refusing to back up: backup directory failed validation before the per-database loop could start; no databases were backed up: $backup_dir!!!"$NC exit 1 fi echo -e "" # printf's %s (unlike `echo -e`) never reinterprets escape sequences in the # substituted value, so even a literal "\n"/ESC-style two-character # sequence surviving the control-byte strip above can't be turned back # into a real newline/control byte here; %b still expands $GR/$NC's own # \033-style color codes as before. printf '%b Congratulations! The backup process has been completed! You may find your backup files here: %s%b\n' "$GR" "$backup_dir_display" "$NC" echo -e $YW" !!!Please check the output and make sure that all databases are backed up successfully!!!!"$NC } # Perform MySQL backup do_backup