Skip to content

add self-escalation in appimage, prefering pkexec, sudo as backup#315

Merged
brkzlr merged 1 commit intokorcankaraokcu:masterfrom
notwithering:appimage-escalation
Feb 23, 2026
Merged

add self-escalation in appimage, prefering pkexec, sudo as backup#315
brkzlr merged 1 commit intokorcankaraokcu:masterfrom
notwithering:appimage-escalation

Conversation

@notwithering
Copy link
Contributor

No description provided.

@brkzlr brkzlr linked an issue Feb 15, 2026 that may be closed by this pull request
@notwithering
Copy link
Contributor Author

notwithering commented Feb 15, 2026

so im wondering why it has to be self-escalation and not just normally escalating the python script similar to PINCE.sh

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 15, 2026

So from my findings, the reason why that perm broken folder is like that is because it's created with root privileges.

For some reason it doesn't behave like the other folders where you can still see the perms, but they correctly show up once you do a su and check it as root, so there was nothing wrong with that folder in particular.

Having said that, I'd still prefer to see if there's a way for us to avoid double mounting the same AppImage, so I was thinking if we should modify AppRun to be a simple privilege escalation script and store the main runner in another AppRun-like script.

@notwithering
Copy link
Contributor Author

notwithering commented Feb 15, 2026

so im wondering why it has to be self-escalation and not just normally escalating the python script similar to PINCE.sh

trying

if [ "$(id -u)" != "0" ]; then
	if type pkexec &> /dev/null; then
		# Preserve env vars to keep settings like theme preferences.
		# Pkexec does not support passing all of env via a flag like `-E` so we need to
		# rebuild the env and then pass it through.
		ENV=()
		while IFS= read -r line
		do
			ENV+=("$line")
		done < <(printenv)

		pkexec env "${ENV[@]}" $APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py
	elif type sudo &> /dev/null; then
		# Debian/Ubuntu does not preserve PATH through sudo even with -E for security reasons
		# so we need to force PATH preservation with venv activated user's PATH.
		sudo -E --preserve-env=PATH PYTHONDONTWRITEBYTECODE=1 $APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py
	else
		echo "No supported privilege escalation utility found. Please run this as root manually."
		exit 1
	fi
	
	exit
fi

gives the error env: ‘/tmp/.mount_PINCE-nBKmCO/usr/bin/python3’: Permission denied, so to answer my own question its because fuse is noexec

@notwithering
Copy link
Contributor Author

Having said that, I'd still prefer to see if there's a way for us to avoid double mounting the same AppImage, so I was thinking if we should modify AppRun to be a simple privilege escalation script and store the main runner in another AppRun-like script.

so A.sh will self escalate itself, running smth like sudo A.sh which will then run B.sh which runs the python script?

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 15, 2026

Seems that FUSE completely prevents running anything from the tmp mount as root then, but it's weird how you can call the AppImage itself as root.

I suppose FUSE doesn't prevent the script itself running an external file as root but just the internal files are prevented.

@notwithering
Copy link
Contributor Author

notwithering commented Feb 15, 2026

so A.sh will self escalate itself, running smth like sudo A.sh which will then run B.sh which runs the python script?

or just have A.sh (escalation script) that does sudo B.sh (the python exec script), that would be simpler

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 15, 2026

image

Something like this basically, but it still didn't work for me. Even copying outside, it still won't let you run the script, giving Permission denied error.

@notwithering
Copy link
Contributor Author

is it because the shell script is mounted within the noexec FUSE fs?

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 15, 2026

Hmm, maybe if the shell script creates it directly outside on the fly?

@notwithering notwithering marked this pull request as draft February 15, 2026 21:01
@brkzlr
Copy link
Collaborator

brkzlr commented Feb 23, 2026

Any new updates on this?

@notwithering
Copy link
Contributor Author

i have not yet looked at how other projects escalate their appimage

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 23, 2026

Cool, just wanted to know if you did anything about this in private before trying to crack at it for a few hours.

I'm waiting on this PR to be finished before I tag 0.5 and release a new AppImage.

@notwithering
Copy link
Contributor Author

Cool, just wanted to know if you did anything about this in private before trying to crack at it for a few hours.

nope, go right ahead

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 23, 2026

So the main issue is that unless FUSE mounting options are changed from user-side, not only you're not allowed to run things as root inside but root user won't see the files inside at all.

A very bruteforce-y way is to just temporarily copy the inside of AppImage mounted folder and then run it from outside. This is effectively the same as running the AppImage from itself and even though doing that seems iffy, it would probably be more preferable than doing this, because AFAIK, FUSE mounting shouldn't occupy space so all 800 megs of our AppImage is not duplicated onto the /tmp folder, but this copy way would and that would not be preferable to the user.

You can find below a working patch with the "copy insides to outside" method.

diff --git a/ci/package.sh b/ci/package.sh
index b910377..15ee0bf 100755
--- a/ci/package.sh
+++ b/ci/package.sh
@@ -176,19 +176,50 @@ EOF
 # Placeholder icon for above desktop file
 touch AppDir/usr/share/icons/hicolor/scalable/apps/PINCE.svg
 
