26

I ran chmod 222 /bin/chmod to know more about chmod. After that, when I run /bin/chmod, I get permission denied.

I tried to change the permissions of chmod back to 755, but it doesn't work.

Does anyone have tips about how to fix this?

Raffa
  • 34,963
Charming_Yard
  • 397
  • 1
  • 3
  • 3

9 Answers9

47

You made chmod not executable.

There are three (no, actually four) options to revert from this situation:

  1. Reinstall the coreutils package, as mentioned in Artur Meinild's answer.

  2. My preferred solution:

    • boot from an installation medium and start a live Ubuntu session.

    • start the Disks application, find the partition where your Ubuntu installation resides and mount it. Note the path where the partition is mounted (something like /media/username/somename).

    • open a terminal and run:

      sudo chmod 755 /media/username/somename/usr/bin/chmod
      
    • unmount the partition, shutdown the live session and reboot from your normal installation.

  3. Be VERY CAREFUL when doing this! Run the following commands:

    sudo cp -p /usr/bin/ls /tmp/chmod
    sudo cp /usr/bin/chmod /tmp/chmod
    sudo /tmp/chmod 755 /usr/bin/chmod
    

    Explanation: first, we copy another file that is still executable (I chose /usr/bin/ls) to /tmp/chmod. By using the -p parameter to the cp command, we are preserving permissions, so we ensure that the resulting file is also executable.

    Next, we overwrite the just created /tmp/chmod file with the contents of actual /usr/bin/chmod, but without preserving permissions. The contents of /tmp/chmod is overwritten with actual chmod, but it is still executable.

    So we can use /tmp/chmod to restore permissions on the actual /usr/bin/chmod.

    Optionally we can delete /tmp/chmod, which is no more needed, but it is not necessary; on the next system boot, /tmp directory will be cleared anyway.

  4. You can use any programming language that supports the chmod() system call. As Ubuntu by default contains the Python interpreter, it would be probably easiest to use Python:

    sudo python3 -c 'import os; os.chmod("/usr/bin/chmod", 0755)'
    
raj
  • 11,409
28

With dpkg-statoverride

dpkg-statoverride is available by default on Ubuntu ... Its main purpose is to override ownership and mode of files ... and you can use it like this:

sudo dpkg-statoverride --update --add root root 755 /bin/chmod

With rsync

rsync is available by default on Ubuntu ... In --archive, -a mode, it should only set the permissions (since the file will never change) ... i.e. when used in one shot like so:

sudo rsync -a --chmod=755 /bin/chmod /bin/chmod

With the install command

There is another utility called install from GNU core utilities as well which should be available by default on your system … It’s mainly used for copying just compiled files and make them executable i.e. install them and hence the name … It should give the copied file the permissions of rwxr-xr-x by default ... It also has the option -m to alter permissions of that file selectively on-the-fly (while you might not need that option in this case as the defaults should suffice), but you can always do:

sudo install -m +x /bin/chmod mychmod

Then, you can simply do:

sudo ./mychmod 755 /bin/chmod

With the dynamic linker/loader

Another simple solution as well is to use the dynamic linker/loader itself ... This is a special way of running binaries as it doesn’t require permissions to do so (It is somewhat similar to running a non-executable shell script by passing it as an argument to /bin/sh for example) … Depending on the architecture your binary was compiled for, you most likely want to use the amd64 variant ... Find its name and path on your system with for example:

$ dpkg -S 'ld-linux*'
manpages: /usr/share/man/man8/ld-linux.8.gz
manpages: /usr/share/man/man8/ld-linux.so.8.gz
libc6:amd64: /lib64/ld-linux-x86-64.so.2
libc6:i386: /lib/i386-linux-gnu/ld-linux.so.2
libc6-i386: /lib32/ld-linux.so.2
libc6:i386: /lib/ld-linux.so.2
libc6:amd64: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

Then, simply use it in one shot like so:

sudo /lib64/ld-linux-x86-64.so.2 /bin/chmod 755 /bin/chmod

Else ...

Search your system for other utilities that can change/set file permissions ... One way is to search the manuals with e.g. man -K "chmod" ... Here are some of what I found on my system:

chacl(change the access control list of a file or directory):

sudo chacl u::rwx,g::r-x,o::r-x /bin/chmod

bwrap(container setup utility):

sudo bwrap --die-with-parent --bind / / --chmod 755 /bin/chmod -- /bin/true
Raffa
  • 34,963
25

You did one of the most obvious things should never do with chmod - you changed chmod itself to not be executable. Not even the powers of sudo will make this command work again (in its current form - see the other answers though).

A way to get it working again would be to reinstall the GNU coreutils package with this command:

sudo apt install --reinstall coreutils

A general tip (that's especially important for Linux utilities): When learning about something, first read up on what each command does, secondly try out stuff in an isolated environment (container/VM), and only after that should you run commands on your production system.

Artur Meinild
  • 31,035
15

In addition to all the other answers, if you have busybox installed, you can use that by running:

sudo busybox chmod 0755 /usr/bin/chmod

Busybox can be installed by enabling the universe repository, and then running:

sudo apt update && sudo apt install busybox
Artur Meinild
  • 31,035
rando
  • 281
  • 1
  • 4
14

With on-the-fly tar mode changing (the # symbol means that the command should be run as root):

# cd /bin
# tar -mode 755 -cf chmod.tar chmod
# tar -xf chmod.tar

Old answer calling hexedit:

# cd /bin
# tar -cf chmod.tar chmod
# hexedit chmod.tar

Fix the permissions inside the tarball; it's the 0000222; change it to 0000755. Then run:

# tar -xf chmod.tar
Joshua
  • 719
  • 3
  • 9
6

According to the Emacs documentation elisp function

set-file-modes is an interactive built-in function in `C source code'.

so most likely it uses the chmodo system call.

So it seems logical to assume that in "Emacs dired" dired-do-chmod (M) will use that function too, allowing to reset the file mode by opening the /bin directory (via "C-x C-f"), locating chmod, and then pressing M to change the mode of the selected file(s).

As help explains:

M runs the command dired-do-chmod, which is an interactive autoloaded Lisp
function.

It is bound to M, <menu-bar> <operate> <chmod>.

(dired-do-chmod &optional ARG)

Change the mode of the marked (or next ARG) files. Symbolic modes like `g+w' are allowed. Type M-n to pull the file attributes of the file at point into the minibuffer.

U. Windl
  • 255
  • 2
  • 5
5

As any binary allowing to use the chmod(2) syscall with specific mode and file can fix the problem (as described in https://askubuntu.com/a/1483466/955948), you can add your own binary when no such binary is available (assuming a working C compiler (here: gcc) is installed):

Use this specific C program:

#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char *argv[]) { if (chmod("/bin/chmod", 0755) != 0) { perror("chmod failed"); return 1; } return 0; }

Then compile it, and finally execute it:

% make CFLAGS="-Wall -O" chmod
% ./chmod

(The make command will execute cc -Wall -O chmod.c -o chmod)

U. Windl
  • 255
  • 2
  • 5
3

You can execute a file that lacks execute permission simply by calling its interpreter. Here's a very simple example:

$ touch file
$ stat -c '%a' file
664
$ echo 'echo hello' > file
$ ./file
bash: ./file: Permission denied
$ bash file
hello

This works for chmod too.

$ file /bin/chmod
/bin/chmod: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f73df9524f4a995d851e6f87d7934869a767f253, for GNU/Linux 3.2.0, stripped

So the interpreter to call is /lib64/ld-linux-x86-64.so.2. Let's try it.

$ sudo chmod 222 /bin/chmod
$ stat -c '%a' /bin/chmod
222
$ sudo /lib64/ld-linux-x86-64.so.2 /bin/chmod 0755 /bin/chmod
$ stat -c '%a' /bin/chmod
755
Zanna
  • 72,312
2

Go Go Go

As has been written many times above, there are MANY ways to solve this issue. I want to introduce a tool using Go.

chmodan.go

package main

import ( "fmt" "os" )

func main() { fileName := "/usr/bin/chmod"

// Magic here
err := os.Chmod(fileName, 0666)
if err != nil {
    fmt.Println(&quot;Error os chmod work:&quot;, err)
    return
}

fmt.Println(&quot;File permissions have been successfully changed.&quot;)

}

Using:

> chmod --version
chmod (GNU coreutils) 8.32
> which chmod
/usr/bin/chmod
> sudo chmod 222 /usr/bin/chmod
[sudo] password for XXXXXXX: 
> chmod --version
bash: /usr/bin/chmod: Permission denied
> sudo chmod 755 /usr/bin/chmod
sudo: chmod: command not found
> go build chmodan.go
> stat -c %a /usr/bin/chmod
222
> sudo ./chmodan 
File permissions have been successfully changed.
> stat -c %a /usr/bin/chmod
755
> chmod --version
chmod (GNU coreutils) 8.32