How to fix chmod -x /usr/bin/chmod
Tue, Oct 5, 2021
I was asked this question years ago (and didnt know the answer then) and just recently I found a question and answer on Stackoverflow which basically solved this using python so I thought it would be fun to draw it out a little further.
Once you have executed chmod -x /usr/bin/chmod
(or in other words you have removed executable permissions from a common tool that is used to change the permissions of files including execution) you will no longer be able to use it to make things executable including chmod
.
The general answer to this question is that you need to flip the correct permission bits in order to make it executable again. chmod itself is a tool which uses underlying system calls to achieve its goal. You can also do that with other languages very easily.
NOTE: I am using the stat
command to output the file access rights in both octal (%a) and human readable (%A) format.
command | output | ||
---|---|---|---|
1 | stat -c "%a/%A" /usr/bin/chmod | 755/-rwxr-xr-x | |
2 | chmod -x /usr/bin/chmod | No output from this command | |
3 | chmod | bash: /usr/bin/chmod: Permission denied | Not executable any more |
4 | stat -c "%a/%A" /usr/bin/chmod | 644/-rw-r--r-- | So now the user, group or any others (nothing) can execute this |
5 | python3 -c "import os,stat; os.chmod('/usr/bin/chmod', os.stat('/usr/bin/chmod').st_mode | 0o111)" | The answer from Stackoverflow just put into one line for the purposes of demonstration | |
6 | stat -c "%a/%A" /usr/bin/chmod | 755/-rwxr-xr-x | The permissions are now back to how they were before removing them |
Taking this a little bit further
How can we then replicate chmod -x
when the above now achieves the same functionality as chmod +x
? Using bitwise operations again, the first step is to ensure the file is executable and then XOR
the executable bits which will flip them back to zero as both will be 1
.
The name XOR stands for “exclusive or” since it performs exclusive disjunction on the bit pairs. In other words, every bit pair must contain opposing bit values to produce a one
Bartosz Zaczyński - https://realpython.com/python-bitwise-operators/
#!/usr/bin/env python3
import os
import stat
import sys
exe_perm=0o111
command = sys.argv[1]
filename= sys.argv[2]
result=os.stat(filename)
if command == "+x":
os.chmod(filename, result.st_mode | exe_perm)
elif command == "-x":
os.chmod(filename, (result.st_mode | exe_perm) ^ exe_perm)
I saved the above into a file called pychmod
and then could use this whether or not the chmod
utility was executable. Here is a quick run through changing executable permissions with this toy script in the absence of chmod.
❯ chmod -x /usr/bin/chmod
chmod: changing permissions of '/usr/bin/chmod': Operation not permitted
❯ sudo !!
❯ sudo chmod -x /usr/bin/chmod
[sudo] password for andy:
❯ chmod +x test.sh
zsh: permission denied: chmod
❯ ./pychmod +x test.sh
❯ stat -c "%a/%A" test.sh
775/-rwxrwxr-x
❯ stat -c "%a/%A" /usr/bin/chmod
644/-rw-r--r--
❯ ./pychmod +x /usr/bin/chmod
Traceback (most recent call last):
File "./pychmod", line 13, in <module>
os.chmod(filename, result.st_mode | exe_perm)
PermissionError: [Errno 1] Operation not permitted: '/usr/bin/chmod'
❯ sudo !!
❯ sudo ./pychmod +x /usr/bin/chmod
❯ stat -c "%a/%A" /usr/bin/chmod
755/-rwxr-xr-x
References:
https://stackoverflow.com/questions/12791997/how-do-you-do-a-simple-chmod-x-from-within-python
https://linuxize.com/post/understanding-linux-file-permissions/
https://www.howtogeek.com/451022/how-to-use-the-stat-command-on-linux/