检查命令是否由用户直接运行

时间:2015-11-20 05:16:14

标签: c linux linux-kernel kernel

出于教育原因,我想改变kill的行为。如果用户直接在shell中键入它,则不会发生任何事情。如果某个其他程序/实体 - 谁不是用户调用它,它会正常执行。包装if语句可能就足够了,但我在if中添加了什么?

编辑我不想在shell中执行此操作。我在问内核编程。

在内核源line 2296中,定义了kill。我将在代码里面包装一个if语句。在该声明中,应该检查一下,调用它的人是用户还是只是某个进程。检查是我不知道如何实施的部分。

关于安全性

目标:

  • 阻止用户直接从任何shell
  • 调用kill
  • 字面上其他一切都很好,不会被阻止

3 个答案:

答案 0 :(得分:4)

虽然其他答案在技术上是正确的,但我认为他们对这个问题过于严格。你想做的事情是不可能以100%可靠的方式做到,但你可以通过做出一些合理的假设来达到目的。

具体来说,如果您将交互式kill定义为:

  • 由登录用户拥有的进程调用
  • 直接从一个名为shell的进程调用(它可能是一个新进程,或者它可能是一个内置操作)
  • 由连接到串行/伪终端(可能也属于登录用户)的进程调用

然后你可以在处理系统调用时检查每个属性,并以这种方式做出选择。

有些方法不可靠(sudo + expect + sh应该适用于大多数这些检查),但它可能足以让你玩得开心。如何实施这些检查是一个较长的故事,可能每一点都值得拥有自己的问题。查看有关用户和pty设备的文档 - 这应该会给你一个好主意。

编辑:实际上,这可能甚至可以作为LKM实现。 Selinux可以做类似的检查。

答案 1 :(得分:2)

看起来你很困惑,不明白究竟是什么system call以及Linux计算机是如何工作的。 Everything 某个进程通过系统调用 中完成。

  

应检查是否有人直接通过用户或某个流程来完成此操作

上面的句子毫无意义。一切都是通过一些系统调用完成的。用户的概念仅作为流程的“属性”存在,请参阅credentials(7)(因此“由用户直接完成”是模糊的)。阅读syscalls(2)并花几天时间阅读Advanced Linux Programming,然后提出一个更有针对性的问题。

(我真的相信你不应该在不知道上面的ALP书正在解释什么的情况下不敢修补内核;那么你会以不同的方式提出你的问题)

您应该花几天或几周阅读Operating SystemsComputer Architecture。您需要更准确地了解计算机的工作原理,这需要花费很多时间(可能很多years),这里的任何答案都无法涵盖所有​​这些。

当用户键入kill时,他可能使用内置shell(类型which killtype kill)并且shell调用kill(2)。当用户键入/bin/kill时,execve(2)是一个将调用kill(2)的程序。并且该命令可能不是来自终端(例如echo kill $$ | sh,然后该命令来自管道,或者echo kill 1234|at midnight在用户交互之外发生杀死并且没有任何用户以交互方式使用计算机,从/var/spool/cron/atjobs/中的某个文件读取命令,请参阅atd(8))在这两种情况下,内核只能看到SYS_kill系统调用。

BTW,修改内核在kill上的行为可能会影响很多系统软件,所以在这样做时要小心。另请阅读signal(7)(某些信号不是来自kill(2))。

您可以使用isatty(STDIN_FILENO)(请参阅isatty(3))来检测程序是否在终端中运行(无需修补内核,您只需修补shell)。但我给了几个不是的情况。您和您的用户也可以编写一个桌面应用程序(使用GTK或Qt)调用kill(2)并在桌面上启动(运行时可能没有连接任何终端,请阅读X11

另见会话概念和setsid(2);最近基于systemd的Linux有一个我不熟悉的multi-seat概念(我不知道哪些内核与它有关)。

如果您只想更改运行某些(已识别的)shell的交互式终端的行为,则只需更改shell-with chsh(1) - (例如,修改它以删除其kill内置,也许是为了避免shell执行/bin/kill kill_ok_by_cred},无需修补内核。但是这不会禁止高级用户编写一个调用execve(2)的小型C程序(甚至用C编写自己的shell并使用它),编译他的C源代码,并运行他刚编译的{{3}可执行文件另请参阅bash中的kill(2)

如果您只想通过练习修补内核并更改ELF系统调用的行为来学习,则需要定义要过滤的过程。所以考虑制作restricted shell系统调用的流程,而不是“用户”(流程确实有多个用户ID)

BTW,修补内核非常困难(如果你希望它是可靠和安全的),因为根据定义它会影响整个Linux系统。经验法则是避免在可能的情况下修补内核 ....在您的情况下,看起来修补shell可能足以实现您的目标,所以更喜欢修补shell(或者修补shell)所有shell实际使用的kill(2) ...)修补内核。另请参阅kill(2)

也许你只是希望你的修补内核使用libc系统调用来拒绝LD_PRELOAD tricks 1234(假设你的用户的uid是1234)(所以他需要{{3}可执行文件),但你的问题不是这样制定的。这可能很容易实现,可能是通过添加 if (uid_eq(1234, tcred->uid)) return 0; (在Linux 4.4文件uid附近的第692行),就像

一样简单
{{1}}

但我可能完全错了(除了一些驱动程序,我从来没有修补内核)。肯定会在几个小时kill(2)给出一个更权威的答案。

答案 2 :(得分:1)

您可以使用别名来更改命令的行为。别名仅适用于交互式shell。 Shell脚本忽略它们。例如:

$ alias kill='echo hello'
$ kill
hello

如果您希望别名始终可用,您可以将其添加到~/.bashrc(或者如果您的shell不是bash,则为等效文件)。