导航:首页 > 操作系统 > linuxptrace

linuxptrace

发布时间:2023-03-27 21:30:57

linux系统top给出的信息都有哪些

Linux新手,个人认为首先就应该了解一下top命令各项的含义.
不用有事就问什么搜索引擎,先看看man top.
top - 16:12:56 up 1 day, 22 min, 4 users, load average: 0.02, 0.04, 0.05
Tasks: 158 total, 1 running, 156 sleeping, 0 stopped, 1 zombie
%Cpu(s): 0.7 us, 0.3 sy, 0.0 ni, 98.8 id, 0.1 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 1017912 total, 895892 used, 122020 free, 15312 buffers
KiB Swap: 1045500 total, 19608 used, 1025892 free. 230012 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5761 eechen 20 0 32144 1548 1076 R 6.2 0.2 0:00.01 top

16:12:56 up 1 day, 22 min, 4 users, load average: 0.02, 0.04, 0.05

这句等同于执行 uptime 命令返回的内容.
16:12:56 是当前时间(date).
up 1 day, 22 min 表示系统已经运行1天又22分钟(uptime -p).
4 users 表示当前登录系统的用户(w,who).
load average 表示系统负载,分别是1分钟,5分钟,15分钟前到现在的负载平均值.
Tasks: 158 total 表示系统的进程数(数目等于ps -ef|wc -l的值减去2),按大写H可以切换到线程模式.
running表示正在运行的进程,sleeping表示睡眠的进程,stopped表示暂停的进程,zombie表示已结束但还没有从进程表中删除的僵尸进程.
total表示总内存,used表示已经使用的内存,free表示空闲的内存,按E可以切换单位.
buffers(Buffer Cache)表示块设备的读写缓冲区占用的内存,cached(Page Cache)表示文件系统缓存占用的内存.
buffers:块设备缓冲 cached:文件系统缓存
如果cached的值很大,说明cache住的文件数很多.如果频繁访问到的文件都能被cache住,那么磁盘的读I/O就非常小.
所谓块设备是指对其信息的存取以"块"为单位,如通常的光盘,硬磁盘,软磁盘,磁带等,块长取512字节或1024字节或4096字节.
块设备可以直接通过块设备特别文件来访问,为了提高数据传输效率,块设备驱动程序内部采用块缓冲技术.
Swap是交换空间,交换空间在物理内存(RAM)被充满时被使用.
如果系统需要更多的内存资源,而物理内存已经充满,内存中不活跃的页就会被移到交换空间去.
虽然交换空间可以为带有少量内存的机器提供帮助,但是这种方法不应该被当做是对内存的取代.
交换空间位于硬盘驱动器上,它比进入物理内存要慢.
load average的理解:
load average指的是处于task_running或task_uninterruptible状态的进程(或线程)数的平均值.
处于task_running状态的进程(或线程),可能正在使用CPU或排队等待使用CPU.
处于task_uninterruptible状态的进程(或线程),可能正在等待I/O,比如等待磁盘I/O.这时I/O等待占用的CPU时间百分比iowait(wa)可能会比较高.
sudo strace -p `pidof top` 可见top从/proc读取了很多信息.
man proc 查看 /proc/loadavg 的说明:
man proc | col -b > proc.txt
/proc/loadavg 内容:
0.22 0.13 0.14 2/374 5306

0.22 0.13 0.14表示在过去的1分钟,5分钟,15分钟,
正在运行(task_running)或等待IO(task_uninterruptible)的任务的数量.
2/374中的2表示当前运行的线程数,374则表示系统当前存在的内核调度实体(进程/线程)的数量.
5306是系统最近创建的进程PID编号.
又比如:
load average: 31.09, 29.87, 29.92

表示在过去的1分钟,5分钟,15分钟的时间里,CPU任务队列中平均有30个程序(这里应该是30个java线程)在使用CPU.
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20248 root 20 0 0.227t 0.012t 18748 S 3090 5.2 29812:58 java

Java进程的CPU使用率%CPU达到3090%,表示这个Java进程正在使用31个CPU核心,
这样对上了上面load average得出的数据,也就是有30个左右的Java线程正在使用30个CPU核心.
按H(区分大小写)切换到线程模式,因为一个线程最多只能使用一个核心,所以线程模式下显示的CPU使用率不会超过100%.
当CPU和磁盘都忙不过来的时候,开再多的进程也没有任何意义,只会徒增CPU上下文切换和磁盘I/O等待,得不偿失.
系统负载高,普遍是因为系统进程数太多,I/O太多导致的.
load average小于1表示系统空闲,大于1表示系统开始繁忙.
Linux服务器的任务(进程)数量保持在200个以下是比较好的,最好不要超过300个.
us, user : time running un-niced user processes 用户空间进程占用CPU时间百分比
sy, system : time running kernel processes 内核进程占用CPU时间百分比
ni, nice : time running niced user processes 用户空间内改变过优先级的进程占用CPU时间百分比
id, idle : time spent in the kernel idle handler 空闲CPU时间百分比(100%表示系统完全空闲)
wa, iowait : time waiting for I/O completion I/O等待占用的CPU时间百分比
hi : time spent servicing hardware interrupts 硬件中断占用CPU时间百分比
si : time spent servicing software interrupts 软件中断占用CPU时间百分比
st : time stolen from this vm by the hypervisor 虚拟化hypervisor从当前虚拟机vm偷走的时间
如果st这个值很高的话,说明你的VPS提供商的CPU资源有限,而你没能抢过别人,很有可能就是VPS提供商超售了.

按F选择要显示的列和查看每列的含义,默认有下面这些列:
PID = Process Id
USER = Effective User Name
PR = Priority PR和NI的值越高越友好即越不竞争资源,比如PR 20和NI 0,另外,PR=NI+20.
NI = Nice Value 负值表示高优先级,正值表示低优先级,比如kworker的NI为-20,PR为0.
VIRT = Virtual Image (KiB)
RES = Resident Size (KiB) 常驻内存,按E切换单位.
SHR = Shared Memory (KiB)
S = Process Status
%CPU = CPU Usage 四核处理器在Tasks模式下满载为400%,在Threads模式(按H切换)下满载为100%(一个线程最多只能使用一个核心).按Shift+P按CPU使用率排序.
%MEM = Memory Usage (RES) 满载为100%,按Shift+M按RES内存排序.
TIME+ = CPU Time, hundredths 进程使用的CPU时间总计.比如2:32.45代表2分钟32.45秒.
COMMAND = Command Name/Line

按F进入域管理窗口后按A可以切换显示模式,按空格选中要显示的列,按S按指定列排序,用向右方向键选中列后可以调整顺序.修改后按Shift+W保存设置到~/.toprc文件.
top里面按Shift+M是按内存排序,按E是切换内存单位,按Shfit+W保存设置.
然后执行top -n1 -b可以看到按内存排序的所有进程的信息.
或者ps后用sort排序:
ps aux | sort -k4nr | head -n5

top里按C或者使用-c参数可以看到进程的绝对路径和启动参数,就可以得到类似ps -ef和ps aux提供的信息了.
看进程路径: top -p `pidof firefox` -c -n1
看进程线程: top -p `pidof firefox` -H -n1

Linux Process Status:
http://blog.csdn.net/tianlesoftware/article/details/6457487
R (task_running) : 可执行状态
S (task_interruptible): 可中断的睡眠状态
D (task_uninterruptible): 不可中断的睡眠状态
T (task_stopped or task_traced): 暂停状态或跟踪状态
Z (task_dead - exit_zombie): 退出状态,进程成为僵尸进程
X (task_dead - exit_dead): 退出状态,进程即将被销毁
running进程:
只有在该状态的进程才可能在CPU上运行。
而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中)。
进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU上运行。
很多操作系统教科书将正在CPU上执行的进程定义为RUNNING状态、而将可执行但是尚未被调度执行的进程定义为READY状态,这两种状态在Linux下统一为TASK_RUNNING状态。
sleeping进程:
处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。
这些进程的task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。
通过ps命令我们会看到,一般情况下,进程列表中的绝大多数进程都处于task_interruptible状态(除非机器的负载很高)。
毕竟CPU就这么一两个,进程动辄几十上百个,如果不是绝大多数进程都在睡眠,CPU又怎么响应得过来。
stopped进程:
向进程发送一个sigstop信号,它就会因响应该信号而进入task_stopped状态,除非该进程本身处于task_uninterruptible状态而不响应信号。
sigstop与sigkill信号一样,是非常强制的。不允许用户进程通过signal系列的系统调用重新设置对应的信号处理函数。
向进程发送一个sigcont信号,可以让其从task_stopped状态恢复到task_running状态。
当进程正在被跟踪时,它处于task_traced这个特殊的状态。“正在被跟踪”指的是进程暂停下来,等待跟踪它的进程对它进行操作。
比如在gdb中对被跟踪的进程下一个断点,进程在断点处停下来的时候就处于task_traced状态。而在其他时候,被跟踪的进程还是处于前面提到的那些状态。
对于进程本身来说,task_stopped和task_traced状态很类似,都是表示进程暂停下来。
而task_traced状态相当于在task_stopped之上多了一层保护,处于task_traced状态的进程不能响应sigcont信号而被唤醒。
只能等到调试进程通过ptrace系统调用执行ptrace_cont、ptrace_detach等操作(通过ptrace系统调用的参数指定操作),或调试进程退出,被调试的进程才能恢复task_running状态。
zombie进程:
在Linux进程的状态中,僵尸进程是非常特殊的一种,它是已经结束了的进程,但是没有从进程表中删除。
太多了会导致进程表里面条目满了,进而导致系统崩溃,倒是不占用其他系统资源。
它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,
仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。
进程在退出的过程中,处于TASK_DEAD状态。在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。
于是进程就只剩下task_struct这么个空壳,故称为僵尸。
之所以保留task_struct,是因为task_struct里面保存了进程的退出码、以及一些统计信息。
而其父进程很可能会关心这些信息。比如在shell中,$?变量就保存了最后一个退出的前台进程的退出码,而这个退出码往往被作为if语句的判断条件。
当然,内核也可以将这些信息保存在别的地方,而将task_struct结构释放掉,以节省一些空间。
但是使用task_struct结构更为方便,因为在内核中已经建立了从pid到task_struct查找关系,还有进程间的父子关系。
释放掉task_struct,则需要建立一些新的数据结构,以便让父进程找到它的子进程的退出信息。
子进程在退出的过程中,内核会给其父进程发送一个信号,通知父进程来“收尸”。
父进程可以通过wait系列的系统调用(如wait4、waitid)来等待某个或某些子进程的退出,并获取它的退出信息。
然后wait系列的系统调用会顺便将子进程的尸体(task_struct)也释放掉。
这个信号默认是SIGCHLD,但是在通过clone系统调用创建子进程时,可以设置这个信号。
如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,子进程的尸体(task_struct)也就无法释放掉。
如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。
但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
当进程退出的时候,会将它的所有子进程都托管给别的进程(使之成为别的进程的子进程)。
托管的进程可能是退出进程所在进程组的下一个进程(如果存在的话),或者是1号进程。
所以每个进程、每时每刻都有父进程存在。除非它是1号进程。1号进程,pid为1的进程,又称init进程。
Linux系统启动后,第一个被创建的用户态进程就是init进程。它有两项使命:
1、执行系统初始化脚本,创建一系列的进程(它们都是init进程的子孙);
2、在一个死循环中等待其子进程的退出事件,并调用waitid系统调用来完成“收尸”工作;
init进程不会被暂停、也不会被杀死(这是由内核来保证的)。它在等待子进程退出的过程中处于task_interruptible状态,“收尸”过程中则处于task_running状态。

