Что делать, если я случайно запустил команду & ldquo; chmod -R & rdquo; в системных каталогах (/, / etc, & hellip;)

Я случайно запустил

sudo chmod 755 -R /

вместо

sudo chmod 755 -R ./

Я остановил его через несколько секунд, но теперь есть некоторые проблемы, такие как

sudo: must be setuid root

Как я могу вернуть разрешения обратно?

65
задан 29 July 2015 в 14:11

9 ответов

Одним словом: вы не можете, переустановите свою систему.

Я имею в виду, что разрешения Posix используются и сильно зависят от них; в файловой системе есть множество мест, где неправильные разрешения могут нарушить работу операционной системы (SUID-флаги) или, что еще хуже, сделать ее уязвимой с точки зрения безопасности (/etc/ssh/ssh_host_rsa_key), в то время как она, кажется, работает нормально.

Следовательно, такое восстановление сложно сделать должным образом. Пропустите одну вещь - и вы все испортите. Вы уже напортачили со своей командой sudo chmod (если это ваша подруга, а не вы, то она тоже может выучить какой-нибудь урок Linux) - и это очень простая команда. Правильное восстановление потребует гораздо большего количества команд и гораздо большей бдительности. Даже если вы используете чей-то скрипт.

- так что поверьте мне, просто переустановите. Это безопасная ставка и гарантированно убережет вас от неприятностей.


Наконец, здесь уместны некоторые советы.

Во-первых: переустановка будет менее болезненной, если в следующий раз вы установите свой /home на отдельный раздел . На самом деле, это будет просто ветерок.

Во-вторых: подумайте о том, чтобы сделать сумасшедшую Linux science в виртуальной машине , такой как VirtualBox, и сделайте свои снимки.

Третий: chmod -R . работает. Точка сама по себе . является действительным именем каталога. Нет никакой реальной необходимости добавлять этот слэш. Вы могли бы избежать катастрофического риска пропустить точку искренне;
. просто chmod: пропущенный операнд после '755' VS разрушенная система.

61
ответ дан 29 July 2015 в 14:11

Я написал и уже несколько лет использую пару Ruby скриптов для rsync разрешений и прав собственности. Скрипт get-filesystem-acl собирает всю информацию, рекурсивно обходя все файлы и помещает все это в файл .acl. Скрипт .acl-restore прочитает .acl и применит все chown и chmod.

Вы можете запустить get-filesystem-acl в аналогичной установке Ubuntu, а затем скопировать файл .acl на ваш ящик chmod, поставить .acl и . acl-restore в /, и запустите .acl-restore.

Вам нужен корень, так что исправьте ваше sudo, как предложил Марко Сеппи.

Я могу сгенерировать и дать вам . acl для моего Ubuntu.

get-filesystem-acl

#!/usr/bin/ruby

RM   = "/bin/rm"
SORT = "/usr/bin/sort"
TMP  = "/tmp/get_acl_#{Time.now.to_i}_#{rand * 899 + 100}"

require 'find'

IGNORE = [".git"]

def numeric2human(m)
  return sprintf("%c%c%c%c%c%c%c%c%c",
            (m & 0400 == 0 ? ?- : ?r),
            (m & 0200 == 0 ? ?- : ?w),
            (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
                             (m & 04000 == 0 ? ?x : ?s)),
            (m & 0040 == 0 ? ?- : ?r),
            (m & 0020 == 0 ? ?- : ?w),
            (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
                             (m & 02000 == 0 ? ?x : ?s)),
            (m & 0004 == 0 ? ?- : ?r),
            (m & 0002 == 0 ? ?- : ?w),
            (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
                             (m & 01000 == 0 ? ?x : ?t)))
end


File.open(TMP, "w") do |acl_file|

  # TODO: Instead of the current dir, find the .git dir, which could be
  #       the same or outside of the current dir
  Find.find(".") do |path|

    next if IGNORE.collect {|ig| !!(path[2..-1] =~ /\A#{ig}/)}.include? true
    next if File.symlink?(path)

    stat = File.lstat(path)
    group_id = stat.gid
    rules    = "#{type}#{numeric2human(stat.mode)}" 

    acl_file.puts "#{path} #{rules} #{owner_id} #{group_id}"
  end
end

`#{SORT} #{TMP} > .acl`
`#{RM}   #{TMP}`

.acl-restore

#!/usr/bin/ruby

# This script will only work with .acl_ids

# Restore from...
FROM  = ".acl"

MKDIR = "/bin/mkdir"
CHMOD = "/bin/chmod"
CHOWN = "/bin/chown"
known_content_missing = false


def numeric2human(m)
  return sprintf("%c%c%c%c%c%c%c%c%c",
            (m & 0400 == 0 ? ?- : ?r),
            (m & 0200 == 0 ? ?- : ?w),
            (m & 0100 == 0 ? (m & 04000 == 0 ? ?- : ?S) :
                             (m & 04000 == 0 ? ?x : ?s)),
            (m & 0040 == 0 ? ?- : ?r),
            (m & 0020 == 0 ? ?- : ?w),
            (m & 0010 == 0 ? (m & 02000 == 0 ? ?- : ?S) :
                             (m & 02000 == 0 ? ?x : ?s)),
            (m & 0004 == 0 ? ?- : ?r),
            (m & 0002 == 0 ? ?- : ?w),
            (m & 0001 == 0 ? (m & 01000 == 0 ? ?- : ?T) :
                             (m & 01000 == 0 ? ?x : ?t)))
end

def human2chmod(mode)
  raise unless mode =~ /([r-][w-][xtsTS-])([r-][w-][xtsTS-])([r-][w-][xtsTS-])/
  triple = [$1, $2, $3]
  u,g,o = triple.collect do |i|
    i.sub('s', 'sx').sub('t', 'tx').downcase.gsub('-', '')
  end

  return "u=#{u},g=#{g},o=#{o}" 
end



File.open(FROM).each do |acl|
  raise unless acl =~ /\A(([^ ]*? )+)([^ ]+) ([^ ]+) ([^ ]+)\Z/
  path, rules, owner_id, group_id = $1, $3, $4, $5
  path = path.strip
  owner_id = owner_id.to_i
  group_id = group_id.to_i

  if !File.exists?(path) and !File.symlink?(path)
    if rules =~ /\Ad/
      STDERR.puts "Restoring a missing directory: #{path}"
      STDERR.puts "Probably it was an empty directory. Git goes not track them."
      `#{MKDIR} -p '#{path}'` # Creating the any parents
    else
      known_content_missing = true
      STDERR.puts "ERROR: ACL is listed but the file is missing: #{path}"
      next
    end
  end

  s = File.lstat(path)
  t = s.ftype[0..0].sub('f', '-') # Single character for the file type
                                  # But a "-" istead of "f"

  # Actual, but not neccesarely Desired 
  actual_rules    = "#{t}#{numeric2human(s.mode)}"
  actual_owner_id = s.uid 
  actual_group_id = s.gid 

  unless [actual_rules, actual_owner_id, actual_group_id] ==
    [rules, owner_id, group_id]

    chmod_argument = human2chmod(rules)

    # Debug
    #p chmod_argument
    #p s.mode

    ## Verbose
    puts path
    puts "Wrong: #{[actual_rules, actual_owner_id, actual_group_id].inspect}"
    puts "Fixed: #{[rules, owner_id, group_id].inspect}"
    `#{CHMOD} #{chmod_argument} '#{path}'`

    #puts
  end

end

if known_content_missing
  STDERR.puts "-" * 80 
  STDERR.puts "Some files that are listed in #{FROM.inspect} are missing in " +
              "the current directory."
  STDERR.puts
  STDERR.puts "Is #{FROM.inspect} outdated?"
  STDERR.puts "(Try retrograding the current directory to an earlier version)"
  STDERR.puts
  STDERR.puts "Or is the current directory incomplete?"
  STDERR.puts "(Try to recover the current directory)"
  STDERR.puts "-" * 80 
end
27
ответ дан 29 July 2015 в 14:11

Я бы попытался переустановить все пакеты с apt-get install --reinstall, возможно, используя вывод dpkg --get-selections | grep install, чтобы получить их список.

4
ответ дан 29 July 2015 в 14:11

В длинном: можно. Вам нужно будет смонтировать файловую систему с Live CD и начать возвращать разрешения в соответствующих местах. Как минимум, чтобы получить sudo обратно, вам нужно запустить sudo chmod u+s /usr/bin/sudo во время сессии LiveCD - это исправит необходимость в setuid root.

Однако, скорее всего, будет проще просто переустановить систему.

13
ответ дан 29 July 2015 в 14:11

Хорошо, я не тестировал это (так что используйте на свой страх и риск), но это все равно может работать. Я протестирую это на виртуальной машине, когда у меня будет возможность:

Во-первых, в все еще работающей системе я сделал следующее, чтобы получить все права доступа к файлам в списке, пропустив / home / directory:

sudo find / -not -path /home -printf "%m:%p\0" > /tmp/fileper.log

Это напечатает разрешения и имя файла для каждого файла или каталога в системе, за которым следует символ \ 0 (это понадобится позже, чтобы иметь дело со странными именами файлов, например, содержащими новые строки).

Затем в системе, где права доступа к файлам были скомпрометированы:

while IFS=: read -r -d '' perm file; do  
    chmod "$perm" "$file"
done < /tmp/fileper.log 

Будет прочитана каждая строка из fileper.log , а разрешения будут сохранены как $ perm и имя файла как $ file , а затем установит права доступа к файлу (или каталогу) в соответствии с тем, что было указано в fileper.log


Несколько вещей, на которые следует обратить внимание:

  • Хотя вывод в файл: /tmp/fileper.log , возможно, вы перечисляете пользовательские настройки, процедуру и т. д.
  • вы не можете загружаться или запускать команды,

Wh Я бы предложил загрузить LiveCD с версией Linux, которая у вас есть на вашем диске, запустить команду, изменить путь к тому месту, где у вас смонтирован локальный диск, и запустить вторую команду!


Я тестировал это при загрузке с CD / USB Ubuntu, я могу выбрать не форматировать диск, то есть он заменит все в каталоге / , НО пропустит каталог / home / . Это означает, что ваши пользователи сохранят конфигурацию приложений / ДАННЫХ (Музыка, Видео, Документы) без изменений. И при замене системных файлов chmod устанавливается на правильный номер.

4
ответ дан 29 July 2015 в 14:11

Многие из ответов являются проблематичными, потому что они требуют sudo, но sudo не работает. Вы не можете использовать sudo для исправления sudo. Другие ответы требуют перезагрузки компьютера с использованием Live CD или режима восстановления, что неудобно.

Другой вариант - использовать pkexec для доступа к оболочке с правами root.

  1. Запустите pkexec bash в терминале, чтобы получить оболочку с правами root.

  2. Установите бит setuid:

    chmod u+s /usr/bin/sudo
    
  3. sudo теперь должно быть доступно для любых дальнейших ремонтов, которые могут потребоваться.

0
ответ дан 29 July 2015 в 14:11

(Я знаю, что не должен комментировать в ответе, но не достаточно репутации, чтобы комментировать)

blade19899 ответ сработал для меня, за исключением симлинков. Например, он применил 755 к /bin/bash, но затем применил 777 к симлинку /bin/rbash, фактически 777-ing /bin/bash.

Так как у меня уже был файл fileper.log, я просто изменил команду назначения:

while IFS=: read -r -d '' perm file; do  
    if [[ ! -L "$file" ]]; then    
        chmod "$perm" "$file"
    fi
done < /tmp/fileper.log 
3
ответ дан 29 July 2015 в 14:11

Вы можете попробовать восстановить разрешения с помощью apt-get .

Если вы не можете запустить эти команды с sudo, возможно, вам придется загрузиться в режим восстановления и запустить их от имени пользователя root.

Для загрузки в режим восстановления см. https: // wiki.ubuntu.com/RecoveryMode.

От http://hyperlogos.org/page/Restoring-Permissions-Debian-System

Примечание. Первоначально это было размещено на форумах Ubuntu, но я не могу найти исходное сообщение.

Попробуйте по порядку,

sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1`

Если это не удастся:

sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | egrep -v '(package1|package2)'`

И, наконец, в крайнем случае,

sudo dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | xargs apt-get --reinstall -y --force-yes install

Использование apt-get

Вот соответствующий фрагмент, EDITED FOR ПРАВИЛЬНОСТЬ и переформатировано:

 sudo apt-get --reinstall install `dpkg --get-selections |  grep install |  grep -v deinstall |  вырезать -f1`
 

Допустим, вы получаете сообщения о том, что некоторые пакеты не могут быть переустановлены, и команда не выполняется. Вот один из способов исправить это, пропустив указанные пакеты:

 sudo apt-get --reinstall install `dpkg --get-selections |  grep install |  grep -v deinstall |  cut -f1 |  egrep -v '(пакет1 | пакет2)' '
 

И, наконец, если вы каким-то образом должны установить так много вещей, что приведенная выше команда не сможет сказать, что ваш список аргументов слишком длинный, вот исправление, которое будет запускать apt-get гораздо чаще, чем вам хотелось бы:

 sudo  dpkg --get-selections |  grep install |  grep -v deinstall |  cut -f1 |  xargs apt-get --reinstall -y --force-yes установить
 

Обратите внимание на параметры -y и - force-yes , которые не позволяют apt-get снова и снова запрашивать вас. Это всегда забавные варианты, если вы уверены, что знаете, что делаете.

3
ответ дан 29 July 2015 в 14:11

Есть закрытый вопрос (с отличным ответом), дублирующий этот из:

Поэтому я отдаю должное Тердону , но вот мой собственный ответ, основанный на его.

Во время разработки нового скрипта переменная $ TMP_DIRECTORY / дала неожиданный результат ] / . За ним последовали chmod 700 и chown -R $ UDO_USER , указывающие на $ TMP_DIRECTORY , что на самом деле было / .

Система медленно разбился и сгорел. После этого он не перезагружался. Все кричат ​​«НЕОБХОДИМО ПЕРЕУСТАНОВИТЬ», но это означает потерю многих лет работы. Этот сценарий представляет собой вариант ответа Тердона:

#!/bin/bash

if [[ $(id -u) != 0 ]]; then # root powers needed to call this script
    echo >&2 "$0 must be called with sudo powers"
    exit 1
fi

# Parameters blank?
[[ $1 == "" ]] && echo "Parm 1 must be source directory" && exit 1
[[ $2 == "" ]] && echo "Parm 2 must be target directory" && exit 1

# Parameters valid directories?
[[ ! -d "$1" ]] && echo "Parm 1 must be a directory" && exit 1
[[ ! -d "$2" ]] && echo "Parm 2 must be a directory" && exit 1
# [[ ! "$2" == "/mnt/"* ]] && echo "Parm 2 must start with /mnt/..." && exit 1

# shopt -s globstar     # From original
shopt -s dotglob
liveSystem="$1"
deadSystem="$2"

# Parameters must end in same subdirectory
[[ "${liveSystem##*/}" != "${deadSystem##*/}" ]] && \
    echo "subdirectory ${liveSystem##*/} not same as ${deadSystem##*/}" && \
    exit 1

cd "$deadsystem"
Count=0
NoRef=0
one() {
    path="$1"
    MountlessPath="${path##*$deadSystem/}"
    if [ -e "$liveSystem/$MountlessPath" ] ; then
        echo chown --reference "$liveSystem/$MountlessPath" "$path"
        echo chmod --reference "$liveSystem/$MountlessPath" "$path"
        (( Count++ ))
    else
        echo "No reference for: $path"
        (( NoRef++ ))
    fi
}

# From: https://stackoverflow.com/questions/51654041/loop-through-all-files-in-a-directory-and-subdirectories-using-bash
# Note typo "If" instead of "if" in above link
recurse() {
  path="$1"
  if [ -d "$path" ] ; then
#     echo "Path: $path"
     one "$path"            # Enhancement: chown of directories too
     for i in "$path/"* # "$path/."* # Enhancement: do hidden directories
     do
        # Skip over .. which gives endless loop
        [[ "$path" == *".cache/speech-dispatcher"* ]] && continue
        [[ "$path" == *"/usr/bin/X11"* ]] && continue
        BaseName=${path##*/}
        [[ "${#BaseName}" -gt 300 ]] && continue
#        [[ ${#BaseName[@]} -gt 1 ]] && continue
#        echo BaseName: $BaseName
#        [[ $BaseName == ".." || $BaseName == "*" ]] && continue
        recurse "$i"
     done
# Original code selected only files but we want links too
#  elif [ -f "$path" ] ; then
  else
    [ ! -f "$path" ] && printf "Not a file -> "
    one "$path"
  fi
}

recurse "$deadSystem"

echo "========================================================================"
echo "$Count references found for chown command to process"
echo "$NoRef files, directories and links, etc. could not be processed"
# From: https://unix.stackexchange.com/questions/193368/can-scp-create-a-directory-if-it-doesnt-exist/193372?noredirect=1#comment1111576_193372
# Original didn't have much luck?
#for file in **/*; do 
#    [ -e "$liveSystem/$file" ] &&
#        echo sudo chown --reference "$liveSystem/$file" "$file"
#done

При запуске сценария с $ sudo reset-owner / mnt / old / var / var | grep "No reference" хвостовая часть говорит следующее:

Not a file -> No reference for: /var/tmp/systemd-private-fdbc599820b645f4a461404675af3b5d-rtkit-daemon.service-jvV8tG/tmp/*
No reference for: /var/tmp/systemd-private-fdbc599820b645f4a461404675af3b5d-systemd-timesyncd.service-vmgqTh
No reference for: /var/tmp/systemd-private-fdbc599820b645f4a461404675af3b5d-systemd-timesyncd.service-vmgqTh/tmp
Not a file -> No reference for: /var/tmp/systemd-private-fdbc599820b645f4a461404675af3b5d-systemd-timesyncd.service-vmgqTh/tmp/*
No reference for: /var/tmp/uefi.dat
No reference for: /var/tmp/uefi.dsl
========================================================================
12369 references found for chown command to process
7676 files, directories and links, etc. could not be processed

Каким бы устрашающим ни казалось, потребовался всего час, чтобы разобраться со всем этим. К тому времени, как я закончил, у меня осталось следующее:

$ sudo reset-owner /mnt/old/var /var | grep "No reference" | grep -v /var/tmp/ | grep -v /var/spool/ | grep -v '\/\*' | grep -v /var/run | grep -v /unattended | grep -v /upstart | grep -v /log/journal | grep -v /log/pm | grep -v /log/cron | grep -v /log/dpkg | grep -v /log/apt | grep -v /log/altern | grep -v /lib/u | grep -v /lib/systemd | grep -v /lib/snapd | grep -v /lib/shim | grep -v /lib/NetworkManager | grep -v /lib/lightdm | grep -v /lib/initram | grep -v /lib/dpkg | grep -v /lib/doc-base | grep -v /var/lib/dkms | grep -v /lib/blue | grep -v /lib/binfmts | grep -v /lib/apt | grep -v /lib/app-info | grep -v /lib/Accounts | grep -v /var/crash | grep -v /var/cache
No reference for: /var
No reference for: /var/lib/flashplugin-installer
No reference for: /var/lib/gems
No reference for: /var/lib/gems/2.3.0
No reference for: /var/lib/git
No reference for: /var/lib/tlp/rfkill-saved
0
ответ дан 5 January 2021 в 23:53

Другие вопросы по тегам:

Похожие вопросы: