6.3 进程管理与调度命令
6.3.1 可执行文件的setuid、setgid权限和目录的sticky属性
在UNIX/Linux系统中,用户级别和执行权力是相关的。但是有些工作,如修改/etc/passwd和/etc/shadow文件等,对于普通用户也是必需的,因为它要修改自己的密码。但是,系统中的这些文件对于普通用户是不允许有写操作的,于是就出现了让普通用户通过某种机制行使超级用户权限的问题。
1.suid和sgid权限
1)概念
对于可执行文件,有些文件还有另外两个与执行有关的属性:
(1)设置用户ID权限:setuid/suid。
(2)设置组ID权限:setgid/sgid。
当一个程序具有suid属性时,它执行时的uid将是该程序所有者的uid,即有效uid,记为euid;而执行者原来的uid称为真实uid,记为ruid。此时,程序的执行者具有程序所有者的权限。
当一个程序具有sgid属性时,它执行时的gid将是该程序的gid,即有效gid,记为egid;而执行者原来的gid称为真实gid,记为rgid。此时,程序的执行者具有程序所有者所在组的权限。
suid/sgid属性只对二进制可执行文件有效,对可执行的脚本文件无效。
当一个属于超级用户的可执行二进制程序具有suid属性时,在一般用户执行它时,也就相当于有了超级用户的身份和权限。同样,当一个属于超级用户所在组的可执行二进制程序具有sgid属性时,则当一般用户执行它时,相当于有了该组员的身份和权限。由此可见,suid和sgid权限的存在可能会给某些程序的执行带来方便,因为权限被放大了,但这也是一种危险,因为过大的权力可能会给系统的安全带来隐患,因此设置这种权限的可执行二进制程序不宜太多。
常用设置suid的程序是/bin/ping、/usr/bin/passwd、/usr/bin/newgrp、/usr/sbin/suexec、/usr/bin/sudo和/usr/sbin/traceroute等被公用的但又必须具有较高权限的程序。
2)管理
按照文件的权限,若用八进制表示,它的u、g、o的读、写和执行权限可分别表示为400、40、4,200、20、2和100、10、1,对应于suid和sgid的权限则为4000和2000。
suid和sgid对应的权限也是用chmod来管理的。设myp1、myp2、myp3的权限分别为:-rwxr-xr-x(755)、-rwxrwxr-x(775)和-rwxrwxrwx(777),则可用以下方法设置suid和sgid权限。
(1)字符方式:
#chmod u+s myp1 #为myp1设置suid。修改后权限为rwsr-xr-x #chmod g+s myp2 #为myp2设置sgid。修改后权限为rwxrwsr-x #chmod ug+s myp3 #为myp3同时设置suid和sgid。修改后权限为rwsrwsrwx
(2)数字方法:
#chmod 4755 myp1 #为myp1设置suid #chmod 2775 myp2 #为myp2设置sgid #chmod 6777 myp3 #为myp3同时设置suid和sgid
2.sticky位
1)概念
在4位八进制权限的最高1位的3位二进制数中,已经被suid和sgid各用去了1位,还剩下1位,这1位在UNIX/Linux系统中可以分别用来描述目录或文件的另一个属性。当用于描述目录时,被叫做限制删除位;当用于描述可执行文件时,被叫做黏着位。为了描述方便,把它统一称为sticky位或sticky权限。
当一个目录具有sticky权限时,它内部的文件只能被其所有者或超级用户删除、更名或移动。当一个可执行文件具有sticky权限时,在早期的系统中,程序执行时的正文段映像将被锁在交换区中,可使程序安装更快速。
设置黏着位的目录有/tmp、/usr/tmp和/var/spool/uucppublic等。
2)管理
sticky位的属性值为1000,可通过chmod命令设置。设目录mydir和文件myfile的权限为755,则可通过以下方法来设置它的sticky位。
#chmod+t mydir myfile #字符方式。修改后权限为1755或rwxr-xr-t #chmod 1755 mydir myfile #数字方式
3.查找
用户可以使用find命令查找系统具有suid、sgid和sticky权限的文件,方法如下:
find/-perm+1000-print #仅查找具有sticky位者 find/-perm+2000-print #仅查找具有sgid权限者 find/-perm+4000-print #仅查找具有suid权限者 find/-perm+6000-print #仅查找具有suid和sgid权限者 find/-perm+7000-print #查找具有suid、sgid和sticky 3种权限者
6.3.2 进程管理与调度命令
1.查询进程状态(ps)
1)功能与用法
ps命令的功能是显示进程状态和信息,给出系统当前正在运行进程信息的快照,可以配合kill命令结束系统中失控或不必要的进程。ps命令支持多种UNIX系统格式的个性化显示方式,其用法为:
ps [ options ]
2)参数说明
ps命令的参数繁多,部分参数如表6-2所示。
表6-2 ps命令的部分参数
3)进程的状态
在ps命令的输出信息中的状态标志如表6-3所示。
表6-3 在ps命令的输出信息中的状态标志
4)示例
#ps-t tty1 #查询与终端(tty1)相关的进程信息 #ps-ef|more #查询系统中的所有命令及参数 #ps-f-u gjshao #查询与用户(gjshao)相关的信息 #ps-axj #查询整个系统内的进程信息情况
2.按名称向进程发信号或终止进程的执行(killall)
1)功能与用法
kill命令用于向指定进程或进程组发送指定信号(参见表6-1),如果未指定信号,则默认发送TERM(15)。若接收者收到TERM信号,没有对信号捕获并进行特殊处理,则它将被终止运行,也就是“被杀掉了”,因此把发送信号功能的命令称为kill。对那些不能用TERM“杀掉”的进程可以使用信号kill(9)来处理,因为kill是不能被捕获的。
killall命令是另一个用来向指定进程发信号或终止进程的命令,它不像kill命令使用进程的pid作为操作对象,而是使用进程名。由于在系统中可能有多个同名进程同时运行,因此使用killall命令终止进程时可能会有扩大化的倾向。其用法为:
killall [-e] [-g] [-i] [-q] [-v] [-w] [-Ⅴ] [-s sig] [--] name … killall -l
killall发送的信号可以是信号名或值。
2)参数说明
killall命令的部分参数如表6-4所示。
表6-4 killall命令的部分参数
3)示例
#killall-l #查询可用信号
#killall man #终止所有名为man的进程 #killall-9 bash #终止所有名为bash的进程,将造成所有终端用户退出系统
3.确定使用指定文件或文件系统的进程(fuser)
1)功能与用法
在系统管理和shell编程时,经常需要确定使用某个设备或文件系统的进程和用户的情况,fuser命令可以完成此工作,其用法为:
fuser[-a|-s][-n namespace][-signal][-kimuv]name … fuser -l
2)参数说明
fuser命令的部分参数如表6-5所示。
表6-5 fuser命令的部分参数
在fuser的默认输出中,进程号的后面可以跟有c、e、f、r、m等字符,意义如下:c,当前目录;e,进程正在执行;f,打开文件,默认情况下不输出此标志;r,根目录;m,内存映像文件或共享库。
3)示例
(1)杀死所有使用某设备的进程。有时需要让使用某设备或文件系统的所有进程终止,例如,要把使用终端/dev/tty5的用户踢出系统,可采用终止使用该设备所有进程的办法来实现。
#fuser -k /dev/tty5
(2)显示使用本地网络端口的进程。从网络监控的角度来讲,有时需要了解系统中哪个端口正在被哪个进程或用户使用,有多少个进程在使用。
#fuser telnet/tcp ftp/tcp #监视本地telnet和ftp端口的tcp活动情况 #fuser-u 23/tcp 21/tcp #监视本地telnet和ftp端口的tcp活动情况 #fuser-n tcp 21 #监视本地ftp端口的tcp活动情况
4.让进程抗SIGHUP运行(nohup)
在UNIX/Linux环境下,进程可在前台运行,也可在后台运行。但不论哪种情况,只要启动进程的用户退出了系统或终端线路断路了,则他创建的所有进程都将终止,这是因为它们都将收到HUP信号。按照系统规定,收到HUP信号的进程都将被终止。为了保证用户退出后,启动的后台进程仍能继续运行,要求进程对信号HUP具有免疫能力。使用nohup命令启动的进程对信号HUP具有免疫力。nohup命令的用法为:
nohup command [ arguments ]
后台进程是不能和终端交互的。如果输入没有被重定向,则定向到/dev/null。如果输出没有重定向,它将输出追加到当前目录的nohup.out文件。如果该文件没有写权限,则输出将被重定向到$HOME/nohup.out。如果两者均无写权限,则命令不能执行。如果有写权限且nohup.out不存在,则创建它,在创建时不对同组和其他人赋访问权(权限为600)。若文件已经存在,则不改变原文件的存取权限。程序未重定向的标准错误也将被追加到nohup.out文件。
nohup不能直接创建后台进程,创建后台进程应在回车前添加“&”符号。尽管没有输出,但仍可以通过其返回值来确定其执行情况,其返回值及意义为:126,命令不能执行;127,命令找不到;其他,所执行命令的返回值。
5.改变进程的优先级(nice)
1)功能与用法
nice命令可用于进程调度与管理,通过它可以改变进程的(静态优先数)NICE值,从而改变进程获得调度的机会。对于那些不急迫的任务,可以通过调高它的NICE值,来降低它的优先级,以保证紧急任务的执行。当然,也可以指定一个负的NICE值来提高进程的优先级。nice命令的用法为:
nice [options] [cmd [arg … ]]
当不带参数或变量运行nice时,将显示默认的NICE值,如果用nice对某个进程进行操作,而没有指定NICE值,则将NICE值设置为10,从而降低优先级。如果要设置负的NICE值,以提高进程的优先级,则要求用户必须具有超级用户权限。关于NICE值的设定可以使用以下形式:
-n<NICE> 例如,-n5,NICE值为5;-n-5,NICE值为-5 -<NICE> 例如,-5,NICE值为5;--5,NICE值为-5 --adjustment=<NICE> 例如,--adjustment=5,NICE值为5
2)示例
#设程序myp可以在前、后台运行 #myp& #以默认优先级运行 #nice myp& #以默认优先数(10)降低myp的运行级 #nice-15 myp& #以15为优先数运行程序myp #nice-n-15 myp& #以-15为优先数运行程序myp #ps-l #查询进程myp的运行级和NICE值 #输出中的S栏为进程状态,PRI栏为优先级,NI为NICE值
6.进程挂起或作业的前/后台运行切换(fg、bg和jobs)
当一个交互式进程正在运行时,用户可以通过Ctrl+Z暂停其当前执行,将它挂起。之后,可让其在后台等待运行,也可让其从后台再重新回到前台运行。实现这些功能的命令是fg和bg,它们都是bash的内部命令。此外,还有jobs命令,用于作业队列查询和管理。它们的用法为:
fg [job] bg [job] jobs [options] [job …]
fg命令(foreground)的功能是让被挂起的进程或作业到前台运行;bg命令(background)的功能是让被挂起的进程或作业在后台运行,就像用符号“&”启动的那样。若不指定job,则默认使用当前作业。
设用户正在运行man bash,此时可以通过Ctrl+Z将其挂起,屏幕显示以下信息后并出现提示符:
[1]+ stopped man bash
表明名为man的进程被挂起,作业编号为1,+表示此为当前作业,用户可以在提示符下继续做其他工作。如果再启动一个进程,如计算器bc,则此时进入bc交互界面,用户同样可以通过Ctrl+Z将其挂起。
[2]+ stopped bc
系统回到提示符。运行jobs命令可得以下输出:
[1]- stopped man bash [2]+ stopped bc
由此可见,有两个作业,编号分别为1和2,其中2为当前作业。此时可以通过命令:
# fg [job]
或 # bg [job]
将作业调到前台或放在后台运行,job为jobs命令列出的作业号,如1、2等。如果输入:
# fg
或 # fg 2
将使bc调到前台执行,而输入:
# fg 1
将使作业man调到前台执行。同样,输入:
bg 1
也可使man命令在后台运行,但交互式命令在后台运行无意义。
6.3.3 与进程身份和位置相关的命令
1.以其他用户身份执行程序(sudo)
1)功能与用法
前面已经介绍过su命令可以在用户不退出系统的情况下,将自己变换为其他用户,或以其他用户的身份工作,这里再介绍一个这方面的命令——sudo(supper user do)。sudo允许用户以超级用户或其他用户的身份执行shell命令。使用sudo用户必须在文件/etc/sudoers中定义,没有在/etc/sudoers中定义的用户试图使用sudo时将向管理员发出警告性邮件。其用法为:
sudo -h|-k|-l|-v|-Ⅴ sudo [-bH]|[-p str] [-u username|#uid] {-s|cmd}
2)参数说明
sudo命令的常用参数如表6-6所示。
表6-6 sudo命令的常用参数
3)示例
(1)设当前用户test没有执行sudo的权力:
$ sudo -l
##Sorry, user test may not run sudo on Fedora9. $ sudo /sbin/shutdown now ##test is not in the sudoers file. This incident will be reported.
(2)以root身份修改/etc/sudoers文件,在其中增加一行内容:
test ALL=(ALL)/sbin/shutdown
(3)然后再以test用户的身份执行命令:
$ sudo -l ##User test may run the following commands on this host: ## (ALL)/sbin/shutdown $ sudo /sbin/shutdown -r -y now
4)配置文件/etc/sudoers
sudoers是sudo的配置文件,通常在/etc目录下。系统为此配置文件提供一个专用的编辑命令visudo,除了编辑修改sudoers文件外,它还会帮使用者检查配置文件内容的正确性。如果不正确,会在保存退出时提示用户哪里出了问题。visudo的用法与vi相同。
(1)变量类型及定义。配置文件/etc/sudoers中除了注释行外,有两类描述项:一类是alias(变量);另一类是用户,描述一个用户能做什么工作。
有四种类型的变量定义:User_Alias(用户定义)、Runas_Alias(使用身份定义)、Host_Alias(主机定义)和Cmnd_Alias(可用命令定义)。
变量的定义形式如下:
Alias_Type NAME=item1,item2, …
Alias_Type为以上四类别名定义的一种,NAME是大写字母开头的,由大写字母、数字和下画线组成的字符串。一个变量定义行中可以同时定义多个变量,变量之间用“:”分隔,例如:
Alias_Type NAME1 = item1, item2, item3 : NAME2 = item4, item5
以上四种变量的具体定义可分别描述如下。
① User_Alias,具有使用sudo权限的用户的列表,定义格式如下:
User_Alias USERs=user1,user2,user3
在User_Alias定义中,右端的user可以是用户名、由“#”引导的UID、由“%”引导的组和由“+”引导的网络组等,任何一类用户前还可以使用“!”表示非操作。例如:
User_Alias FULLTIMERS=zhangsan,lisi,wangwu User_Alias PARTTIMERS=test1,arm,oracle User_Alias WEBMASTERS=oauser,www
② Host_Alias,主机的列表,定义格式如下:
Host_Alias HOSTs=hostname1,hostname2,hostname3
上式的右端可以是主机名、IP地址、网络地址和由“+”引导的网络组等,也可以在主机前使用“!”表示非操作。例如:
Host_Alias CUNETS=128.138.0.0/255.255.0.0 Host_Alias CSNETS=128.138.243.0,128.138.204.0/24,128.138.242.0 Host_Alias SERⅤERS=master,mail,www,ns
③ Runas_Alias,用户可以使用的身份列表,定义格式如下:
Runas_Alias RUNASs=operator1,operator2,operator3
Runas_Alias与User_Alias定义方法相似,例如:
Runas_Alias OPs=root,operator
Runas_Alias DBs=oracle,sybase
④ Cmnd_Alias,允许执行的命令的列表,“!”引导的命令表示不能执行。
命令列表中的命令要使用绝对路径,避免其他目录的同名命令被执行,造成安全隐患。定义格式如下:
Cmnd_Alias COMMANDs=command1,command2,command3,!command4
示例如下:
Cmnd_Alias KILL=/usr/bin/kill Cmnd_Alias SHUTDOWN=/sbin/shutdown,/usr/sbin/halt,/usr/sbin/reboot Cmnd_Alias NETWORKING=/sbin/route,/sbin/ifconfig,/bin/ping Cmnd_Alias SERⅤICES=/sbin/service,/sbin/chkconfig
(2)权限设置。有了前面的准备就可以配置用户的执行或操作权限了。权限配置的格式如下:
USERs HOSTs=(RUNASs) COMMANDs
其中,每个项目均可配置为ALL,例如:
ALL ALL=(ALL) ALL
这意味着任何用户在任何位置均可使用sudo执行任何命令,权限控制太松了。
如果要使某类用户在执行某种操作时不需要密码验证,则可按照以下格式来配置:
USERs HOSTs=(RUNASs) NOPASSWD: COMMANDs
具体配置示例如下:
## 允许root在任何位置执行任何命令 root ALL=(ALL) ALL ## 允许sys组中的用户执行NETWORKING、SERⅤICES和SHUTDOWN %sys ALL = NETWORKING, SERⅤICES, SHUTDOWN # #允许wheel组中的用户执行所有命令 %wheel ALL=(ALL)ALL # #允许wheel组中的用户执行所有命令,并且不需要密码 %wheel ALL=(ALL)NOPASSWD:ALL # #允许test1用户在本地执行SHUTDOWN test1 localhost = SHUTDOWN # #允许WEBMASTERS在CSNETS上以任何人的身份执行SERⅤERS WEBMASTERS CSNETS = (ALL) SERⅤERS
2.改变进程的家目录(chroot)
1)功能与用法
chroot(change root)的作用是改变根目录。其用法为:
chroot newroot [cmd]
参数newroot为chroot改变以后使用的“根目录”,可以使用绝对路径或相对路径。cmd为以newroot为新“根”文件系统内存放的命令,如果不提供cmd,则默认执行环境变量SHELL指定的shell。如果指定了cmd,则cmd不能是一个通过符号链接指向newroot外部的文件。如果是指向newroot内部的,应以相对路径的方式链接,因为如果此时chroot能够成功,则cmd已经不能再看到newroot以外的整个文件系统了,从而使符号链接失效。
若要成功执行chroot,必须事前有一定的准备。首先,新的根目录newroot必须存在;其次,cmd命令必须事先在newroot目录内的合适位置存在,并且最好是采用静态链接生成的,以便成功改变根目录后以newroot为根目录时能够找到它,并能够独立执行,否则执行时所需要的动态库也必须出现在新根目录内的合适位置。为了找到cmd的共享库,可以使用ldd cmd命令查询,然后按照查询结果创建相应目录,并将相关的库和命令复制到newroot对应的目录内。
2)准备
以chroot newroot cmd为例说明chroot命令的准备和使用过程:
(1)查询newroot目录是否存在,若无,则先创建。
(2)查询SHELL环境变量的值,并记住该值。
(3)查询cmd的位置,并记住该位置。
(4)查询cmd所使用的共享库,并记住库名和位置。
(5)在newroot下创建命令和共享库所用的每个目录。
(6)将命令、共享库文件和其他必需的文件复制或(硬)链接到相应位置。
(7)执行命令chroot newroot cmd。
(8)若成功,按Ctrl+D或Exit键退出chroot。
第(1)到(6)步是真正的准备过程,而第(7)、(8)步是对准备工作的检验。
3)示例
这里以仅将目录切换到nroot,而不执行任何命令为例说明准备过程。尽管不执行任何命令,但默认要执行的是环境变量$SHELL所指定的命令。准备过程如下所示。
#chroot nroot #执行chroot nroot,得到以下错误,说明目录不存在 # #chroot: cannot change root directory to nroot: No such file or directory #mkdir nroot #创建目录nroot #chroot nroot #再次执行chroot nroot,得到以下错误 # #chroot: cannot run command `/bin/bash': No such file or directory # #说明/bin/bash不存在。创建目录nroot/bin并复制文件/bin/bash到其中 #mkdir nroot/bin; #创建目录nroot/bin #cp$SHELL nroot/bin #将/bin/bash复制到/nroot/bin #chroot nroot #再次执行chroot nroot,仍得到以下错误 # #chroot: cannot run command `/bin/bash': No such file or directory # #检查/bin/bash的支持库 #ldd$SHELL #检查/bin/bash的依赖库文件,得到以下输出 linux-gate.so.1=> (0x00110000) libtinfo.so.5 => /lib/libtinfo.so.5 (0x0280b000) libdl.so.2 => /lib/libdl.so.2 (0x0093f000) libc.so.6 => /lib/libc.so.6 (0x007d4000) /lib/ld-linux.so.2 (0x007b4000) # #创建目录nroot/lib,并将以上依赖文件复制到其中 # mkdir nroot/lib; cp /lib/libtinfo.so.5 nroot/lib; cp /lib/libdl.so.2 nroot/lib # cp /lib/libc.so.6 nroot/lib; cp /lib/ld-linux.so.2 nroot/lib #chroot nroot #执行chroot nroot成功,输出以下提示符 # # bash-3.2#
到此为止,准备工作完毕,下边执行几个命令以观察效果。
#pwd #执行内部命令pwd,成功,得到输出为/ #ls #执行外部命令ls,失败,得到以下错误提示 # #bash: ls: command not found
因为ls为外部命令,没有为它准备,故在以nroot为根目录的新位置文件找不到它,因此不能执行。为了让/bin/ls能够执行,还需要继续准备,过程同前。
由上可见,为chroot做准备工作并不太容易,不过就一般的应用来讲,所需文件并不太多。以后将看到很多的网络应用程序是采用这种方式运行的,以保证系统的安全。