Ⅱ 如何利用Ptrace拦截和模拟Linux系统调用

这里的“拦截”我指的是tracer能够改变系统调用参数,改变系统调用的返回值,甚至屏蔽特定的系统调用。这也就意亮蔽味着,一个tracer将能够完全实现自己的系统调用,这就非常有趣了,也就是说,一个tracer将可以模拟出一整套操作系统机制,而且这一切都不需要内核提供任何其他帮助。
但问题在于,一个进程一次只能够绑定一个tracer,因此我们无法在调试进程(GDB)的过程中模拟出一套外部操作系统,而另一个问题就是模拟系统调用将耗费更多的资源开销。
在敬罩州这篇文章中,我将主要讨论x86-64架构下闷晌的Linux Ptrace,并且我还会使用到一些特定的Linux扩展。除此之外,我可能会忽略错误检查,但最终发布的完整源码将会解决这些问题。

Ⅲ 怎样查询linux系统调用函数

以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数。这可能是你在互联网上所能看到的唯一一篇中文注释的Linux系统调用列表,即使是简单的字母序英文列表,能做到这么完全也是很罕见的。
按照惯例,这个列表以man pages第2节,即系统调用节为蓝本。按照笔者的理解,对其作了大致的分类,同时也作了一些小小的修改,删去了几个仅供内核使用,不允许用户调用的系统调用,对个别本人稍觉不妥的地方作了一些小的修改,并对所有列出的系统调用附上简要注释。
其中有一些函数的作用完全相同,只是参数不同。(可能很多熟悉C++朋友马上就能联想起函数重载,但是别忘了Linux核心是用C语言写的,所以只能取成不同的函数名)。还有一些函数已经过时,被新的更好的函数所代替了(gcc在链接这些函数时会发出警告),但因为兼容的原因还保留着,这些函数我会在前面标上“*”号以示区别。
一、进程控制:
fork 创建一个新进程
clone 按指定条件创建子进程
execve 运行可执行文件
exit 中止进程
_exit 立即中止当前进程
getdtablesize 进程所能打开的最大文件数
getpgid 获取指定进程组标识号
setpgid 设置指定进程组标志号
getpgrp 获取当前进程组标识号
setpgrp 设置当前进程组标志号
getpid 获取进程标识号
getppid 获取父进程标识号
getpriority 获取调度优先级
setpriority 设置调度优先级
modify_ldt 读写进程的本地描述表
nanosleep 使进程睡眠指定的时间
nice 改变分时进程的优先级
pause 挂起进程,等待信号
personality 设置进程运行域
prctl 对进程进行特定操作
ptrace 进程跟踪
sched_get_priority_max 取得静态优先级的上限
sched_get_priority_min 取得静态优先级的下限
sched_getparam 取得进程的调度参数
sched_getscheler 取得指定进程的调度策略
sched_rr_get_interval 取得按RR算法调度的实时进程的时间片长度
sched_setparam 设置进程的调度参数
sched_setscheler 设置指定进程的调度策略和参数
sched_yield 进程主动让出处理器,并将自己等候调度队列队尾
vfork 创建一个子进程,以供执行新程序,常与execve等同时使用
wait 等待子进程终止
wait3 参见wait
waitpid 等待指定子进程终止
wait4 参见waitpid
capget 获取进程权限
capset 设置进程权限
getsid 获取会晤标识号
setsid 设置会晤标识号

二、文件系统控制
1、文件读写操作
fcntl 文件控制
open 打开文件
creat 创建新文件
close 关闭文件描述字
read 读文件
write 写文件
readv 从文件读入数据到缓冲数组中
writev 将缓冲数组里的数据写入文件
pread 对文件随机读
pwrite 对文件随机写
lseek 移动文件指针
_llseek 在64位地址空间里移动文件指针
p 复制已打开的文件描述字
p2 按指定条件复制文件描述字
flock 文件加/解锁
poll I/O多路转换
truncate 截断文件
ftruncate 参见truncate
umask 设置文件权限掩码
fsync 把文件在内存中的部分写回磁盘
2、文件系统操作
access 确定文件的可存取性
chdir 改变当前工作目录
fchdir 参见chdir
chmod 改变文件方式
fchmod 参见chmod
chown 改变文件的属主或用户组
fchown 参见chown
lchown 参见chown
chroot 改变根目录
stat 取文件状态信息
lstat 参见stat
fstat 参见stat
statfs 取文件系统信息
fstatfs 参见statfs
readdir 读取目录项
getdents 读取目录项
mkdir 创建目录
mknod 创建索引节点
rmdir 删除目录
rename 文件改名
link 创建链接
symlink 创建符号链接
unlink 删除链接
readlink 读符号链接的值
mount 安装文件系统
umount 卸下文件系统
ustat 取文件系统信息
utime 改变文件的访问修改时间
utimes 参见utime
quotactl 控制磁盘配额

三、系统控制
ioctl I/O总控制函数
_sysctl 读/写系统参数
acct 启用或禁止进程记账
getrlimit 获取系统资源上限
setrlimit 设置系统资源上限
getrusage 获取系统资源使用情况
uselib 选择要使用的二进制函数库
ioperm 设置端口I/O权限
iopl 改变进程I/O权限级别
outb 低级端口操作
reboot 重新启动
swapon 打开交换文件和设备
swapoff 关闭交换文件和设备
bdflush 控制bdflush守护进程
sysfs 取核心支持的文件系统类型
sysinfo 取得系统信息
adjtimex 调整系统时钟
alarm 设置进程的闹钟
getitimer 获取计时器值
setitimer 设置计时器值
gettimeofday 取时间和时区
settimeofday 设置时间和时区
stime 设置系统日期和时间
time 取得系统时间
times 取进程运行时间
uname 获取当前UNIX系统的名称、版本和主机等信息
vhangup 挂起当前终端
nfsservctl 对NFS守护进程进行控制
vm86 进入模拟8086模式
create_mole 创建可装载的模块项
delete_mole 删除可装载的模块项
init_mole 初始化模块
query_mole 查询模块信息
*get_kernel_syms 取得核心符号,已被query_mole代替

