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?

3
  • 12
    What I find most fascinating is the ingenuity of the answers here. So far there are 8 different ways to restore 755 permissions to chmod. Commented Aug 23, 2023 at 19:16
  • 1
    @U.Windl: It's one finger misposition off chmod 111, which is sane.
    – Joshua
    Commented Aug 24, 2023 at 16:54
  • @ArturMeinild and that's why blacklisting specific commands while allowing general command execution is never a good strategy.
    – muru
    Commented Mar 12 at 9:43

9 Answers 9

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)'
    
8
  • 17
    Option 4 is very simple, and there are several languages that are likely to be available: python, perl, php.
    – Barmar
    Commented Aug 23, 2023 at 13:23
  • 2
    +1 for mentioning my favorite clever solution: using cp to just copy a different binary with appropriate permissions and overwrite it
    – Josh
    Commented Aug 25, 2023 at 1:20
  • 4
    Why is 2 your preferred solution? The others seem easier. Commented Aug 25, 2023 at 5:31
  • 1
    @AugustJanse : 2 is way more flexible and powerfull: could help restore many things from a sane distro (permissions, suid, owners, etc, using that distro as a reference) Commented Aug 25, 2023 at 7:39
  • 2
    @AugustJanse I just think it's a "proper" or "canonical" (nothing related to a company name ;)) way to fix such an issue. The first is an overkill, the two others are a bit "hackish". And as mentioned in the comment above, this method is generally used to fix many other broken things.
    – raj
    Commented Aug 25, 2023 at 8:32
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
9
  • Re: dynamic loader: On Debian, and I assume Ubuntu as well, /usr/bin/ld.so does the same thing, so the slightly simpler ld.so /bin/chmod 755 /bin/chmod would suffice!
    – marcelm
    Commented Aug 23, 2023 at 20:31
  • 1
    AFAIK using the dynamic loader requires that /bin/chmod still has read permission I think? So that method would work for mode 6xx or 4xx but not 2xx Commented Aug 23, 2023 at 22:51
  • 2
    @steeldriver, and Raffa, it still needs to, yes (cp /bin/ls ./ls; chmod 0 ./ls; /lib64/ld-linux-x86-64.so.2 ./ls and I get an error). But if you're running it as root, you get to ignore such pesky details as the permission bits, as root usually does, so it works there. Nothing to do with the dynamic loader being special here. (That's not to say it wouldn't be special when the kernel loads it as part of the normal process of executing a binary file, but that's what we're doing here.)
    – ilkkachu
    Commented Aug 24, 2023 at 7:01
  • 1
    @ilkkachu Ah I see what you mean, ... It should be invoked as the super user with sudo as in the example in my answer.
    – Raffa
    Commented Aug 24, 2023 at 7:03
  • 1
    @U.Windl, if you mean the command in the answer above: sudo /lib64/ld-linux-x86-64.so.2 /bin/chmod, then yes, ld-linux-x86-64.so.2 can read it because it's being run as root via sudo, and root is exempt from the permission bits checks on reading. With cat /bin/chmod >chmod.copy, and given the mode 0222 (-w--w--w-), you won't be able to read it (as a regular user), since no-one has read access on it. Also, even if you do sudo sh -c 'cat /bin/chmod >chmod.copy', the new file gets created without the x permission because normally programs don't add it when creating files.
    – ilkkachu
    Commented Aug 24, 2023 at 9:45
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.

1
  • 7
    "and only after that should you run commands on your production system." One thousand upvotes!
    – chili555
    Commented Aug 22, 2023 at 13:09
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
5
  • probably better to use chmod 0755 to restore the permissions to what they originally were, instead of just adding the execute permission and leaving the other permissions off
    – ilkkachu
    Commented Aug 24, 2023 at 6:57
  • 2
    @raj, I did wonder. Part of the reason I suggested in a comment was that I seem to have it on every Ubuntu I have access to, even ones where I don't think anyone would have explicitly installed it. The package descriptions say busybox-static is Priority: standard, which I guess it means it should be installed by default but perhaps someone will correct me.
    – ilkkachu
    Commented Aug 24, 2023 at 12:49
  • 1
    @ilkkachu Yes, indeed busybox is being shipped by default with Ubuntu for quiet a while now.
    – Raffa
    Commented Aug 24, 2023 at 15:41
  • @ilkkachu busybox has been included in most Linux distros to make initramfs generation easy.
    – rando
    Commented Aug 24, 2023 at 18:39
  • @ilkkachu Indeed, it is. I assumed it's not because why anybody would need it by default on a general purpose, non space-limited system? But I have checked on my system (where I definitely did NOT install it) and it is there.
    – raj
    Commented Aug 24, 2023 at 19:33
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
3
  • Doesn't mode 222 prevent reading the file?
    – U. Windl
    Commented Aug 24, 2023 at 8:58
  • 1
    @U.Windl: root don't care. (Intentional misspelling because meme)
    – Joshua
    Commented Aug 24, 2023 at 14:03
  • 4
    Ubuntu's GNU tar supports changing permissions on-the-fly i.e. sudo tar --mode 0755 -cf chmod.tar /bin/chmod.
    – Raffa
    Commented Aug 24, 2023 at 15:37
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.
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)

4
  • 3
    C compiler and other build tools are not installed in Ubuntu by default; you need to install them first. It's better to use some programming language that is already available with the default installation, like Perl or Python.
    – raj
    Commented Aug 24, 2023 at 10:29
  • The OP did not make a statement whether it was a "default" installation. Of course perl -e "chmod 0755, '/bin/chmod'" would work, too. But one could also compile the needed binary on another machine. The binary, specifically when stripped, is probably less than 8kB in size.
    – U. Windl
    Commented Aug 24, 2023 at 13:40
  • 2
    if you can copy it from another system, with the copy getting the x permission bit (and being compatible wrt. any dynamic libraries), then you could likely just copy /bin/chmod from that other system and not need to compile anything. scp -p /bin/chmod target: or so.
    – ilkkachu
    Commented Aug 24, 2023 at 14:32
  • @ilkkachu A compatible executable copy of the binary should be available through APT download ... i.e. mkdir extracted && apt download coreutils && dpkg-deb -xv coreutils*.deb extracted for instance.
    – Raffa
    Commented Aug 24, 2023 at 15:56
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
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("Error os chmod work:", err)
        return
    }

    fmt.Println("File permissions have been successfully changed.")
}

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .