我遇到了一个错误,某些应用程序的配置文件没有被正确包含,因此为了尝试隔离文件中有问题的行,我将旧内容一次几行复制到新文件中。
最后,我制作了该文件的完全副本,但旧文件仍然无法工作,而新文件却可以正常工作。
更确切地说,如果我使用命令mv
将文件从存储位置移动到它想要的位置,则会导致错误。如果我使用cp
将文件复制到它想要的位置,则不会出现任何错误。
显然,诸如diff
、file
或 之类的内容ls -l
不会揭示两个文件之间的任何差异,因为一个是另一个的副本,只要cp
制作文件的精确副本。
我不能分享太多关于文件的信息,因为这是工作上的事情。最重要的是,这些命令cp fileA fileB
会mv fileA fileB
产生一个“不同的”文件 B。我最好的猜测是,文件 B 中的一些超低级属性在执行过程中被遗留了下来cp
(甚至cp -p
产生了相同的行为)。
就结果文件的确切内容而言,mv 与 cp 有何不同?
編輯:與ls -l
:
-rw-r--r--. 1 root root 3389 Aug 8 22:53 fileA
-rw-r--r--. 1 root root 3389 Aug 8 23:03 fileB
编辑:应用程序是 mysql,文件是 .cnf 文件,此配置文件中特别令人感兴趣的项是主从数据库复制中使用的二进制日志的名称。“错误”是“您未使用二进制日志记录”,因为没有二进制日志,因为 mysql 从未“读取”过该项。
我最初的想法是配置文件中存在语法错误,导致整个内容无法读取,这导致我通过复制文本块手动重新创建它
编辑:取得进展...最后文件有一些不同。
ls -lZ
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 server.cnf.bad
-rw-r--r--. root root unconfined_u:object_r:mysqld_etc_t:s0 server.cnf.good
答案1
TL;DR:在一个系统中SELinux正在使用中,系统使用的文件(即守护进程)应该使用 和而不是和进行复制cp -aZ
或移动。如果没有这样做,应该在目标上使用或来要求系统恢复默认的 SELinux 上下文。使用mv -Z
cp -a
mv
restorecon -v -r
restorecon -v -F -r
restorecon
在处理关键配置文件的脚本的末尾。
RHEL 及其大部分衍生产品默认使用 SELinux。
因此,为了解决您的问题,如果您的系统是基于 RHEL 的并且使用该mariadb-server
软件包,则只需在文件位于正确的地方:
# restorecon -v -F /etc/my.cnf.d/server.cnf
Relabeled /etc/my.cnf.d/server.cnf from unconfined_u:object_r:user_home_t:s0 to system_u:object_r:mysqld_etc_t:s0
(请注意,如果没有-F
它,它就不会改变unconfined_u
为已配置的system_u
。对于常见的系统来说,这并不重要。我对差异以及为什么它不重要了解并不多)。
在文件中放入正确的上下文只会增加更多的工作量其他地方。chcon
可以做到这一点(可以通过使用等来陈述-u
-t
,也可以通过从其他文件复制上下文来做到这一点--reference
):
# ls -lZ /home/test/server.cnf.bad
-rw-r--r--. 1 root root unconfined_u:object_r:user_home_t:s0 744 Apr 30 2017 /home/test/server.cnf.bad
# chcon -v -u system_u -t mysqld_etc_t /home/test/server.cnf.bad
changing security context of '/home/test/server.cnf.bad'
# ls -lZ /home/test/server.cnf.bad
-rw-r--r--. 1 root root system_u:object_r:mysqld_etc_t:s0 744 Apr 30 2017 /home/test/server.cnf.bad
如果您怀疑 SELinux 存在问题,请检查/var/log/audit/audit.log
包含与您的进程或文件相关的单词的条目denied
。您可以随时暂时要求 SELinux 允许操作,然后分别使用和来恢复它们setenforce Permissive
以setenforce Enforcing
比较行为。不要将其留在Permissive
生产环境中。
以下是各种解释...
示例以及处理配置文件时应做的事情
在启用 SELinux 的系统上具有各种cp
选项的 bahaviour 示例:mv
$ id
uid=1034(test) gid=1034(test) groups=1034(test)
$ pwd
/home/test
test@glasswalker:~$ ls -lZ foo
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0 0 Aug 11 11:25 foo
$ cp foo /tmp/foo1
$ cp --preserve=context foo /tmp/foo2
$ cp -a foo /tmp/foo3
$ cp -aZ foo /tmp/foo4
$ mv foo /tmp/foo5
$ ls -lZ /tmp/foo?
-rw-r--r--. 1 test test unconfined_u:object_r:user_tmpfs_t:s0 0 Aug 11 11:25 /tmp/foo1
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0 0 Aug 11 11:25 /tmp/foo2
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0 0 Aug 11 11:25 /tmp/foo3
-rw-r--r--. 1 test test unconfined_u:object_r:user_tmpfs_t:s0 0 Aug 11 11:25 /tmp/foo4
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0 0 Aug 11 11:25 /tmp/foo5
$ touch bar
$ ls -lZ bar
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0 0 Aug 11 11:49 bar
$ mv -Z bar /tmp
$ ls -lZ /tmp/bar
-rw-r--r--. 1 test test unconfined_u:object_r:user_tmpfs_t:s0 0 Aug 11 11:49 /tmp/bar
因此,当安全上下文确实重要且仍保留其他属性时,使用cp -aZ
或mv -Z
可以正常工作。移动系统文件的脚本应始终-Z
对任何cp
或mv
命令使用选项,否则仅restorecon
在最后一步使用以避免意外问题。
为什么会有这些差异呢?
该mv
命令保持一致的行为。如果它发生在同一个文件系统中,那么附加到文件的任何内容(包括其安全上下文)当然都不会被更改,因为它只是一个“重命名”。因此,在两个文件系统中,它实际上是复制然后删除,它还会复制附加到文件的任何未更改的内容,并且它知道这些内容,包括其安全上下文,以保持一致性。
默认情况下,命令cp
只是创建一个新文件,因此该文件照常继承父级的 selinux 上下文,除非另有说明,其中--preserve=context
包含-a
。可以使用选项--preserve=context
从中减去,因此复制整个树状图时最好的选择是使用,而不是如果 SELinux 确实很重要。-a
-Z
-aZ
-a
默认情况下,在创建文件时(通常情况下),这个新文件会继承其目录的 SELinux 上下文,这就是一切正常的原因(题外话:在极少数情况下,文件上下文应该与其目录的上下文不同,只是因为其名称上有规则,内核不会关心,像守护进程这样的程序restorecond
需要处理它)。
什么是 SELinux
SELinux 是一种强制访问控制机制(又称苹果) 除了所有其他机制(unix 权限又称数模转换器,又称访问控制列表访问控制列表等)。当一个进程在进程安全上下文中运行时,有一个“规则矩阵”来检查这个进程是否过程上下文可以对文件它试图发挥作用的背景。
OP 的情况示例:如果mysqld
的进程上下文仅允许访问少数文件上下文类型,则包括mysqld_etc_t
但不包括user_home_t
启动mysqld
将失败,因为它无法读取具有错误user_home_t
类型的配置文件。
在通常的系统上,这对于交互/登录用户来说并不重要,因为其通常的进程上下文不受限制,这意味着不适用任何 SELinux 规则。由systemd
或其他类似机制启动的每个守护进程将要接收进程上下文,可以使用 选项进行检查ps
。-Z
在运行 SELinux 的 Debian 系统上的示例:
# ps -Z -p $$
LABEL PID TTY TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 22498 pts/7 00:00:00 bash
# ps -Z -p $(pidof /sbin/getty)
LABEL PID TTY STAT TIME COMMAND
system_u:system_r:getty_t:s0 6158 tty1 Ss+ 0:00 /sbin/getty 38400 tty1
system_u:system_r:getty_t:s0 6159 tty2 Ss+ 0:00 /sbin/getty 38400 tty2
system_u:system_r:getty_t:s0 6160 tty3 Ss+ 0:00 /sbin/getty 38400 tty3
system_u:system_r:getty_t:s0 6161 tty4 Ss+ 0:00 /sbin/getty 38400 tty4
system_u:system_r:getty_t:s0 6162 tty5 Ss+ 0:00 /sbin/getty 38400 tty5
system_u:system_r:getty_t:s0 6163 tty6 Ss+ 0:00 /sbin/getty 38400 tty6
答案2
是的,有一个主要的区别:
- cp 复制文件
- mv(如果您停留在文件系统内)只是移动磁盘上的某些指针。
请尝试以下操作:
touch a
ls -i a
cp a b
ls -i a b
mv a c
ls -i b c
您将看到 b 是一个具有新 inode 编号的新文件,而 c 只是具有旧 a 的 inode 编号的同一个文件。
但这并不能解释你的奇怪行为。
答案3
这是什么可能正在发生(您分享的有关应用程序或这些错误的信息很少,所以我只能猜测)。
在 Linux 中强制文件锁定并不常见. 调用类似flock(2)
管理咨询锁。这意味着内核会跟踪锁,但不会强制执行,而是由应用程序来遵守它们。
如果某个东西被锁定fileA
,并且您的应用程序遵守该锁定,它可能会拒绝服务。我们假设这是发生的情况。
锁定会影响 inode,而不是路径或名称。将锁定的文件移动(重命名)fileA
到fileB
单个文件系统内不会对 inode 产生任何影响,文件仍处于锁定状态,应用程序仍拒绝使用它。复制文件会创建一个单独的文件,该文件fileB
有自己的 inode,但未被锁定,应用程序可以正常工作。
(注意:将文件移动到另一个文件系统实际上是复制+删除,因此如果有的话,它应该打破锁)。