四、内存管理
brk 改变数据段空间的分配
sbrk 参见brk
mlock 内存页面加锁
munlock 内存页面解锁
mlockall 调用进程所有内存页面加锁
munlockall 调用进程所有内存页面解锁
mmap 映射虚拟内存页
munmap 去除内存页映射
mremap 重新映射虚拟内存地址
msync 将映射内存中的数据写回磁盘
mprotect 设置内存映像保护
getpagesize 获取页面大小
sync 将内存缓冲区数据写回硬盘
cacheflush 将指定缓冲区中的内容写回磁盘

五、网络管理
getdomainname 取域名
setdomainname 设置域名
gethostid 获取主机标识号
sethostid 设置主机标识号
gethostname 获取本主机名称
sethostname 设置主机名称

六、socket控制
socketcall socket系统调用
socket 建立socket
bind 绑定socket到端口
connect 连接远程主机
accept 响应socket连接请求
send 通过socket发送信息
sendto 发送UDP信息
sendmsg 参见send
recv 通过socket接收信息
recvfrom 接收UDP信息
recvmsg 参见recv
listen 监听socket端口
select 对多路同步I/O进行轮询
shutdown 关闭socket上的连接
getsockname 取得本地socket名字
getpeername 获取通信对方的socket名字
getsockopt 取端口设置
setsockopt 设置端口参数
sendfile 在文件或端口间传输数据
socketpair 创建一对已联接的无名socket

七、用户管理
getuid 获取用户标识号
setuid 设置用户标志号
getgid 获取组标识号
setgid 设置组标志号
getegid 获取有效组标识号
setegid 设置有效组标识号
geteuid 获取有效用户标识号
seteuid 设置有效用户标识号
setregid 分别设置真实和有效的的组标识号
setreuid 分别设置真实和有效的用户标识号
getresgid 分别获取真实的,有效的和保存过的组标识号
setresgid 分别设置真实的,有效的和保存过的组标识号
getresuid 分别获取真实的,有效的和保存过的用户标识号
setresuid 分别设置真实的,有效的和保存过的用户标识号
setfsgid 设置文件系统检查时使用的组标识号
setfsuid 设置文件系统检查时使用的用户标识号
getgroups 获取后补组标志清单
setgroups 设置后补组标志清单

八、进程间通信
ipc 进程间通信总控制调用
1、信号
sigaction 设置对指定信号的处理方法
sigprocmask 根据参数对信号集中的信号执行阻塞/解除阻塞等操作
sigpending 为指定的被阻塞信号设置队列
sigsuspend 挂起进程等待特定信号
signal 参见signal
kill 向进程或进程组发信号
*sigblock 向被阻塞信号掩码中添加信号,已被sigprocmask代替
*siggetmask 取得现有阻塞信号掩码,已被sigprocmask代替
*sigsetmask 用给定信号掩码替换现有阻塞信号掩码,已被sigprocmask代替
*sigmask 将给定的信号转化为掩码,已被sigprocmask代替
*sigpause 作用同sigsuspend,已被sigsuspend代替
sigvec 为兼容BSD而设的信号处理函数,作用类似sigaction
ssetmask ANSI C的信号处理函数,作用类似sigaction
2、消息
msgctl 消息控制操作
msgget 获取消息队列
msgsnd 发消息
msgrcv 取消息
3、管道
pipe 创建管道
4、信号量
semctl 信号量控制
semget 获取一组信号量
semop 信号量操作
5、共享内存
shmctl 控制共享内存
shmget 获取共享内存
shmat 连接共享内存
shmdt 拆卸共享内存

Ⅳ linux内核有没有hook机制

有啊,一切顺序逻辑,都有被hook的可能。 下面是一个linux上的hook的实例

截获write系统调用:

#ifndefMODULE
#defineMODULE
#endif