-# Create main running script
+# Create AppImage setup and self-escalation script
 cat > AppRun.sh <<\EOF
 #!/bin/bash
+export APPDIR="$(dirname "$0")"
 if [ "$(id -u)" != "0" ]; then
-	echo "Please run this AppImage using 'sudo -E'!"
-	exit 1
+	export TEMP_APPDIR=/tmp/PINCE-AppImg
+	mkdir -p $TEMP_APPDIR
+	cp -r $APPDIR/opt $TEMP_APPDIR/
+	cp -r $APPDIR/usr $TEMP_APPDIR/
+	export APPDIR=$TEMP_APPDIR
+
+	if type pkexec &> /dev/null; then
+		# Preserve env vars to keep settings like theme preferences.
+		# Pkexec does not support passing all of env via a flag like `-E` so we need to
+		# rebuild the env and then pass it through.
+		ENV=()
+		while IFS= read -r line
+		do
+			ENV+=("$line")
+		done < <(printenv)
+
+		pkexec env "${ENV[@]}" $APPDIR/opt/PINCERun.sh
+	elif type sudo &> /dev/null; then
+		# Debian/Ubuntu does not preserve PATH through sudo even with -E for security reasons
+		# so we need to force PATH preservation with venv activated user's PATH.
+		sudo -E --preserve-env=PATH PYTHONDONTWRITEBYTECODE=1 $APPDIR/opt/PINCERun.sh
+	else
+		echo "No supported privilege escalation utility found. Please run this as root manually."
+		exit 1
+	fi
+	exit
 fi
-export APPDIR="$(dirname "$0")"
-export PYTHONHOME=$APPDIR/usr/conda
-$APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py
+$APPDIR/opt/PINCERun.sh
 EOF
 chmod +x AppRun.sh
 
+# Create main running script
+cat > AppDir/opt/PINCERun.sh <<\EOoF
+export PYTHONHOME=$APPDIR/usr/conda
+$APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py
+rm -rf $TEMP_APPDIR
+EOoF
+chmod +x AppDir/opt/PINCERun.sh
+
 # Patch libqxcb's runpath (not rpath) to point to our packaged libxcb-cursor to fix X11 issues
 patchelf --add-rpath "\$ORIGIN/../../../../../../" AppDir/usr/conda/lib/python3.13/site-packages/PyQt6/Qt6/plugins/platforms/libqxcb.so

I think the only lead that remains to chase starting from this code is to temporarily copy only the required files to kickstart the process.
I'm thinking of copying just the python3 binary and then pointing it to the inside of the mounted AppImage folder so that we copy only single digit megs instead of hundreds.

Sadly trying to do this was unsuccessful as Python keeps complaining about missing modules even if PYTHONHOME and PYTHONPATH is set, so either I'm doing something wrong or FUSE might be interfering yet again by preventing a root Python from seeing the inside modules somehow.

I'll have to look into this more but feel free to try this idea yourself too if you want.

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 23, 2026

Nah, I give up. Life is too short and my hatred for Python too high for me to waste time trying to do this and then fix edge case after edge case.

Feel free to update the PR with your $APPIMAGE approach.

@notwithering
Copy link
Contributor Author

notwithering commented Feb 23, 2026

Nah, I give up. Life is too short and my hatred for Python too high for me to waste time trying to do this and then fix edge case after edge case.

same here bud 💀, you know its bad when collaborators of a python project even hate python

@notwithering
Copy link
Contributor Author

that should be the same $appimage approach from before

@brkzlr
Copy link
Collaborator

brkzlr commented Feb 23, 2026

/ranton

Python IMO is one of the biggest dogshit languages when it comes to actually making a program larger than a small script and especially when it comes to publishing/packaging.

So many packaging issues and even normal issues would've been fixed if we could've compiled the code and then ship with either statically linked libraries or just dynamic targeting specific base versions.

You have no idea how many times I wanted to rewrite this in another language.

PS: pip should be nuked off of this universe.

/rantoff

@notwithering
Copy link
Contributor Author

notwithering commented Feb 23, 2026

personally my biggest gripe with python is how shitty the tooling is, you cant use pip without doing 20 steps. i also really really love how it handles versions, making it impossible to use any dependencies even though python is touted as having the best ecosystem. for the love of god python needs to take after the go ecosystem: all you need is a go.mod file for a project, and all compiler versions are backwards compatible since 1.x

pr works for me, hopefully you can double check it

@brkzlr brkzlr marked this pull request as ready for review February 23, 2026 23:56
@brkzlr brkzlr merged commit 28a2646 into korcankaraokcu:master Feb 23, 2026
@brkzlr
Copy link
Collaborator

brkzlr commented Feb 23, 2026

Works for me, thanks for the PR.

"Python is touted as having the best ecosystem", whoever said that line needs to be checked. 🫡

@notwithering notwithering deleted the appimage-escalation branch February 23, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Use polkit rather than sudo

2 participants