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
  • 32,237
  • 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. – Artur Meinild Aug 23 '23 at 19:16
  • 1
    @U.Windl: It's one finger misposition off chmod 111, which is sane. – Joshua Aug 24 '23 at 16:54
  • @ArturMeinild and that's why blacklisting specific commands while allowing general command execution is never a good strategy. – muru Mar 12 '24 at 09:43

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
  • 10,353
  • 17
    Option 4 is very simple, and there are several languages that are likely to be available: python, perl, php. – Barmar Aug 23 '23 at 13:23
  • +1. I had to discover option 3 for myself back in the 90s on a SCO Unix system after I'd (accidentally) removed execute permission from everything in /bin by mistake. The emergency boot disk had executable binaries on it, but not a copy of chmod! – TripeHound Aug 23 '23 at 16:58
  • 2
    +1 for mentioning my favorite clever solution: using cp to just copy a different binary with appropriate permissions and overwrite it – Josh Aug 25 '23 at 01:20
  • 4
    Why is 2 your preferred solution? The others seem easier. – August Janse Aug 25 '23 at 05: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) – Olivier Dulac Aug 25 '23 at 07: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 Aug 25 '23 at 08:32
  • Isn’t /tmp mounted noexec in Ubuntu? – user3840170 Aug 25 '23 at 14:02
  • @user3840170 /tmp usually isn't a separate filesystem at all. It's just a regular directory under the root filesystem, at least in default install. – raj Aug 25 '23 at 14:22
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
  • 32,237
  • 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 Aug 23 '23 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 – steeldriver Aug 23 '23 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 Aug 24 '23 at 07: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 Aug 24 '23 at 07:03
  • yes exactly, sudo makes the execution work here. (and of course that should be "that's not what we're doing here." at the end of my last comment, blah.) – ilkkachu Aug 24 '23 at 07:29
  • @ilkkachu and @steeldriver ... In the sense of reading the file initially yes, both of you are right, but sudo or super user is needed anyway for that and for setting permissions on /bin/chmod as well ... I was talking about particularly the loading and running/executing part hence the special notation ... I wasn't talking about the reading part though, my bad :-). – Raffa Aug 24 '23 at 08:15
  • @ilkkachu I updated the comment: I wonder: Given the mode 222 (-w--w--w-) can ld read it? And if it can, couldn't you simply copy it to elsewhere using umask 0222; cat /bin/chmod >chmod.copy, and finally chmod.copy 0755 /bin/chmod; rm chmod.copy? – U. Windl Aug 24 '23 at 09:35
  • 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 Aug 24 '23 at 09:45
  • @ilkkachu You are right: I was assuming all non-masked bits would be set when creating a new file. – U. Windl Aug 24 '23 at 10:05
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
  • 26,018
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
  • 26,018
rando
  • 281
  • 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 Aug 24 '23 at 06: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 Aug 24 '23 at 12:49
  • 1
    @ilkkachu Yes, indeed busybox is being shipped by default with Ubuntu for quiet a while now. – Raffa Aug 24 '23 at 15:41
  • @ilkkachu busybox has been included in most Linux distros to make initramfs generation easy. – rando Aug 24 '23 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 Aug 24 '23 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
Joshua
  • 709
  • 3
  • 8
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
  • 243
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
  • 243
  • 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 Aug 24 '23 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 Aug 24 '23 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 Aug 24 '23 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 Aug 24 '23 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
Zanna
  • 70,465
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