#ifndef__KERNEL__
#define__KERNEL__
#endif
#include<linux/init.h>
#include<linux/mole.h>
#include<linux/version.h>
#include<linux/kernel.h>
#include<asm/unistd.h>
#include<linux/slab.h>
/*
#include<sys/types.h>
#include<asm/fcntl.h>
#include<linux/malloc.h>
#include<linux/types.h>
#include<linux/string.h>
#include<linux/fs.h>
#include<asm/errno.h>
#include<sys/syscall.h>
*/
MODULE_LICENSE("GPL");
structdescriptor_idt
{
unsignedshortoffset_low;
unsignedshortignore1;
unsignedshortignore2;
unsignedshortoffset_high;
};
staticstruct{
unsignedshortlimit;
unsignedlongbase;
}__attribute__((packed))idt48;
staticunsignedintSYS_CALL_TABLE_ADDR;
void**sys_call_table;
intbase_system_call;
int(*orig_write)(unsignedintfd,char*buf,unsignedintcount);
unsignedcharopcode_call[3]={0xff,0x14,0x85};
intmatch(unsignedchar*source)
{
inti;
for(i=0;i<3;i++){
if(source[i]!=opcode_call[i])
return0;
}
return1;
}
intget_sys_call_table(void)
{
inti,j;
unsignedchar*ins=(unsignedchar*)base_system_call;
unsignedintsct;

for(i=0;i<100;i++){
if(ins[i]==opcode_call[0]){
if(match(ins+i)){
sct=*((unsignedint*)(ins+3+i));
printk(KERN_ALERT"sys_call_tabl'saddressis
0x%X ",sct);
returnsct;
}
}
}

printk(KERN_ALERT"can'tfindtheaddressofsys_call_table ");
return-1;
}
inthacked_write(unsignedintfd,char*buf,unsignedintcount)
{
char*hide="hello";
if(strstr(buf,hide)!=NULL){
printk(KERN_ALERT"findname. ");
returncount;
}
else{
returnorig_write(fd,buf,count);
}
}
intinit_mole(void)
{
__asm__volatile("sidt%0":"=m"(idt48));
structdescriptor_idt*pIdt80=(structdescriptor_idt*)(idt48.base+8*0x80);
base_system_call=(pIdt80->offset_high<<16|pIdt80->offset_low);
printk(KERN_ALERT"system_calladdressat0x%x ",base_system_call);
SYS_CALL_TABLE_ADDR=get_sys_call_table();
sys_call_table=(void**)SYS_CALL_TABLE_ADDR;
orig_write=sys_call_table[__NR_write];
sys_call_table[__NR_write]=hacked_write;
return0;
}
voidcleanup_mole()
{
sys_call_table[__NR_write]=orig_write;
}

Ⅳ linux内核态,在LSM框架中的文件操作hook接口中如何获取一个正在被操作的文件的内容(linux4.4版本)

LSM是Linux Secrity Mole的简称,即linux安全模块。其是一种轻量级通用访
问控制框架,适合于多种访问控制模型在它上面以内核可加载模块的形实现。用
户可以根据自己的需求选择合适的安全模块加载到内核上实现。

LSM设计思想:
LSM的设计思想:在最少改变内核代码的情况下,提供一个能够成功实现强制访
问控制模块需要的结构或者接口。LSM避免了利用如在systrace系统调用中的出
现过的系统调用干预,因为它不能扩展到多处理器内核,并且它受制于参数替换
攻击。还有LSM在设计时做了两点考虑:对不使用的人来说尽量少引入麻烦,对
使用的人来说要带来效率。以Linus Torvalds为代表的内核开发人员对Linux安

全模块(LSM)提出了三点要求:
1、真正的通用,当使用一个不同的安全模型的时候,只需要加载一个不同的内
核模块。
2、概念上简单,对Linux内核影响最小,高效,并且。
3、能够支持现存的POSIX.1e capabilities逻辑,作为一个可选的安全模块。
还有,针对linux上提出的各种不同的Linux安全增强系统对Linux安全模块(LSM
)提出的要求是:能够允许他们以可加载内核模块的形式重新实现其安全功能,

并且不会在安全性方面带来明显的损失,也不会带来额外的系统开销。
LSM框架结构:
LSM框架主要由五部分构成:
1、在特定的内核数据结构中加入安全域。
2、在内核源代码中不同的关键点插入对安全钩子函数的调用。
3、加入一个通用的安全系统调用。
4、提供了函数允许内核模块注册为安全模块或者注销。
5、5、将capabilities逻辑的大部分移植为一个可选的安全模块。
安全域是一个void*类型的指针,它使得安全模块把安全信息和内核内部对象联
系起来。下面列出被修改加入了安全域的内核数据结构,以及各自所代表的内核

内部对象:
task_struct结构:代表任务(进程)
linux_binprm结构:代表程序
super_block结构:代表文件系统
inode结构:代表管道,文件,或者Socket套接字
file结构:代表打开的文件
sk_buff结构:代表网络缓冲区(包)
net_device结构:代表网络设备
kern_ipc_perm结构:代表Semaphore信号,共享内存段,或者消息队列
msg_msg:代表单个的消息

Linux安全模块(LSM)提供了两类对安全钩子函数的调用:一类管理内核对象的
安全域,另一类仲裁对这些内核对象的访问。对安全钩子函数的调用通过钩子来
实现,钩子是全局表security_ops中的函数指针,这个全局表的类型是
security_operations结构,这个结构定义在include/linux/security.h这个头
文件中。
LSM接口的核心是security_ops,当系统启动时,他们被初始化为传统的DAC策略
。传统DAC访问控制是指控制系统中的主体(如进程)对系统中的客体(如文件
目录、文件)的访问(读、写和执行等)。自主访问控制DAC 是指主体(进程,
用户)对客体(文件、目录、特殊设备文件、IPC等)的访问权限是由客体的属
主或超级用户决定的,而且此权限一旦确定,将作为以后判断主体对客体是否有

访问权限的依据。
在加载安全模块时,我们必需先对模块进行注册,我们可以使用
register_security()函数向LSM注册一个安全模块。在我们的模块被加载成
功后,就可以进行访问控制操作。如果此时还有一个安全模块要使用
register_security()函数进行加载,则会出现错误,直到使用
unregister_security()函数向框架注销后,下一个模块才可以载入。当然LS
M还提供了mod_reg_security()函数和mod_unreg_security()函数,可以连续注
册多个安全模块。如果有其他后来的模块需要载入,可以通过mod_reg_security
()向第一个模块注册,形成支持不同策略的模块栈。
注:以上出现的函数均基于2.6.22以前的版本,对于后续的版本,出现了
register_security()函数未被导出或者取消掉了unregister_security()函数。
LSM执行过程:
根据下图的执行步骤:用户在执行系统调用时,先通过原有的内核接口依次执行
功能性的错误检查,接着进行传统的DAC检查,并在即将访问内核的内部对象之
前,通过LSM钩子函数调用LSM。LSM再调用具体的访问控制策略来决定访问的合
法性。图三显示了LSM钩子的调用:

图三:基于LSM的内核对象访问过程

Lilinux安全模块(LSM)主要支持"限制型"的访问控制决策:当Linux内核授予
文件或目录访问权限时,Linux安全模块(LSM)可能会拒绝,而当 Linux内核拒
绝访问时,可以跳过LSM。

========

使用LSM实现自己的访问控制

首先对LSM 进行简单介绍。虽然linux下的各位基本都知道一些,但是还要罗嗦
一下。
LSM中文全称是linux安全模块。英文全称:linux security mole.
LSM是一种轻量级、通用的访问控制框架,适合多种访问控制模型以内核模块的
形式实现。其特点是通用、简单、高效、支持POSIX。1e能力机制。
LSM的架构图如下:

通过系统调用进入内核之后,系统首先进行传统的权限检查(传统权限检查主要
是基于用户的,用户通过验证之后就可以访问资源),通过之后才会进行强制访
问控制。(强制访问控制是不允许主体干涉的一种访问控制,其采用安全标识、
信息分级等信息敏感性进行访问控制。并且通过比较主体的级别和资源的敏感性
来确定是否允许访问。比如说系统设置A用户不允许访问文件B,即便A是文件B的
所有者,访问也是受限制的。)从图上看来,LSM实现访问控制主要通过安全模
块的钩子函数实现。

LSM框架主要由五部分组成:这个网上资料很多。
在关键的特定内核数据结构中加入了安全域;
在内核源码中不同的关键点处插入对安全钩子函数的调用;
提供了一个通用的安全系统调用;
提供了注册和注销函数,使得访问控制策略可以以内核模块方式实现;
将capabilities逻辑的大部分功能移植为一个可选的安全模块。

我们这里重点结合源码对LSM框架进行解释。我使用的源码是3.5.4
首先介绍安全域字段,它是一个空类型的指针,在内核中的很多内核结构中都存
在,比如inode、superblock、dentry、file等等。类型字段为void *
security;
那么安全域怎么和安全模块中的信息关联起来?
当安全模块加载之后,安全域中的指针便指向安全模块中的安全信息。这里以
selinux为例进行介绍。
内核里面security/selinux/include/objsec.h中定义了不同对象的安全信息,
格式为XXX_security_strut.

上面的文件的安全信息里面包含打开文件描述符时的安全ID、文件所有者的安全
ID等等。
要联系安全模块中安全信息和安全域需要几个控制钩子函数。这些钩子函数实现
了对内核关键信息的设置和管理。这里主要介绍alloc_security、
free_security。
selinux里面通过实现安全信息空间分配实现关联。比如以文件安全信息为例
这里分配空间成功之后,通过file->f_security = fsec实现了关联。
撤销关联是在安全模块卸载之后调用file_free_security.

这里具体通过设置file->f_secrity为NULL,然后释放安全信息结构实现。
现在来看看内核如何实现selinux的访问控制。这里主要就是实现LSM里面的钩子
函数了。LSM里面给出了结构体security_operations,里面给出了很多钩子函数
,实现了相关钩子函数就可以实现访问控制了。

上面的函数就实现了file_permission钩子函数。可以看下inode结构体的获得,
感受内核是通过文件->目录项->inode。该函数主要实现自己的访问控制策略就
OK 了。
哪selinux来说,在获得文件安全ID之后,主要对掩码和文件打开时相关的安全
信息进行检测,符合就通过访问控制。
selinux基本实现了LSM里面的所有钩子函数,待钩子函数实现后,对LSM里面钩
子域进行填充就OK了。

做完以上这些还需要注册安全模块到LSM,这里注册和注销使用了
register_security和unregister_security。
比如selinux在注册时使用语句register_security(&selinux_ops)实现。

接下来通过上面的分析我们可以实现简单的基于LSM的访问控制。
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mole.h>
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <linux/fcntl.h>
#include <linux/uaccess.h>
#include <linux/file.h>
#include <linux/namei.h>

static int lsm_test_file_permission(struct file *file,int mask)
{
int path=0;
struct file *filp;
struct nameidata nd;

path = path_lookup(FILENAME,LOOKUP_FOLLOW,&nd);

if(!mask)
return 0;

if(path)
{
printk("lookup file failed!\n");
return -1;
}

filp = filp_open("/home/yuyunchao/code/sb.c",O_RDONLY,0);
{
printk("open failed!\n");
}
return 0;
}

static struct security_operations lsm_test_security_ops = {
.file_permission = lsm_test_file_permission,
};

static int __init lsm_file_init(void)
{
if(register_security(&lsm_test_security_ops)){
printk("register error ..........\n");
return -1;
}

printk("lsm_file init..\n ");
return 0;
}

static void __exit lsm_file_exit(void)
{
if(unregister_security(&lsm_test_security_ops)){
printk("unregister error................\n");
return ;
}

printk("mole exit.......\n");
}

MODULE_LICENSE("GPL");
mole_init(lsm_file_init);
mole_exit(lsm_file_exit);
========

LSM(Linux Security Mole)应用方法(简单例子)

LSM在内核中很多地方已经插入了hook函数,并且在security.c函数中声明了
security_ops结构,要实现你自己的安全模块,只需要定义你自己的struct
security_operations,并且用register_security注册即可,下面举个简单例子

test.c代码如下:
/*
* Test Linux Security Mole
*
* Author: penghuan <[email protected]>
*
* Copyright (C) 2010 UbuntuKylin, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/

#include <linux/security.h>
#include <linux/sysctl.h>
#include <linux/ptrace.h>
#include <linux/prctl.h>
#include <linux/ratelimit.h>
#include <linux/workqueue.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/dcache.h>
#include <linux/path.h>

int test_file_permission(struct file *file, int mask)
{
char *name = file->f_path.dentry->d_name.name;
if(!strcmp(name, "test.txt"))
{
file->f_flags |= O_RDONLY;
printk("you can have your control code here!\n");
}
return 0;
}

static struct security_operations test_security_ops = {
.name = "test",

.file_permission = test_file_permission,
};

static __init int test_init(void)
{
printk("enter test init!\n");

printk(KERN_INFO "Test: becoming......\n")

if (register_security(&test_security_ops))
panic("Test: kernel registration failed.\n");

return 0;
}

security_initcall(test_init);

将该文件以模块的形式放到security/下编译进内核,启用新的内核后,当你操
作文件test.txt时,通过dmesg命令就能再终端看到”you can have your
control code here!“输出
所以一般的做法是:定义你自己的struct security_operations,实现你自己的
hook函数,具体有哪些hook函数可以查询include/linux/security.h文件,然后
调用register_security来用你的test_security_ops初始化全局的security_ops
指针

楼主,我刚开始研究LSM,但网上资料太少,您这个代码,我编译成ko文件老是
有警告,并且insmod时,说Unknown symbol register_security。我最近看了看
内核模块变成,没有对内核进行太深入的了解。不知能否把LSM的实验步骤给出
的再详细点,谢谢。

你需要把代码编进内核

是需要把那段源码拷到内核目录下,然后重新编译内核?。。没有不编译内核的
方法吗?。。直接按照模块进行编译。另外那个test.txt放在哪个文件夹里?。

是需要把那段源码拷到内核目录下,然后重新编译内核?。。没有不编译内核的
方法吗?。。直接按照模块进行 ...

是的,你去网上找下怎么把模块编进内核,lsm模块不能以模块方式加载,涉及
安全;test.txt是测试文件,当你把代码编进内核后,用新内核启动,然后操作
test.txt文件,就会有输出,test.txt随便放哪里

楼主,您好,我刚开始学习lsm模块,把您的模块编译进内核,新的内核加载后
,register_security总是失败,请问下可能是什么原因导致的。我的内核版本
是3.13.11。

register_security的返回值是-11

========

LSM在Linux中的实现方式
LSM(Linux Secure Model)一种轻量级访问控制机制.
其实现方式有如在系统调用中加入一个后门....
方式如下:
static struct file *__dentry_open(struct dentry *dentry, struct

vfsmount *mnt,
struct file *f,
int (*open)(struct inode *, struct file *),
const struct cred *cred)
{
struct inode *inode;
int error;
...............................................................
error = security_dentry_open(f, cred); //LSM机制实现方式,在此加入了

一个LSM函数.

//security_dentry_open的实现如下,相当于一个接口,对一个函数指针再

//封装一下.

//只返回是与否,这样的控制信息.
if (error)
goto cleanup_all;
................................................................
return f;
cleanup_all:
.................................................................
return ERR_PTR(error);
}
//========简单封装一个指针结构体===========================
int security_dentry_open(struct file *file, const struct cred *cred)
{
int ret;
ret = security_ops->dentry_open(file, cred);
if (ret)
return ret;
return fsnotify_perm(file, MAY_OPEN);
}

========

利用LSM实现更安全的linux

LSM的全称是Linux Security Moles,它是linux内核中用来支持更灵活的

安全策略的一个底层框架,虽然听起来比较复杂,但是可以就把它理解成一组安

插在linux内核的钩子函数和一些预留的被称为安全域的数据结构,下面先说说

这个框架的由来吧。

linux本身的机制就保证了linux拥有更好的安全机制,但是在这个机制下面

,还是隐藏了许多的问题:

1、权限粒度太大。用过linux的人应该对0644这样的访问权限设置不陌生,

它对能够操作这个文件的用户做了限制,但是这个只是限制到了组,而没有更进

一步的细分,当然,如果LSM只是用来限制这个的话,那么也就太没意思了,因

为实现文件更细的控制粒度,ACL就能够很出色的完成,顺便提一下,ACL有一个

分配的限制,如果哪位朋友需要用ACL进行粒度更细的访问权限控制的话,可能

需要注意一下这方面的东西。

2、root用户的权限太大。在linux中,root用户就是至高无上的,他拥有对

机器的完全控制权限,可以做他想做的一切事情。但是很多时候,我们可能并不

希望有root有这么大的权限,比如在现在比较流行的云存储中,用户肯定不希望

服务提供商能够随意访问我们的文件,那么这个时候,就需要对root用户进行一

定的设置了。

由于这些问题的存在,所以出现了像SE Linux(Securiy Enhanced Linux )

这样的增强补丁。但是每个系统对于具体安全细节的控制不尽相同, 所以Linus

Tovalds 提出应该要有一个 Linux 内核所能接受的安全框架来支持这些安全策

略,这个安全框架应该提供包含内核数据结构中的透明安全域以及用来控制、维

护安全域操作的安全钩子,于是就有了LSM。

LSM在内核中的位置,可以用下图来表示:

当用户态程序调用某些操作系统提供的函数的时候,比如read()函数,其会

对应于内核中的一个系统调用,然后该首先会进行一些常规的错误检测,接着进

行DAC(Discretionary Access Control)检测,再接着它会进行LSM检测。从上

图中能够看出来,LSM其实是一个非常底层的安全策略框架,利用LSM,可以接管

所有的系统调用,这样,我们就能对包括root在内的所有用户的权限进行控制,

并且实现粒度更细的访问权限控制。

当系统初始化的时候,LSM就是一个空的框架,它不提供任何的检测,其所

做的全部工作几乎就是返回0,当然,有些不带返回值的函数除外。而我们则可

以针对自己特定的需求来编写LSM,然后将我们编写的LSM钩子函数,通过其数据

结构struct security_operations注册到系统中去,这样,我们的LSM检测就开

始起作用了。
更多信息可参考《Linux就该这么学》

Ⅵ 求linux ptrace函数的详细介绍

推荐http://blog.chinaunix.net/u2/67414/showart_1716467.html去学习用法,有例子

在用户模式中,虽然只有一个函数可用,即ptrace(int _request, pid_t _pid, caddr_t _addr, int _data),但是这个函数能做所有的事情!如果你愿意,也可以花费几个小时来编写自己的小调试器,以解决特定的问题。

ptrace函数的_request参数是最重要的一个参数,因为它确定你将做什么。BSD和Linux的头文件使用不同的定义,这使得将ptrace应用从一个平台移植到另一个平台变得很复杂。默认地,我们使用BSD头文件中的定义。

r PT_TRACE_ME(PTRACE_TRACEME)将当前进程切换到停止状态。它通常总是与fork/exec一起使用,虽然也能遇到自我追踪的应用程序。对于每一个进程,PT_TRACE_ME只能被调用一次。追踪一个正被追踪的进程是会失败的(另一个较不重要的结果是进程不能追踪它自己。如果要这样做,应该首先从自身派生一个进程)。大量的反调试技术都是以这一事实为基础的。为了克服这类技术,必须使用绕过ptrace的调试器。一个信号被发送到正被调试的进程,并将该进程切换到停止状态,该进程可以使用从父进程上下文中调用的PT_CONTINUE和PT_STEP命令从停止状态退出。wait函数会延迟父进程的执行,直到被调试的进程切换为停止状态或者终止为止(终止时,返回值为1407)。其他的所有参数都被忽略。

r PT_ATTACH(PTRACE_ATTACH)将进程标志为pid的运行进程切换为停止状态,在这种情形下,调试器进程成为“父进程”。其他的所有参数都被忽略。进程必须具有与调试进程相同的用户标志(UID),并且不能是setuid/setid进程(否则就要用root来调试)。

r PT_DETACH(PTRACE_DETACH)停止进程标志为pid进程(由PT_ATTACH和PT_TRACE_ME指定)的调试,并继续其常态运行。其他的所有参数都被忽略。

r PT_CONTINUE(PTRACE_CONT)继续进程标志为pid的被调试进程的执行,而不中断与调试器进程的通信。如果addr == 1(在Linux中为0),从上次停止的地址继续执行;否则,从指定的地址继续执行。参数_data指定发送到被调试进程的信号数量(零说明没有信号)。

r PT_STEP(PTRACE_SINGLESTEP)进行进程标志为pid的进程的单步执行,即执行下一条机器指令并切换为停止状态(在i386中,这是根据设置追踪标志来实现的,虽然有些“黑客”函数库使用硬件断点)。BSD要求将参数addr置为1,而Linux要求将该参数置为0。其他的所有参数都被忽略。

r PT_READ_I和PT_READ_D(PTRACE_PEEKTEXT和PTRACE_PEEKDATA)分别从代码区和正被调试进程的地址空间区读取机器字。在许多当代的平台中,这两个指令是等价的。ptrace函数接嫌键收目标地址addr,并芹桥巧返回读到的结果。

r PT_WRITE_I和PR_READ_D(PTRACE_POKETEXT和PTRACE_POKEDATA)将由_data传入的机器字写入addr所指定的地址。

r PT_GETREGS,PT_GETFPREGS和PT_GETDBREGS(PTRACE_GETREGS,PTRACE_ FPREGS和PT_GETFPXREGS)将一般用途寄存器、段寄存器和调试寄存器的值读入到地址由_addr指针所指定的调试器进程的内存区中。只有i386平台接收这些与系统相关的命令。寄存器结构的描述放在头文件machine/reg.h文件中。

r PT_SETREGS,PT_SETFPREGS和PT_SETDBREGS(PTRACE_SETREGS,PTRACE_ SETFPREGS和PT_SETFPXREGS)通过拷贝由_addr指针所指定的内存区域的内容来设置被调消册试进程的寄存器的值。

r PT_KILL(PTRACE_KILL)将sigkill发送到被调试进程,以终止其执行。

Ⅶ linux禁止gdb调试

禁止在 Linux 中 gdb 调试的方法有许多,以下是其中的一种方法:

1. 禁用 core mp:可以通过以下命令将 core mp 禁用:

```
ulimit -c 0
```

这将确保应用程序在芦碧举崩溃时不会生成任何 core mp 文件。gdb 通常需要访问 core mp 文件来执行调试操作,因此禁用它们可以帮助防止调试。

2. 使用 ptrace:慧察ptrace 系统调用可以被用来执行程序间的跟踪和调试,因此禁用它可以防止 gdb 调试。为了禁用 ptrace,可以在 /etc/sysctl.conf 文件中添加以下内容:

```
kernel.yama.ptrace_scope = 1
```

然后更新 sysctl.conf 文件,使设置生效:

```
sudo sysctl -p
```

这将限制 ptrace 仅在其父进程和子进程之间(或在具有适当权限的特权用户之间)进行。这样可以防止普通用户使用 gdb 调试其他用户、系统进程或其他特权进程。

请注意,以上方法仅仅是防止 gdb 调试的其中一种方法,还有其陪碧他方法可以绕过这些限制。因此,禁止 gdb 调试并不能完全保证系统的安全性和机密性。如果您对系统安全性有更高的要求,建议请咨询专业安全人员提供更加严格的安全策略。

阅读全文

与linuxptrace相关的资料

热点内容
教孩子学编程ppt 浏览:812
77服务器怎么找 浏览:990
国外免费电影网站 浏览:913
java负数二进制 浏览:670
单片机多字节加减程序 浏览:151
手机网店用什么APP好 浏览:926
周星驰粤语资源 浏览:520
莱美健身教练app叫什么 浏览:887
有道词典forlinux 浏览:203
汇开优店的代理app叫什么 浏览:141
如何体验原生态的安卓 浏览:847
精致lee滤波源码 浏览:851
美颜都用什么app 浏览:139
单片机内存 浏览:554
mci命令 浏览:651
风月片洗发店 浏览:833
台湾电影,一个双腿残疾的人 浏览:737
消失的眼睛电影在线看 浏览:530
安卓导航如何升级系统 浏览:991
电影邪恶 浏览:896