??xml version="1.0" encoding="utf-8" standalone="yes"?> 2011-02-19 xiao H Posted in pȝ理 错误提示Q?/p> 上面的方法不行可以试试下面这?/p> l极大法 以上Ҏ(gu)来自Q?/p> http://forum.ubuntu.org. 本h的系l默认是命o行界面启动的。于是重启以RunLevel 5q入囑Ş界面。发现图形界面可以正常进入。下面就查询日志吧: 在日志文件中Q我看到了如下信息: PAM unable to dlopen(/lib/security/pam_limits.so) PAM [error: /lib/security/pam_limits.so: wrong ELF class: ELFCLASS32] PAM adding faulty module: /lib/security/pam_limits.so pam_unix(login:session): session opened for user Oracle by LOGIN(uid=0) Module is unknown 看到q里Q我惌v我在/etc/pam.d/login中加入了: session required /lib/security/pam_limits.so session required pam_limits.so 两条配置语句。根据日志信息以上Login上的其他配置信息Q将W一条语句注释掉Q?br /> #session required /lib/security/pam_limits.so session required pam_limits.so 重启Q登录,一切正常。问题解冟?/p> ########################更新##########################33 以上问题的出现是׃操作pȝ的问题。我本想安装32位centosQ结果错手拿了一?4bit Centos安装Q然后按?2位的配置q行了配|。正配|在64位下应ؓQ?/p>
Linux Signals are:
As noted above, processes can ignore, block, or catch all signals except
SIGSTOP and SIGKILL. If a process catches a signal, it means that it
includes code that will take appropriate action when the signal is
received. If the signal is not caught by the process, the kernel will
take default action for the signal.
FIFOs are permanent objects and can be created using the mkfifo(1) or
mknod(1) command. Inside the program, the FIFO can be created using the
mknod command, then opened and read from or written to just like a
normal file. The FIFO is normally in blocking mode when attempting to
perform read operations. 引用自:http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html 在终端用kill -l 命o可以昄所有的信号?br>
$kill -l 其中前面31个信号ؓ不可靠信?非实时的Q可能会出现信号的丢?Q后面的信号为可靠信?实时的real_time,对信?br>
排队Q不会丢??/strong> 1) SIGHUP (挂v) 当运行进E的用户注销旉知该进E,使进E终?/strong> 2) SIGINT (中断) 当用h下时,通知前台q程l终止进E?/strong> 3) SIGQUIT (退? 用户按下或时通知q程Qɘq程l止 4) SIGILL (非法指o) 执行了非法指令,如可执行文g本n出现错误、试图执行数据段、堆栈溢?/strong> 5) SIGTRAP 由断Ҏ(gu)令或其它trap指o产生. 由debugger使用 6) SIGABRT (异常中止) 调用abort函数生成的信?/strong> 7) SIGBUS 非法地址, 包括内存地址寚w(alignment)出错. eg: 讉K一个四个字长的整数, 但其地址不是4的倍数. 8) SIGFPE (术异常) 发生致命术q算错误,包括点q算错误、溢出及除数?. 9) SIGKILL (认杀? 当用户通过kill -9命o向进E发送信hQ可靠的l止q程 10) SIGUSR1 用户使用 11) SIGSEGV (D越? 当进E尝试访问不属于自己的内存空间导致内存错误时Q终止进E?/strong> 12) SIGUSR2 用户使用 13) SIGPIPE 写至无读q程的管? 或者Socket通信SOCT_STREAM的读q程已经l止Q而再写入?/strong> 14) SIGALRM (时) alarm函数使用该信P旉定时器超时响?/strong> 15) SIGTERM (软中? 使用不带参数的kill命o时终止进E?/strong> 17) SIGCHLD (子进E结? 当子q程l止旉知父进E?/strong> 18) SIGCONT (暂停q程l箋) 让一个停?stopped)的进El执? 本信号不能被d. 19) SIGSTOP (停止) 作业控制信号,暂停停止(stopped)q程的执? 本信号不能被d, 处理或忽? 20) SIGTSTP (暂停/停止) 交互式停止信? Ctrl-Z 发出q个信号 21) SIGTTIN 当后C业要从用L(fng)端读数据? l端驱动E序产生SIGTTIN信号 22) SIGTTOU 当后C业要往用户l端写数据时, l端驱动E序产生SIGTTOU信号 23) SIGURG ?紧?数据或网l上带外数据到达socket时? 24) SIGXCPU 过CPU旉资源限制. q个限制可以由getrlimit/setrlimit来读?改变?/strong> 25) SIGXFSZ 当进E企图扩大文件以至于过文g大小资源限制?/strong> 26) SIGVTALRM 虚拟旉信号. cM于SIGALRM, 但是计算的是该进E占用的CPU旉. 27) SIGPROF (梗概旉时) setitimer(2)函数讄的梗概统计间隔计时器(profiling interval timer) 28) SIGWINCH H口大小改变时发? 29) SIGIO(异步I/O) 文g描述W准备就l? 可以开始进行输?输出操作. 30) SIGPWR 甉|失效/重启?/strong> 31) SIGSYS 非法的系l调用?/strong> 在以上列出的信号中, 此外QSIGIO在SVR4是退出,?.3BSD中是忽略QSIGCONT在进E挂h是l,否则是忽略,不能被阻塞?/strong> 在Unix/Linux中signal函数是比较复杂的一?其定义原型如? gdb对于多线E程序的调试有如下的支持Q?br> 【命令】time ?执行命oq计?/span> 【格式】time [-p] command [arguments...] 【说明?/span> 执行命o?command [arguments...]"Q命令行执行l束时在标准输出中打印执行该命o行的旉l计l果Q其l计l果包含以下数据Q?/font> 1)实际旉(real time): 从command命o行开始执行到q行l止的消逝时_ 2)用户CPU旉(user CPU time): 命o执行完成p的用户CPU旉Q即命o在用h中执行旉dQ?/font> 3)pȝCPU旉(system CPU time): 命o执行完成p的系lCPU旉Q即命o在核心态中执行旉d?/font> 其中Q用户CPU旉和系lCPU旉之和为CPU旉Q即命o占用CPU执行的时间d。实际时间要大于CPU旉Q因为Linux是多d操作pȝQ往往在执行一条命令时Q系l还要处理其它Q务?/font> 另一个需要注意的问题是即使每ơ执行相同命令,但所p的时间也是不一P其花Ҏ(gu)间是与系l运行相关的?/font> ?Q?/font> 1. # time date 在例1中,执行命o"time date"(见第1?。系l先执行命o"date"Q第2行ؓ命o"date"的执行结果。第3-6行ؓ执行命o"date"的时间统计结果,其中W? ?real"为实际时_W??user"为用户CPU旉Q第6?sys"为系lCPU旉。以上三U时间的昄格式均ؓ MMmNN[.FFF]s?/font> 在例1中,CPU旉 = 用户CPU旉 + pȝCPU旉 = 0m0.010s + 0m0.070s = 0m0.080sQ实际时间大于CPU旉Q说明在date命oq行的同Ӟq有其它d在运行?/font> 【参数说明?/span> -p 以POSIX~省的时间格式打印时间统计结果,单位为秒。详l的输出格式见例2?/font> ?Q?/font> 在例2中,同样执行命o"time date"(见第1?。系l先执行命o "date"Q第2行ؓ该命令的执行l果。第3-5行ؓ执行命o"date"的时间统计结果。注意本例的旉格式与例1中的旉格式差别Q?p 参数后的旉昄格式为NN.FFQ其单位为秒?/font> 【相关环境变量说明?/span> TIMEFORMAT 自定义输出的旉格式?/font> 我们也可以通过环境变量TIMEFORMAT来自定义输出的时间格式[1]。格式中使用和标准C中的函数printf一致的转义W,以及使用以下的{义序列来指定输出的时间格式: 其中Q选项prec为指定时间精度,卛_数点后面的位敎ͼ选项l表示使用分秒(具体格式为:MMmNN[.FFF]s)的格式;最后一个字W表C时间的cdQ其中R表示实际旉QU表示用户CPU旉QS表示pȝCPU 旉Q它们的单位均ؓU?/font> time命o~省输出的时间格式同 TIMEFORMAT=$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'?/font> 使用-p参数的time命o输出的时间格式同 TIMEFORMAT=$'real %2R\nuser %2U\nsys %2S'?/font> ?Q?/font> 比较?和例3昄l果Q很Ҏ(gu)发现?虽然没有使用参数-pQ但其输出的l果和例2一模一栗?/font> 当然Q我们也可以修改ZQ何自己喜Ƣ的旉格式?/font> ?Q?/font> ?的第4-8行正是我们自定义的输出格式?/font> 从以上介l了三种指定旉格式的方法,即缺省的旉格式、用参?p的POSIX~省的时间格式和讑֮环境变量TIMEFORMAT自定义的旉格式QLinuxpȝ使用的先后顺序如下: 1.参数-p的POSIX~省旉格式Q?/font> 2.环境变量TIMEFORMAT自定义的旉格式Q?/font> 3.~省的时间格式?/font> 【退出状态说明?/span> 如果能执行command命oQ则q回该命令的退出状态,否则q回如下的退出状态| 127 命o未找?/font> 126 命o扑ֈQ但不能执行 1-125 其它错误Ubuntu 更新源签名错?–BADSIG 40976EAF437D05B5
GPG 错误Qhttp://mirrors.163.com maverick-updates Release: 下列{无效Q?BADSIG 40976EAF437D05B5 Ubuntu Archive Automatic Signing Key <ftpmaster @ubuntu.com> </ftpmaster>
修复Ҏ(gu) gpg --keyserver keyserver.ubuntu.com --recv 40976EAF437D05B5 gpg --export --armor 40976EAF437D05B5 | sudo apt-key add -
sudo aptitude -o Acquire::http::No-Cache=True -o Acquire::BrokenProxy=true update
sudo apt-get clean cd /var/lib/apt sudo mv lists lists.old sudo mkdir -p lists/partial sudo apt-get clean sudo apt-get update
转自Q?br />
]]> 1: # cd /var/log/
2: #cat security
1: session required /lib64/security/pam_limits.so
2:
3: session required pam_limits.so
转自Q?div>http://www.zhaofengcao.com/archives/138
]]>
I was about to try the CD startup when I tried one last thing again.
sudo mdadm --stop /dev/md0
It worked, but I find it strange because I did it before and md0 did not appear in the fdisk -l screen.
Immdiately after that I was able to run the sudo mkfs.ext3 /dev/sdc
Maybe it is because I ran the zero-superblock tasks overnight - something that made me nervous, since I have no idea what it does.
Than You for your help!
It worked for me. Thanks!
]]>
Signal Name
Number
Description
SIGHUP
1
Hangup (POSIX)
SIGINT
2
Terminal interrupt (ANSI)
SIGQUIT
3
Terminal quit (POSIX)
SIGILL
4
Illegal instruction (ANSI)
SIGTRAP
5
Trace trap (POSIX)
SIGIOT
6
IOT Trap (4.2 BSD)
SIGBUS
7
BUS error (4.2 BSD)
SIGFPE
8
Floating point exception (ANSI)
SIGKILL
9
Kill(can't be caught or ignored) (POSIX)
SIGUSR1
10
User defined signal 1 (POSIX)
SIGSEGV
11
Invalid memory segment access (ANSI)
SIGUSR2
12
User defined signal 2 (POSIX)
SIGPIPE
13
Write on a pipe with no reader, Broken pipe (POSIX)
SIGALRM
14
Alarm clock (POSIX)
SIGTERM
15
Termination (ANSI)
SIGSTKFLT
16
Stack fault
SIGCHLD
17
Child process has stopped or exited, changed (POSIX)
SIGCONT
18
Continue executing, if stopped (POSIX)
SIGSTOP
19
Stop executing(can't be caught or ignored) (POSIX)
SIGTSTP
20
Terminal stop signal (POSIX)
SIGTTIN
21
Background process trying to read, from TTY (POSIX)
SIGTTOU
22
Background process trying to write, to TTY (POSIX)
SIGURG
23
Urgent condition on socket (4.2 BSD)
SIGXCPU
24
CPU limit exceeded (4.2 BSD)
SIGXFSZ
25
File size limit exceeded (4.2 BSD)
SIGVTALRM
26
Virtual alarm clock (4.2 BSD)
SIGPROF
27
Profiling alarm clock (4.2 BSD)
SIGWINCH
28
Window size change (4.3 BSD, Sun)
SIGIO
29
I/O now possible (4.2 BSD)
SIGPWR
30
Power failure restart (System V)
FIFOs
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT
17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN
35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4
39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6
59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
E序不可捕获、阻塞或忽略的信hQSIGKILL,SIGSTOP
不能恢复至默认动作的信号有:SIGILL,SIGTRAP
默认会导致进E流产的信号有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ
默认会导致进E退出的信号有:SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM
默认会导致进E停止的信号有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
默认q程忽略的信hQSIGCHLD,SIGPWR,SIGURG,SIGWINCH
void (*signal(int signo,void (*func)(int))) (int)
q个函数?最外层的函C
void (* XXX )(int)表明是一个指?指向一个函数XXX的指?XXX所代表的函数需要一个int型的参数,q回void
signal(int signo, void(*func)(int))是signal函数的主?
需要两个参数int型的signo以及一个指向函数的函数.
void (*func)(int).
正是׃其复杂?在[Plauger 1992]用typedef来对其进行简?br>
typedef void Sigfuc(int);//q里可以看成一个返回?.
再对signal函数q行化就是这L(fng)?br>
Sigfunc *signal(int,Sigfuc *);
在signal.h头文件中q有以下几个定义
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1
本文来自CSDN博客Q{载请标明出处Q?/strong> http://blog.csdn.net/nevercgoodbye/archive/2008/11/25/3367853.aspx
]]>
U程产生通知Q在产生新的U程? gdb会给出提CZ?br> (gdb) r
Starting program: /root/thread
[New Thread 1073951360 (LWP 12900)]
[New Thread 1082342592 (LWP 12907)]---以下三个为新产生的线E?br> [New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]
查看U程Q用info threads可以查看q行的线E?br> (gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
注意Q行首的蓝色文字为gdb分配的线E号Q对U程q行切换Ӟ使用该该L(fng)Q而不是上文标出的l色数字?br>
另外Q行首的U色星号标识了当前活动的U程
切换U程Q?thread THREADNUMBER q行切换QTHREADNUMBER Z文提到的U程受下例显C将zdU程?1 切换?4?br> (gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0 0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
以上即ؓ使用gdb提供的对多线E进行调试的一些基本命令。另外,gdb也提供对U程的断点设|以及对指定或所有线E发布命令的命o?br>
初次接触gdb下多U程的调试,往往会忽视gdb中活动线E的概念。一般来Ԍ在用gdb调试的时候,只有一个线EؓzdU程Q如果希望得到其他的U程的输出结果,必须使用thread命o切换x定的U程Q才能对该线E进行调试或观察输出l果?/p>
]]>
2. Sun Mar 26 22:45:34 GMT-8 2006
3.
4. real 0m0.136s
5. user 0m0.010s
6. sys 0m0.070s
7. #
2. Wed Mar 27 00:33:11 GMT-8 2006
3. real 0.11
4. user 0.00
5. sys 0.02
6. #
2. # time date
3. Wed Mar 27 00:52:03 GMT-8 2006
4. real 0.04
5. user 0.00
6. sys 0.01
7. #
2. # time date
3. Wed Mar 27 01:09:26 GMT-8 2006
4.
5. Hello, ThinkerABC!
6. real time : 0m0.016s
7. user CUP time : 0m0.006s
8. system CPU time : 0m0.008s
9. #
]]>
]]>
3.1 建立调试关系
用gdb调试E序Q可以直接gdb ./test,也可以gdb <pid>(test的进E号)。这对应着使用ptrace建立跟踪关系的两U方?
1)fork: 利用fork+execve执行被测试的E序Q子q程在执行execve之前调用ptrace(PTRACE_TRACEME)Q徏立了与父q程(debugger)的跟t关pR如我们在分析strace时所C意的程序?br>2)attach:
debugger可以调用ptrace(PTRACE_ATTACHQpid,...)Q徏立自׃q程号ؓpid的进E间的跟t关pR即利用
PTRACE_ATTACHQ自己变成被调试程序的父进E?用ps可以看到)。用attach建立h的跟t关p,可以调用ptrace
(PTRACE_DETACHQpid,...)来解除。注意attachq程时的权限问题Q如一个非root权限的进E是不能attachC?
rootq程上的?br>
3.2 断点原理
断点是大家在调试E序时常用的一个功?如break linenumberQ当执行到l(f)inenumber那一行的时候被调试E序会停止,{待debugger的进一步操作?
断点的实现原理,是在指定的位置插入断点指oQ当被调试的E序q行到断点的时候,产生SIGTRAP信号。该信号被gdb捕获q进行断点命中判定,当gdb判断ơSIGTRAP是断点命中之后就会{入等待用戯入进行下一步处理,否则l箋?br>断点的设|原? 在程序中讄断点Q就是先该位置的原来的指o保存Q然后向该位|写入int 3。当执行到int 3的时候,发生软中断,内核会给子进E发出SIGTRAP信号Q当然这个信号会被{发给父进E。然后用保存的指令替换int3,{待恢复q行?br>断点命中判定:gdb把所有的断点位置都存攑֜一个链表中Q命中判定即把被调试E序当前停止的位|和链表中的断点位置q行比较Q看是断点生的信号Q还是无关信受?br>
3.3 单步跟踪原理
单步跟踪是指在调试E序的时候,让程序运行一条指?语句后就停下。GDB中常用的命o有next, step, nexti, stepi。单步跟t又常分句单?next, step)和指令单?如nexti, stepi)?br>
在linux上,指o单步可以通过ptrace来实现。调用ptrace(PTRACE_SINGLESTEP,pid,...)可以使被调试的进E在每执行完一条指令后p发一个SIGTRAP信号Q让GDBq行。下面来看一个例?
child = fork();
if(child == 0) {
execl("./HelloWorld", "HelloWorld", NULL);
}
else {
ptrace(PTRACE_ATTACH,child,NULL,NULL);
while(1){
wait(&val);
if(WIFEXITED(val))
break;
count++;
ptrace(PTRACE_SINGLESTEP,child,NULL,NULL);
}
printf("Total Instruction number= %d\n",count);
}
q?
D늨序比较简单,子进E调用execve执行HelloWorld,而父q程则先调用ptrace(PTRACE_ATTACH,pid,...)建立?
子进E的跟踪关系。然后调用ptrace(PTRACE_SINGLESTEP, pid,
...)让子q程一步一停,以统计子q程一共执行了多少条指?你会发现一个简单的HelloWorld实际上也执行了好几万条指令才完成)。当然你也完
全可以在q个时候查看EIP寄存器中存放的指令,或者某个变量的|当然前提是你得知道这个变量在子进E内存镜像中的位|?br>指o单步可以依靠g
完成Q如x86架构处理器支持单步模?通过讄EFLAGS寄存器的TF标志实现)Q每执行一条指令,׃产生一ơ异?在Intel
80386以上的处理器上还提供了DRx调试寄存器以用于软g调试)。也可以通过软g完成Q即在每条指令后面都插入一条断Ҏ(gu)令,q样每执行一条指令都?
产生一ơY中断?br>语句单步Z指o单步实现Q即GDB好每条语句所对应的指令,从什么地方开始到什么地方结束。然后在l束的地Ҏ(gu)入断点,或者指令单步一步一步的走到l束点,再进行处理?br>
?
然gdb的实现远比今天我们所说的内容要复杂,它能让我们很Ҏ(gu)的监,修改被调试的q程Q比如通过行号Q函数名Q变量名。而要真正实现q些Q一是需要在
~译的时候提供够的信息Q如在gcc时加?g选项Q这样gcc会把一些程序信息放到生成的ELF文g中,包括函数W号表,行号Q变量信息,宏定义等Q?
以便日后gdb调试Q当然生成的文g也会大一些。二是需要我们对ELF文g格式Q进E的内存镜像(布局)以及E序的指令码十分熟?zhn)。这h能保证在正确?
时机(断点发生Q单步?)扑ֈ正确的内存地址(代码Q数据?)q接回正确的程序代?q是哪个变量Q程序第几行Q?。感兴趣的同学可以找到相应的代码?
l分析一下?br>
结:
ptrace可以实时监测和修改另一个进E的q行Q它是如此的强大以至于曾l因为它在unix-likeq_
(如Linux,
*BSD)上生了各种漏洞。但换言之,只要我们能掌握它的用,p开发出很多以前在用h下不可能实现的应用。当然这可能需要我们掌握编译,文g?
式,E序内存布局{相当多的底层知识?br>
最后让我们来回一下ptrace的?
1)用PTRACE_ATTACH或者PTRACE_TRACEME 建立q程间的跟踪关系?br>2)PTRACE_PEEKTEXT, PTRACE_PEEKDATA, PTRACE_PEEKUSR{读取子q程内存/寄存器中保留的倹{?br>3)PTRACE_POKETEXT, PTRACE_POKEDATA, PTRACE_POKEUSR{把值写入到被跟t进E的内存/寄存器中?br>4)用PTRACE_CONTQPTRACE_SYSCALL, PTRACE_SINGLESTEP控制被跟t进E以何种方式l箋q行?br>5)PTRACE_DETACH, PTRACE_KILL qq程间的跟踪关系?br>
TIPS:
1. q程状态TASK_TRACED用以表示当前q程因ؓ被父q程跟踪而被pȝ停止?br> 2. 如在子进E结束前Q父q程l束Q则trace关系解除?br> 3. 利用attach建立h的跟t关p,虽然ps看到双方为父子关p,但在"子进E?中调用getppid()仍会q回原来的父q程id?br> 4. 不能attach到自׃能跟t的q程Q如non-rootq程跟踪rootq程?br> 5. 已经被trace的进E,不能再次被attach?br> 6. 即是用PTRACE_TRACEME建立h的跟t关p,也可以用DETACH的方式予以解除?br> 7. 因ؓq入/退出系l调用都会触发一ơSIGTRAPQ所以通常的做法是在第一?q入)的时候读取系l调用的参数Q在W二?退?的时候读取系l调用的q回倹{但注意execve是个例外?br> 8. E序调试时的断点由int 3讄完成Q而单步跟t则可由ptrace(PTRACE_SINGLESTEP)实现?br>
Pthread 08/01/14
原文地址Qhttp://blog.csdn.net/Javadino/archive/2008/09/06/2891434.aspx
]]>
2.strace可以方便的帮助我们记录进E所执行的系l调用,它是如何跟踪到进E执行的Q?br>3.gdb是我们调试程序的利器Q可以设|断点,单步跟踪E序。它的实现原理又是什么?
所有这一切的背后都隐藏着Linux所提供的一个强大的pȝ调用ptrace().
1.ptracepȝ调用
ptrace
pȝ调从名字上看是用于进E跟t的Q它提供了父q程可以观察和控制其子进E执行的能力Qƈ允许父进E检查和替换子进E的内核镜像(包括寄存?的倹{其?
本原理是:
当用了ptrace跟踪后,所有发送给被跟t的子进E的信号(除了SIGKILL)Q都会被转发l父q程Q而子q程则会被阻塞,q时子进E的状态就会被
pȝ标注为TASK_TRACED。而父q程收到信号后,可以对停止下来的子q程q行查和修改Q然后让子进El运行?nbsp;
其原型ؓQ?nbsp;
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
ptrace有四个参?
1). enum __ptrace_request requestQ指CZptrace要执行的命o?br> 2). pid_t pid: 指示ptrace要跟t的q程?br> 3). void *addr: 指示要监控的内存地址?br> 4). void *data: 存放d出的或者要写入的数据?br>ptrace是如此的强大Q以至于有很多大家所常用的工具都Zptrace来实玎ͼ如strace和gdb。接下来Q我们借由对strace和gdb的实玎ͼ来看看ptrace是如何用的?br>
2. strace的实?br>strace常常被用来拦截和记录q程所执行的系l调用,以及q程所收到的信受如有这么一D늨序:
HelloWorld.c:
#include <stdio.h>
int main(){
printf("Hello World!\n");
return 0;
}
~译后,用strace跟踪Q?strace ./HelloWorld
可以看到形如:
execve("./HelloWorld", ["./HelloWorld"], [/* 67 vars */]) = 0
brk(0) = 0x804a000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f18000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/home/supperman/WorkSpace/lib/tls/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
...
的一D输出,q就是在执行HelloWorld中,pȝ所执行的系l调用,以及他们的返回倹{?br>
下面我们用ptrace来研I一下它是怎么实现的?br>...
switch(pid = fork())
{
case -1:
return -1;
case 0: //子进E?br> ptrace(PTRACE_TRACEME,0,NULL,NULL);
execl("./HelloWorld", "HelloWorld", NULL);
default: //父进E?br> wait(&val); //{待q记录execve
if(WIFEXITED(val))
return 0;
syscallID=ptrace(PTRACE_PEEKUSER, pid, ORIG_EAX*4, NULL);
printf("Process executed system call ID = %ld\n",syscallID);
ptrace(PTRACE_SYSCALL,pid,NULL,NULL);
while(1)
{
wait(&val); //{待信号
if(WIFEXITED(val)) //判断子进E是否退?br> return 0;
if(flag==0) //W一?q入pȝ调用)Q获取系l调用的参数
{
syscallID=ptrace(PTRACE_PEEKUSER, pid, ORIG_EAX*4, NULL);
printf("Process executed system call ID = %ld ",syscallID);
flag=1;
}
else //W二?退出系l调?Q获取系l调用的q回?br> {
returnValue=ptrace(PTRACE_PEEKUSER, pid, EAX*4, NULL);
printf("with return value= %ld\n", returnValue);
flag=0;
}
ptrace(PTRACE_SYSCALL,pid,NULL,NULL);
}
}
...
?
上面的程序中Qfork出的子进E先调用了ptrace(PTRACE_TRACEME)表示子进E让父进E跟t自己。然后子q程调用execl加蝲执行
了HelloWorld。而在父进E中则用waitpȝ调用{待子进E的状态改变。子q程因ؓ讄了PTRACE_TRACEME而在执行pȝ调用被系
l停?讄为TASK_TRACED)Q这时父q程被唤醒,使用ptrace(PTRACE_PEEKUSER,pid,...)分别去读取子q程执行
的系l调用ID(攑֜ORIG_EAX?以及pȝ调用q回时的?攑֜EAX?。然后用ptrace(PTRACE_SYSCALL,
pid,...)指示子进E运行到下一ơ执行系l调用的时?q入或者退?Q直到子q程退Zؓ止?br>
E序的执行结果如?
Process executed system call ID = 11
Process executed system call ID = 45 with return value= 134520832
Process executed system call ID = 192 with return value= -1208934400
Process executed system call ID = 33 with return value= -2
Process executed system call ID = 5 with return value= -2
...
?
中,11L(fng)l调用就是execveQ?5hbrk,192是mmap2,33是access,5是open...l过比对可以发现Q和strace?
输出l果一栗当然straceq行了更详尽和完善的处理Q我们这里只是揭C其原理Q感兴趣的同学可以去研究一下strace的实现?br>
PS:
1). 在系l调用执行的时候,会执行pushl %eax # 保存pȝ调用号ORIG_EAX在程序用h中?br> 2). 在系l调用返回的时候,会执行movl %eax,EAX(%esp)系l调用的q回值放入寄存器%eax中?br> 3). WIFEXITED()宏用来判断子q程是否为正帔R出的Q如果是Q它会返回一个非零倹{?br> 4). 被跟t的E序在进入或者退出某ơ系l调用的时候都会触发一个SIGTRAP信号Q而被父进E捕莗?br> 5). execve()pȝ调用执行成功的时候ƈ没有q回|因ؓ它开始执行一D|的程序,q没?q回"的概c失败的时候会q回-1?br> 6). 在父q程q行q行操作的时候,用ps查看Q可以看到子q程的状态ؓT,表示子进E处于TASK_TRACED状态。当然ؓ了更h作性,你可以在父进E中加入sleep()?br>
(To Be Continued)
Pthread 08/01/13
原文地址Qhttp://blog.csdn.net/Javadino/archive/2008/09/06/2891413.aspx
]]>
ptrace函数?/span>_request参数是最重要的一个参敎ͼ因ؓ它确定你做什么?/span>BSD?/span>Linux的头文g使用不同的定义,q得将ptrace应用从一个^台移植到另一个^台变得很复杂。默认地Q我们?/span>BSD头文件中的定义?/span>
r PT_TRACE_MEQ?/span>PTRACE_TRACEMEQ将当前q程切换到停止状态。它通常L?/span>fork/exec一起用,虽然也能遇到自我q踪的应用程序。对于每一个进E,PT_TRACE_ME只能被调用一ơ。追t一个正被追t的q程是会p|的(另一个较不重要的l果是进E不能追t它自己。如果要q样做,应该首先从自w派生一个进E)。大量的反调试技术都是以q一事实为基的。ؓ了克服这cL术,必须使用l过ptrace的调试器。一个信可发送到正被调试的进E,q将该进E切换到停止状态,该进E可以用从父进E上下文中调用的PT_CONTINUE?/span>PT_STEP命o从停止状态退出?/span>wait函数会gq父q程的执行,直到被调试的q程切换为停止状态或者终止ؓ止(l止Ӟq回gؓ1407Q。其他的所有参?span style="letter-spacing: 0.1pt;">都被忽略?/span>
r PT_ATTACHQ?/span>PTRACE_ATTACHQ?/span>进E标志ؓpid的运行进E切换ؓ停止状态,在这U情形下Q调试器q程成ؓ“父进E?#8221;。其他的所有参数都被忽略。进E必d有与调试q程相同的用h志(UIDQ,q且不能?/span>setuid/setduidq程Q否则就要用root来调试)?/span>
r PT_DETACHQ?/span>PTRACE_DETACHQ?/span>停止q程标志?/span>pidq程Q由PT_ATTACH?/span>PT_TRACE_ME指定Q的调试Qƈl箋其常态运行。其他的所有参数都被忽略?/span>
r PT_CONTINUEQ?/span>PTRACE_CONTQ?/span>l箋q程标志?/span>pid的被调试q程的执行,而不中断与调试器q程的通信。如?/span>addr Q= 1Q在Linux中ؓ0Q,从上ơ停止的地址l箋执行Q否则,从指定的地址l箋执行。参?/span>_data指定发送到被调试进E的信号数量Q零说明没有信号Q?/span>
r PT_STEPQ?/span>PTRACE_SINGLESTEPQ?/span>q行q程标志?/span>pid的进E的单步执行Q即执行下一条机器指令ƈ切换为停止状态(?/span>i386中,q是Ҏ(gu)讄q踪标志来实?span style="letter-spacing: -0.1pt;">的,虽然有些“黑客”函数库用硬件断点)?/span>BSD要求参?/span>addr|ؓ1Q?/span>Linux要求该参数|ؓ0。其他的所有参数都被忽略?/span>
r PT_READ_I?/span>PT_READ_DQ?/span>PTRACE_PEEKTEXT?/span>PTRACE_PEEKDATAQ分别从代码区和?/span>?/span>调试q程的地址I间取机器字。在许多当代的^CQ这两个指o是等L(fng)?/span>ptrace函数接收目标地址addrQƈq回d的结果?/span>
r PT_WRITE_I?/span>PR_READ_DQ?/span>PTRACE_POKETEXT?/span>PTRACE_POKEDATAQ?/span>由_data传入的机器字写入addr所指定的地址?/span>
r PT_GETREGSQ?/span>PT_GETFPREGS?/span>PT_GETDBREGSQ?/span>PTRACE_GETREGSQ?/span>PTRACE_ FPREGS?/span>PT_GETFPXREGSQ?/span>一般用途寄存器、段寄存器和调试寄存器的D入到地址?/span>_addr指针所指定的调试器q程的内存区中。只?/span>i386q_接收q些与系l相关的命o。寄存器l构的描q放在头文gmachine/reg.h文g中?/span>
r PT_SETREGSQ?/span>PT_SETFPREGS?/span>PT_SETDBREGSQ?/span>PTRACE_SETREGSQ?/span>PTRACE_ SETFPREGS?/span>PT_SETFPXREGSQ?/span>通过拯?/span>_addr指针所指定的内存区域的内容来设|被调试q程的寄存器的倹{?/span>
r PT_KILLQ?/span>PTRACE_KILLQ?/span>?/span>sigkill发送到被调试进E,以终止其执行?/span>
In Part I, we ran the process to be traced as a child after calling ptrace(PTRACE_TRACEME, ..). If you simply wanted to see how the process is making system calls and trace the program, this would be sufficient. If you want to trace or debug a process already running, then ptrace(PTRACE_ATTACH, ..) should be used.
When a ptrace(PTRACE_ATTACH, ..) is called with the pid to be traced, it is roughly equivalent to the process calling ptrace(PTRACE_TRACEME, ..) and becoming a child of the tracing process. The traced process is sent a SIGSTOP, so we can examine and modify the process as usual. After we are done with modifications or tracing, we can let the traced process continue on its own by calling ptrace(PTRACE_DETACH, ..).
The following is the code for a small example tracing program:
int main()
{ int i;
for(i = 0;i < 10; ++i) {
printf("My counter: %d\n", i);
sleep(2);
}
return 0;
}
Save the program as dummy2.c. Compile and run it:
gcc -o dummy2 dummy2.cNow, we can attach to dummy2 by using the code below:
./dummy2 &
#include <sys/ptrace.h>The above program simply attaches to a process, waits for it to stop, examines its eip (instruction pointer) and detaches.
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h> /* For user_regs_struct
etc. */
int main(int argc, char *argv[])
{ pid_t traced_process;
struct user_regs_struct regs;
long ins;
if(argc != 2) {
printf("Usage: %s <pid to be traced>\n",
argv[0], argv[1]);
exit(1);
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process,
NULL, NULL);
wait(NULL);
ptrace(PTRACE_GETREGS, traced_process,
NULL, ®s);
ins = ptrace(PTRACE_PEEKTEXT, traced_process,
regs.eip, NULL);
printf("EIP: %lx Instruction executed: %lx\n",
regs.eip, ins);
ptrace(PTRACE_DETACH, traced_process,
NULL, NULL);
return 0;
}
To inject code use ptrace(PTRACE_POKETEXT, ..) and ptrace(PTRACE_POKEDATA, ..) after the traced process has stopped.
How do debuggers set breakpoints? Generally, they replace the instruction to be executed with a trap instruction, so that when the traced program stops, the tracing program, the debugger, can examine it. It will replace the original instruction once the tracing program continues the traced process. Here's an example:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
const int long_size = sizeof(long);
void getdata(pid_t child, long addr,
char *str, int len)
{ char *laddr;
int i, j;
union u {
long val;
char chars[long_size];
}data;
i = 0;
j = len / long_size;
laddr = str;
while(i < j) {
data.val = ptrace(PTRACE_PEEKDATA, child,
addr + i * 4, NULL);
memcpy(laddr, data.chars, long_size);
++i;
laddr += long_size;
}
j = len % long_size;
if(j != 0) {
data.val = ptrace(PTRACE_PEEKDATA, child,
addr + i * 4, NULL);
memcpy(laddr, data.chars, j);
}
str[len] = '\0';
}
void putdata(pid_t child, long addr,
char *str, int len)
{ char *laddr;
int i, j;
union u {
long val;
char chars[long_size];
}data;
i = 0;
j = len / long_size;
laddr = str;
while(i < j) {
memcpy(data.chars, laddr, long_size);
ptrace(PTRACE_POKEDATA, child,
addr + i * 4, data.val);
++i;
laddr += long_size;
}
j = len % long_size;
if(j != 0) {
memcpy(data.chars, laddr, j);
ptrace(PTRACE_POKEDATA, child,
addr + i * 4, data.val);
}
}
int main(int argc, char *argv[])
{ pid_t traced_process;
struct user_regs_struct regs, newregs;
long ins;
/* int 0x80, int3 */
char code[] = {0xcd,0x80,0xcc,0};
char backup[4];
if(argc != 2) {
printf("Usage: %s <pid to be traced>\n",
argv[0], argv[1]);
exit(1);
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process,
NULL, NULL);
wait(NULL);
ptrace(PTRACE_GETREGS, traced_process,
NULL, ®s);
/* Copy instructions into a backup variable */
getdata(traced_process, regs.eip, backup, 3);
/* Put the breakpoint */
putdata(traced_process, regs.eip, code, 3);
/* Let the process continue and execute
the int 3 instruction */
ptrace(PTRACE_CONT, traced_process, NULL, NULL);
wait(NULL);
printf("The process stopped, putting back "
"the original instructions\n");
printf("Press <enter> to continue\n");
getchar();
putdata(traced_process, regs.eip, backup, 3);
/* Setting the eip back to the original
instruction to let the process continue */
ptrace(PTRACE_SETREGS, traced_process,
NULL, ®s);
ptrace(PTRACE_DETACH, traced_process,
NULL, NULL);
return 0;
}
Here we replace the three bytes with the code for a trap instruction, and when the process stops, we replace the original instructions and reset the eip to original location. Figures 1-4 clarify how the instruction stream looks when above program is executed.
![]() |
![]() |
Figure 1. After the Process Is Stopped |
Figure 2. After the Trap Instruction Bytes Are Set |
![]() |
![]() |
Figure 3. Trap Is Hit and Control Is Given to the Tracing Program |
Figure 4. After the Original Instructions Are Replaced and eip Is Reset to the Original Location |
Now that we have a clear idea of how breakpoints are set, let's inject some code bytes into a running program. These code bytes will print “hello world”.
The following program is a simple “hello world” program with modifications to fit our needs. Compile the following program with:
gcc -o hello hello.c
void main()
{
__asm__("
jmp forward
backward:
popl %esi # Get the address of
# hello world string
movl $4, %eax # Do write system call
movl $2, %ebx
movl %esi, %ecx
movl $12, %edx
int $0x80
int3 # Breakpoint. Here the
# program will stop and
# give control back to
# the parent
forward:
call backward
.string \"Hello World\\n\""
);
}
The jumping backward and forward here is required to find the address of the “hello world” string.
We can get the machine code for the above assembly from GDB. Fire up GDB and disassemble the program:
(gdb) disassemble main
Dump of assembler code for function main:
0x80483e0 <main>: push %ebp
0x80483e1 <main+1>: mov %esp,%ebp
0x80483e3 <main+3>: jmp 0x80483fa <forward>
End of assembler dump.
(gdb) disassemble forward
Dump of assembler code for function forward:
0x80483fa <forward>: call 0x80483e5 <backward>
0x80483ff <forward+5>: dec %eax
0x8048400 <forward+6>: gs
0x8048401 <forward+7>: insb (%dx),%es:(%edi)
0x8048402 <forward+8>: insb (%dx),%es:(%edi)
0x8048403 <forward+9>: outsl %ds:(%esi),(%dx)
0x8048404 <forward+10>: and %dl,0x6f(%edi)
0x8048407 <forward+13>: jb 0x8048475
0x8048409 <forward+15>: or %fs:(%eax),%al
0x804840c <forward+18>: mov %ebp,%esp
0x804840e <forward+20>: pop %ebp
0x804840f <forward+21>: ret
End of assembler dump.
(gdb) disassemble backward
Dump of assembler code for function backward:
0x80483e5 <backward>: pop %esi
0x80483e6 <backward+1>: mov $0x4,%eax
0x80483eb <backward+6>: mov $0x2,%ebx
0x80483f0 <backward+11>: mov %esi,%ecx
0x80483f2 <backward+13>: mov $0xc,%edx
0x80483f7 <backward+18>: int $0x80
0x80483f9 <backward+20>: int3
End of assembler dump.
We need to take the machine code bytes from main+3 to backward+20, which is a total of 41 bytes. The machine code can be seen with the x command in GDB:
(gdb) x/40bx main+3Now we have the instruction bytes to be executed. Why wait? We can inject them using the same method as in the previous example. The following is the source code; only the main function is given here:
<main+3>: eb 15 5e b8 04 00 00 00
<backward+6>: bb 02 00 00 00 89 f1 ba
<backward+14>: 0c 00 00 00 cd 80 cc
<forward+1>: e6 ff ff ff 48 65 6c 6c
<forward+9>: 6f 20 57 6f 72 6c 64 0a
int main(int argc, char *argv[])
{ pid_t traced_process;
struct user_regs_struct regs, newregs;
long ins;
int len = 41;
char insertcode[] =
"\xeb\x15\x5e\xb8\x04\x00"
"\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"
"\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"
"\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"
"\x72\x6c\x64\x0a\x00";
char backup[len];
if(argc != 2) {
printf("Usage: %s <pid to be traced>\n",
argv[0], argv[1]);
exit(1);
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process,
NULL, NULL);
wait(NULL);
ptrace(PTRACE_GETREGS, traced_process,
NULL, ®s);
getdata(traced_process, regs.eip, backup, len);
putdata(traced_process, regs.eip,
insertcode, len);
ptrace(PTRACE_SETREGS, traced_process,
NULL, ®s);
ptrace(PTRACE_CONT, traced_process,
NULL, NULL);
wait(NULL);
printf("The process stopped, Putting back "
"the original instructions\n");
putdata(traced_process, regs.eip, backup, len);
ptrace(PTRACE_SETREGS, traced_process,
NULL, ®s);
printf("Letting it continue with "
"original flow\n");
ptrace(PTRACE_DETACH, traced_process,
NULL, NULL);
return 0;
}
In the previous example we injected the code directly into the executing instruction stream. However, debuggers can get confused with this kind of behaviour, so let's find the free space in the process and inject the code there. We can find free space by examining the /proc/pid/maps file of the traced process. The following function will find the starting address of this map:
long freespaceaddr(pid_t pid)
{
FILE *fp;
char filename[30];
char line[85];
long addr;
char str[20];
sprintf(filename, "/proc/%d/maps", pid);
fp = fopen(filename, "r");
if(fp == NULL)
exit(1);
while(fgets(line, 85, fp) != NULL) {
sscanf(line, "%lx-%*lx %*s %*s %s", &addr,
str, str, str, str);
if(strcmp(str, "00:00") == 0)
break;
}
fclose(fp);
return addr;
}
Each line in /proc/pid/maps represents a mapped region of the process. An entry in /proc/pid/maps looks like this:
map start-mapend protection offset deviceThe following program injects code into free space. It's similar to the previous injection program except the free space address is used for keeping our new code. Here is the source code for the main function:
inode process file
08048000-0804d000 r-xp 00000000 03:08
66111 /opt/kde2/bin/kdeinit
int main(int argc, char *argv[])
{ pid_t traced_process;
struct user_regs_struct oldregs, regs;
long ins;
int len = 41;
char insertcode[] =
"\xeb\x15\x5e\xb8\x04\x00"
"\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"
"\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"
"\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"
"\x72\x6c\x64\x0a\x00";
char backup[len];
long addr;
if(argc != 2) {
printf("Usage: %s <pid to be traced>\n",
argv[0], argv[1]);
exit(1);
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process,
NULL, NULL);
wait(NULL);
ptrace(PTRACE_GETREGS, traced_process,
NULL, ®s);
addr = freespaceaddr(traced_process);
getdata(traced_process, addr, backup, len);
putdata(traced_process, addr, insertcode, len);
memcpy(&oldregs, ®s, sizeof(regs));
regs.eip = addr;
ptrace(PTRACE_SETREGS, traced_process,
NULL, ®s);
ptrace(PTRACE_CONT, traced_process,
NULL, NULL);
wait(NULL);
printf("The process stopped, Putting back "
"the original instructions\n");
putdata(traced_process, addr, backup, len);
ptrace(PTRACE_SETREGS, traced_process,
NULL, &oldregs);
printf("Letting it continue with "
"original flow\n");
ptrace(PTRACE_DETACH, traced_process,
NULL, NULL);
return 0;
}
So what happens within the kernel now? How is ptrace implemented? This section could be an article on its own; however, here's a brief description of what happens.
When a process calls ptrace with PTRACE_TRACEME, the kernel sets up the process flags to reflect that it is being traced:
Source: arch/i386/kernel/ptrace.c
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
if (current->ptrace & PT_PTRACED)
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
ret = 0;
goto out;
}
When a system call entry is done, the kernel checks this flag and calls the trace system call if the process is being traced. The gory assembly details can be found in arch/i386/kernel/entry.S.
Now, we are in the sys_trace() function as defined in arch/i386/kernel/ptrace.c. It stops the child and sends a signal to the parent notifying that the child is stopped. This wakes up the waiting parent, and it does the ptrace magic. Once the parent is done, and it calls ptrace(PTRACE_CONT, ..) or ptrace(PTRACE_SYSCALL, ..), it wakes up the child by calling the scheduler function wake_up_process(). Some other architectures can implement this by sending a SIGCHLD to child.
ptrace may appear to be magic to some people, because it can examine and modify a running program. It is generally used by debuggers and system call tracing programs, such as ptrace. It opens up interesting possibilities for doing user-mode extensions as well. There have been a lot of attempts to extend the operating system on the user level. See Resources to read about UFO, a user-level extension to filesystems. ptrace also is used to employ security mechanisms.
All example code from this article and from Part I is available as a tar archive on the Linux Journal FTP site [ftp.ssc.com/pub/lj/listings/issue104/6210.tgz].
原文Q?br>
http://www.linuxjournal.com/article/6210
当服务器close一个连接时Q若client端接着发数据。根据TCP协议的规定,会收C个RST响应Qclient再往q个服务器发送数据时Q系l会发出一个SIGPIPE信号l进E,告诉q程q个q接已经断开了,不要再写了?br style="LINE-HEIGHT: normal"> Ҏ(gu)信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(l止、退?,所以client会退出。若不想客户端退出可以把SIGPIPE设ؓSIG_IGN ? signal(SIGPIPE,SIG_IGN); 服务器采用了fork的话Q要攉垃圾q程Q防止僵进E的产生Q可以这样处理:
#define MAXBUF 40960 while (1) { memset(sendline, 'a', sizeof(sendline)); } int signal(SIGPIPE, SIG_IGN); if (argc != 2) sockfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); Connect(sockfd, (SA *) &servaddr, sizeof(servaddr)); str_cli(stdin, sockfd); /* do it all */ exit(0); Z方便观察错误输出Qlib/writen.c也做了修改,加了些日志: /* include writen */ ssize_t &nbs
client.c攑֜tcpclieserv目录下,修改了MakefileQ增加了client.c的编译目?/p>
接着可以开始测试了?/p> 试1 忽略SIGPIPE信号Qwriten之前Q对方关闭接受进E?/h2>本机服务端:
试2 catch SIGPIPE信号Qwriten之前Q对方关闭接受进E?/h2>修改客户端代码,catch sigpipe信号
本机服务端:
试3 writenq程中,Ҏ(gu)关闭接受q程Z方便操作Q加?ơwrite的数据量Q修改MAXBUF?096000 本机服务端:
Z么以上测试,都是Ҏ(gu)已经中断socket后,发送端再次writeQ结果会有所不同呢。从后来扑ֈ的UNP5.12,5.13能找到答?/p>
以上解释了测?的现象,writeӞ收到RST.
以上解释了测?Q?的现?write一个已l接受到RST的socketQ系l内怼发送SIGPIPEl发送进E,如果q程catch/ignoreq个信号Qwrite都返回EPIPE错误. 因此,UNP应用Ҏ(gu)需要处理SIGPIPE信号Q至不要用pȝ~省的处理方式处理这个信Ppȝ~省的处理方式是退E,q样你的应用很难查处处理进Eؓ什么退出?/p>
在Unixpȝ下,如果send在等待协议传送数据时|络断开的话Q调用send的进E会接收C个SIGPIPE信号Q进E对该信L(fng)默认处理是进E终止?br style="LINE-HEIGHT: normal">在Unixpȝ下,如果recv函数在等待协议接收数据时|络断开了,那么调用recv的进E会接收C个SIGPIPE信号Q进E对该信L(fng)默认处理是进E终止?/p> 处理Ҏ(gu)Q?br style="LINE-HEIGHT: normal">在初始化时调?strong style="LINE-HEIGHT: normal">signal(SIGPIPE,SIG_IGN)忽略该信P只需一ơ) gdbQ?br style="LINE-HEIGHT: normal">gdb默认收到sigpipe时中断程序,可调?strong style="LINE-HEIGHT: normal">handle SIGPIPE nostop print 相关 (1)SIG_DFL信号专用的默认动? (2)SIG_IGN忽略信号 (3)指向函数的指?-捕获信号 每一U信号都被OSKitl予了一个符号名Q对?2位的i386q_而言Q一个字32位,因而信h32U。下面的表给Z常用的符号名、描q和它们的信号倹{?/p> W号名 信号?描述 是否W合POSIX 另外Q我再做一些补充,产生RST响应以至于系l发出SIGPIPE信号Q应该分ZU情? 1. 客户端到服务端之间网l断掉,或者服务端断电(sh){,物理q接断掉了,q种情况下客L(fng)不会退出,send函数正常执行Q不会感觉到自己出错。因为由于物理网l断开Q服务端不会l客L(fng)回应错误消息Q没有RST响应Q自然也不会产生SIGPIPE信号。但是当服务端再恢复正常的时候,对客L(fng)send来的消息会生RST响应Q客L(fng)收到SIGPIPE信号了,E序退出,但是q时send函数是能够返?-1的。可以进行异常处理?/p> 2.客户端到服务端的|络能通,服务E序挂掉Q客L(fng)E序会马上退出,因ؓ服务端能正常q回错误消息Q客L(fng)收到QSIGPIPE信号׃生了。不q我不确定此时服务端q回是的RST响应Q抓包来看没有RST标志。水qx限,只写到这了?/p> 文章出处Q?a style="LINE-HEIGHT: normal" >http://www.diybl.com/course/6_system/linux/Linuxjs/20081020/150832.html |
|
Z方便观察错误输出Qlib/writen.c也做了修改,加了些日志:
|
client.c攑֜tcpclieserv目录下,修改了MakefileQ增加了client.c的编译目?/p>
|
接着可以开始测试了?/p>
本机服务端:
修改客户端代码,catch sigpipe信号
|
本机服务端:
Z方便操作Q加?ơwrite的数据量Q修改MAXBUF?096000
本机服务端:
Z么以上测试,都是Ҏ(gu)已经中断socket后,发送端再次writeQ结果会有所不同呢。从后来扑ֈ的UNP5.12,5.13能找到答?/p>
The client's call to readline may happen before the server's RST is received by the client, or it may happen after. If the readline happens before the RST is received, as we've shown in our example, the result is an unexpected EOF in the client. But if the RST arrives first, the result is an ECONNRESET ("Connection reset by peer") error return from readline. |
以上解释了测?的现象,writeӞ收到RST.
What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST. The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated. If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE. |
以上解释了测?Q?的现?write一个已l接受到RST的socketQ系l内怼发送SIGPIPEl发送进E,如果q程catch/ignoreq个信号Qwrite都返回EPIPE错误.
因此,UNP应用Ҏ(gu)需要处理SIGPIPE信号Q至不要用pȝ~省的处理方式处理这个信Ppȝ~省的处理方式是退E,q样你的应用很难查处处理进Eؓ什么退出?/p>
http://blog.csdn.net/shcyd/archive/2006/10/28/1354577.aspx
在Unixpȝ下,如果send在等待协议传送数据时|络断开的话Q调用send的进E会接收C个SIGPIPE信号Q进E对该信L(fng)默认处理是进E终止?br>在Unixpȝ下,如果recv函数在等待协议接收数据时|络断开了,那么调用recv的进E会接收C个SIGPIPE信号Q进E对该信L(fng)默认处理是进E终止?/p>
处理Ҏ(gu)Q?br>在初始化时调?strong>signal(SIGPIPE,SIG_IGN)忽略该信P只需一ơ)
其时send或recv函数返?1Qerrno为EPIPEQ可视情况关闭socket或其他处?/p>
gdbQ?br>gdb默认收到sigpipe时中断程序,可调?strong>handle SIGPIPE nostop print
相关
(1)SIG_DFL信号专用的默认动?
(a)如果默认动作是暂停线E,则该U程的执行被暂时挂v。当U程暂停期间Q发送给U程的Q何附加信号都不交付,直到该线E开始执行,但是SIGKILL除外?br> (b)把挂起信L(fng)信号动作讄成SIG_DFLQ且光认动作是忽略信号 (SIGCHLD)?
(2)SIG_IGN忽略信号
(a)该信L(fng)交付对线E没有媄?br> (b)pȝ不允许把SIGKILL或SIGTOP信号的动作设|ؓSIG_DFL
(3)指向函数的指?-捕获信号
(a)信号一l交付,接收U程在指定地址上执行信hL(fng)序。在信号?获函数返回后Q接受线E必d被中断点恢复执行?br> (b)用C语言函数调用的方法进入信h捉程?
void func (signo)
int signo;
func( )是指定的信号捕捉函数Qsigno是正被交付信L(fng)~码
(c)如果SIGFPE,SIGILL或SIGSEGV信号不是由C标准定义的kill( )或raise( )函数所生成Q则从信号SIGFPE,SIGILL,SIGSEGV的信h获函数正常返回后U程的行为是未定义的?br> (d)pȝ不允许线E捕获SIGKILL和SIGSTOP信号?br> (e)如果U程为SIGCHLD信号建立信号捕获函数Q而该U程有未被等待的以终止的子线E时Q没有规定是否要生成SIGCHLD信号来指明那个子U程?br>
每一U信号都被OSKitl予了一个符号名Q对?2位的i386q_而言Q一个字32位,因而信h32U。下面的表给Z常用的符号名、描q和它们的信号倹{?
W号名 信号?描述 是否W合POSIX
SIGHUP 1 在控制终端上到挂断或控制线E死亡 ?br>SIGINT 2 交互注意信号 ?br>SIGQUIT 3 交互中止信号 ?br>SIGILL 4 到非法g的指令 ?br>SIGTRAP 5 从陷׃回朔 ?br>SIGABRT 6 异常l止信号 ?br>SIGEMT 7 EMT 指o ?br>SIGFPE 8 不正的术操作信号 ?br>SIGKILL 9 l止信号 ?br>SIGBUS 10 ȝ错误 ?br>SIGSEGV 11 到非法的内存调用 ?br>SIGSYS 12 pȝcall的错误参数 ?br>SIGPIPE 13 在无读者的道上写 ?br>SIGALRM 14 报时信号 ?br>SIGTERM 15 l止信号 ?br>SIGURG 16 IO信道紧急信受 ?br>SIGSTOP 17 暂停信号 ?br>SIGTSTP 18 交互暂停信号 ?br>SIGCONT 19 如果暂停则l ?br>SIGCHLD 20 子线E终止或暂停 ?br>SIGTTIN 21 后台U程l一成员试图从控制终端上d ?br>SIGTTOU 22 后台U程l的成员试图写到控制l端上 ?br>SIGIO 23 允许I/O信号 ?br>SIGXCPU 24 出CPU旉 ?br>SIGXFSZ 25 出文g大小限制 ?br>SIGVTALRM 26 虚时间警报器 ?br>SIGPROF 27 侧面旉警报器 ?br>SIGWINCH 28 H口大小的更攏V ?br>SIGINFO 29 消息h ?br>SIGUSR1 30 保留作ؓ用户自定义的信号1 ?br>SIGUSR2 31 保留作ؓ用户自定义的信号 ?nbsp;
注意QLinux信号机制基本上是从Unixpȝ中承过来的。早期Unixpȝ中的信号机制比较单和原始Q后来在实践中暴露出一些问题,因此Q把那些建立在早期机制上的信号叫?不可靠信?Q信号值小于SIGRTMIN(Red hat 7.2中,SIGRTMIN=32QSIGRTMAX=63)的信号都是不可靠信号。这是"不可靠信?的来源。它的主要问题是Q进E每ơ处理信号后Q就对信号的响应设|ؓ默认动作。在某些情况下,导致对信号的错误处理;因此Q用户如果不希望q样的操作,那么p在信号处理函数结ֆ一ơ调用signal()Q重新安装该信号?/p>
另外Q我再做一些补充,产生RST响应以至于系l发出SIGPIPE信号Q应该分ZU情?
1. 客户端到服务端之间网l断掉,或者服务端断电(sh){,物理q接断掉了,q种情况下客L(fng)不会退出,send函数正常执行Q不会感觉到自己出错。因为由于物理网l断开Q服务端不会l客L(fng)回应错误消息Q没有RST响应Q自然也不会产生SIGPIPE信号。但是当服务端再恢复正常的时候,对客L(fng)send来的消息会生RST响应Q客L(fng)收到SIGPIPE信号了,E序退出,但是q时send函数是能够返?-1的。可以进行异常处理?/p>
2.客户端到服务端的|络能通,服务E序挂掉Q客L(fng)E序会马上退出,因ؓ服务端能正常q回错误消息Q客L(fng)收到QSIGPIPE信号׃生了。不q我不确定此时服务端q回是的RST响应Q抓包来看没有RST标志。水qx限,只写到这了?br>
# use module
use XML::Simple;
use Data::Dumper;
# create object
$xml = new XML::Simple;
# read XML file
$data = $xml->XMLin("DebugInfo.xml", ForceArray => 1);
# print output
#print Dumper($data);
#print Dumper($data->{'employee'}[0]);
#print Dumper($data->{'employee'}[1]);
$data1=$data->{'DebugInfo'};
#print @{$data1};
open FILE,">>debug.log";
foreach $item (@{$data1}){
print FILE "${$item}{UID}[0],";
print FILE "${$item}{ChannelID}[0],";
print FILE "${$item}{IPAddress}[0],";
if (${$item}{BufferMapString}[0] =~/^HASH/)
{print FILE ",n";}
else{print FILE "${$item}{BufferMapString}[0]n"};
}
close FILE;
E疏(SparseQ文件的创徏
文gE疏化QsparsifyQ?/strong>
下面的方法都可以一个文件稀疏化?br>
1. cp:
cp~省使用--sparse=autoQ会自动探测源文件中是否有空z,以决定目标文件是否ؓE疏文Ӟ使用--sparse=never会禁止创建稀疏文件?br>
2. cpio:
如果不加--sparse参数Q稀疏文件中的空z将被填满?
3. tar:
如果不加 -S --sparse参数Q稀疏文件中的空z将被填满?
文gE疏化QsparsifyQ效率比?/strong>
下面我们创徏一?00M的稀疏文Ӟ比较一下几U文件稀疏化Ҏ(gu)的效率?
由此可见Q上面几U文件稀疏化的方法中Qcp的效率最高;tar和cpio׃使用道Q效率下降?
使EXT2/EXT3文gpȝE疏化QsparsifyQ?/strong>
如何是一个文件系l的映像文gE疏化QRon Yorston为大家提供了几种Ҏ(gu)Q我觉得下面的方法最单:
1. 使用Ron Yorston?a >zerofree文件系l中未用的块清零?br>
2.使用cp命o使映像文件稀疏化Q?
EXT2/EXT3文gpȝ的sparse_super参数
q个参数与EXT2/EXT3是否支持Sparse文g无关Q当打开该参数时Q文件系l将使用更少的超U块QSuper blockQ备份,以节省空间?/p>
如下的命令可以查看该参数Q?br>
或者:
可以通过使用Q?
或者:
来设|该参数?
参考资?br>
apt-cache search # —?package 搜烦?
apt-cache show #—?package 获取包的相关信息Q如说明、大、版本等)
sudo apt-get install # —?package 安装?
sudo apt-get install # ?#8211;(package - - reinstall 重新安装?
sudo apt-get -f install # ?#8211;(强制安装?#”-f = –fix-missing”当是修复安装?#8230;)
sudo apt-get remove #?#8211;(package 删除?
sudo apt-get remove - - purge # —?package 删除包,包括删除配置文g{?
sudo apt-get autoremove –purge # ?(package 删除包及其依赖的软g?配置文g{(只对6.10有效Q强烈推荐))
sudo apt-get update #——更新源
sudo apt-get upgrade #——更新已安装的包
sudo apt-get dist-upgrade # ———升U系l?br>
sudo apt-get dselect-upgrade #——?dselect 升
apt-cache depends #—?(package 了解使用依赖)
apt-cache rdepends # —?package 了解某个具体的依?#当是查看该包被哪些包依赖?#8230;)
sudo apt-get build-dep # —?package 安装相关的编译环?
apt-get source #—?package 下蝲该包的源代码)
sudo apt-get clean && sudo apt-get autoclean # —?#8211;清理下蝲文g的存?&& 只清理过时的?br>
sudo apt-get check #—?查是否有损坏的依?/p>
相关文gQ?br> openssh-clients-2.9p2-7.rpm
openssh-2.9p-7.rpm
openssh-server-2.9p2-7
内容Q?br>SSH的英文全U是Secure SHell。通过使用SSHQ你可以把所有传输的数据q行加密Q这?中间?q种d方式׃可能实现了,而且也能够防止DNS和IPƺ骗。还有一个额外的好处是传输的数据是l过压羃的,所以可以加快传输的速度。SSH有很多功能,它既可以代替telnetQ又可以为ftp、pop、甚至ppp提供一个安全的"通道"?/p>
1.什么是SSHQ?br>传统的网l服务程序,如:ftp、pop和telnet在本质上都是不安全的Q因为它们在|络上用明文传送口令和数据Q别有用心的人非常容易就可以截获q些口o和数据。而且Q这些服务程序的安全验证方式也是有其q的,是很容易受?中间?Qman-in-the-middleQ这U方式的d。所?中间?的攻?yn)L式,是"中间?冒充真正的服务器接收你的传给服务器的数据Q然后再冒充你把数据传给真正的服务器。服务器和你之间的数据传送被"中间?一转手做了手脚之后Q就会出现很严重的问题?br>SSH的英文全U是Secure SHell。通过使用SSHQ你可以把所有传输的数据q行加密Q这?中间?q种d方式׃可能实现了,而且也能够防止DNS和IPƺ骗。还有一个额外的好处是传输的数据是l过压羃的,所以可以加快传输的速度。SSH有很多功能,它既可以代替telnetQ又可以为ftp、pop、甚至ppp提供一个安全的"通道"?br>最初SSH是由芬兰的一家公司开发的。但是因为受版权和加密算法的限制Q现在很多h都{而用OpenSSH。OpenSSH是SSH的替代YӞ而且是免费的Q可以预计将来会有越来越多的Z用它而不是SSH?br>SSH是由客户端和服务端的软gl成的,有两个不兼容的版本分别是Q?.x?.x。用SSH 2.x的客L(fng)序是不能q接到SSH 1.x的服务程序上ȝ。OpenSSH 2.x同时支持SSH 1.x?.x?/p>
2.SSH的安全验证是如何工作?br>从客L(fng)来看QSSH提供两种U别的安全验证?br>W一U别(Z口o的安全验证)只要你知道自己帐号和口oQ就可以d到远E主机。所有传输的数据都会被加密,但是不能保证你正在连接的服务器就是你惌接的服务器。可能会有别的服务器在冒充真正的服务器,也就是受?中间?q种方式的攻凅R?br>W二U别(Z密匙的安全验证)需要依靠密匙,也就是你必须己创Z对密匙,q把公用密匙攑֜需要访问的服务器上。如果你要连接到SSH服务器上Q客L(fng)软g׃向服务器发出hQ请求用你的密匙q行安全验证。服务器收到h之后Q先在你在该服务器的家目录下L你的公用密匙Q然后把它和你发送过来的公用密匙q行比较。如果两个密匙一_服务器就用公用密匙加?质询"QchallengeQƈ把它发送给客户端Y件。客L(fng)软g收到"质询"之后可以用你的Uh密匙解密再把它发送给服务器?br>用这U方式,你必ȝ道自己密匙的口o。但是,与第一U别相比,W二U别不需要在|络上传送口令?br>W二U别不仅加密所有传送的数据Q而且"中间?q种d方式也是不可能的Q因Z没有你的Uh密匙Q。但是整个登录的q程可能需?0U?/p>
3.安装q测试OpenSSH
因ؓ受到国法律的限Ӟ在很多Linux的发行版中都没有包括OpenSSH。但是,可以从网l上下蝲q安装OpenSSH
安装完OpenSSH之后Q用下面命o试一下:
ssh -l [your accountname on the remote host] [address of the remote host]
如果OpenSSH工作正常Q你会看C面的提示信息Q?br>The authenticity of host [hostname] can't be established.
Key fingerprint is 1024 5f:a0:0b:65:d3:82:df:ab:44:62:6d:98:9c:fe:e9:52.
Are you sure you want to continue connecting (yes/no)?
OpenSSH告诉你它不知道这C机,但是你不用担心这个问题,因ؓ你是W一ơ登录这C机。键?yes"。这把q台L?识别标记"加到"~/.ssh/know_hosts"文g中。第二次讉Kq台L的时候就不会再显C条提CZ息了?br>然后QSSH提示你输入远E主Z你的帐号的口令。输入完口o之后Q就建立了SSHq接Q这之后可以象使用telnet那样使用SSH了?/p>
4.SSH的密?br>4.1 生成你自q密匙?br>生成q分发你自己的密匙有两个好处Q?br>可以防止"中间?q种d方式
可以只用一个口令就d到所有你想登录的服务器上
用下面的命o可以生成密匙Q?br>ssh-keygen如果q程L使用的是SSH 2.xp用这个命令:
ssh-keygen -d在同一CZ同时有SSH1和SSH2的密匙是没有问题的,因ؓ密匙是存成不同的文g的?/p>
ssh-keygen命oq行之后会显CZ面的信息Q?br>Generating RSA keys: ............................ooooooO......ooooooO
Key generation complete.
Enter file in which to save the key (/home/[user]/.ssh/identity):
[按下ENTERp了]
Created directory '/home/[user]/.ssh'.
Enter passphrase (empty for no passphrase):
[输入的口令不会显C在屏幕上]
Enter same passphrase again:
[重新输入一遍口令,如果忘记了口令就只能重新生成一ơ密匙了]
Your identification has been saved in /home/[user]/.ssh/identity.
[q是你的Uh密匙]
Your public key has been saved in /home/[user]/.ssh/identity.pub.
The key fingerprint is: 2a:dc:71:2f:27:84:a2:e4:a1:1e:a9:63:e2:fa:a5:89 [user]@[local machine]
"ssh-keygen -d"做的是几乎同L(fng)事,但是把一对密匙存为(默认情况下)"/home/[user]/.ssh/id_dsa"Q私人密匙)?/home/[user]/.ssh/id_dsa.pub"Q公用密匙)?/p>
现在你有一对密匙了Q公用密匙要分发到所有你想用sshd的远E主Z去;Uh密匙要好好地保管防止别h知道你的Uh密匙。用"ls -l ~/.ssh/identity"?ls -l ~/.ssh/id_dsa"所昄的文件的讉K权限必须?-rw-------"?br>如果你怀疑自q密匙已经被别人知道了Q不要迟疑马上生成一Ҏ(gu)的密匙。当Ӟ你还要重新分发一ơ公用密匙?/p>
4.2 分发公用密匙
在每一个你需要用SSHq接的远E服务器上,你要在自q家目录下创徏一?.ssh"的子目录Q把你的公用密匙"identity.pub" 拯到这个目录下q把它重命名?authorized_keys"。然后执行:
chmod 644 .ssh/authorized_keys
q一步是必不可少的。如果除了你之外别h?authorized_keys"文g也有写的权限QSSH׃会工作?br>如果你想从不同的计算机登录到q程LQ?authorized_keys"文g也可以有多个公用密匙。在q种情况下,必须在新的计机上重新生成一对密匙,然后把生成的"identify.pub"文g拯q粘贴到q程L?authorized_keys"文g里。当然在新的计算Z你必L一个帐P而且密匙是用口o保护的。有一点很重要Q就是当你取消了q个帐号之后Q别忘了把这一对密匙删掉?/p>
5.配置SSH CompressionLevel 压羃的别从"1"Q最快)?9"Q压~率最高)。默认gؓ"6"?/p>
ForwardX11 yes Z在本地运行远E的XE序必须讄q个选项?/p>
LogLevel DEBUG 当SSH出现问题的时候,q选项很有用了。默认gؓ"INFO"?/p>
5.2 配置服务端的软g 6.拯文g 6.2 ?sftp"拯文g 6.3 ?rsync"拯文g 6.4 ?加密通道"的ftp拯文g 7.用SSH讄"加密通道" 如果收到q样的出错信息:telnet: Unable to connect to remote host: Connection refused p明远E服务器上没有运行SSH服务软g?/p>
端口转发使用q样的命令语法: 7.2 为POP加上"加密通道" 7.3 为X加上"加密通道" Q如果在q程L上你的家目录下不存在".Xauthority"q个文gQ那么当用SSHd的时候就会自动创建)?br>比如启动一个XE序QxtermQ可以这个命令: 7.4 为linuxconf加上"加密通道" 7.5 为Webmin加上"加密通道"
5.1 配置客户端的软g
OpenSSH有三U配|方式:命o行参数、用户配|文件和pȝU的配置文gQ?/etc/ssh/ssh_config"Q。命令行参数优先于配|文Ӟ用户配置文g优先于系l配|文件。所有的命o行的参数都能在配|文件中讄。因为在安装的时候没有默认的用户配置文gQ所以要?/etc/ssh/ssh_config"拯q新命名ؓ"~/.ssh/config"?br>标准的配|文件大概是q样的:
[lots of explanations and possible options listed]
# Be paranoid by default
Host *
ForwardAgent no
ForwardX11 no
FallBackToRsh no
q有很多选项的设|可以用"man ssh"查看"CONFIGURATION FILES"q一章?br>配置文g是按序d的。先讄的选项先生效?br>假定你在Host *fbc
HostName www.foobar.com
User bilbo
ForwardAgent yes
Compression yes
# Be paranoid by default
Host *
ForwardAgent no
ForwardX11 no
FallBackToRsh no
你输?ssh fbc"之后QSSH会自动地从配|文件中扑ֈL的全名,用你的用户名dq且?ssh-agent"理的密匙进行安全验证。这样很方便吧!
用SSHq接到其它远E计机用的q是"paranoidQ偏执)"默认讄。如果有些选项没有在配|文件或命o行中讄Q那么还是用默认的"paranoid"讄?br>在我们上面D的那个例子中Q对于到其它q有一些需要仔l看一看的讄选项是:
CheckHostIP yes q个选项用来q行IP地址的检查以防止DNSƺ骗?/p>
SSH服务器的配置使用的是"/etc/ssh/sshd_config"配置文gQ这些选项的设|在配置文g中已l有了一些说明而且?man sshd"也可以查看帮助。请注意OpenSSH对于SSH 1.x?.x没有不同的配|文件?br>在默认的讄选项中需要注意的有:
PermitRootLogin yes 最好把q个选项讄?PermitRootLogin without-password"Q这?root"用户׃能从没有密匙的计机上登录。把q个选项讄?no"禁?root"用户dQ只能用"su"命o从普通用戯{?root"?br>X11Forwarding no 把这个选项讄?yes"允许用户q行q程L上的XE序。就禁止这个选项也不能提高服务器的安全因为用户可以安装他们自q转发器(forwarderQ,请参?man sshd"?br>PasswordAuthentication yes 把这个选项讄?no"只允许用L(fng)Z密匙的方式登录。这当然会给那些l常需要从不同Ld的用户带来麻烦,但是q能够在很大E度上提高系l的安全性。基于口令的d方式有很大的q?br># Subsystem /usr/local/sbin/sftpd 把最前面的#号去掉ƈ且把路径名设|成"/usr/bin/sftpserv"Q用户就能?sftp"Q安全的FTPQ了Qsftpserv在sftp软g包中Q。因为很多用户对FTP比较熟?zhn)而且"scp"用v来也有一些麻烦,所?sftp"q是很有用的。而且2.0.7版本以后的图形化的ftp工具"gftp"也支?sftp"?/p>
6.1 ?scp"拯文g
SSH提供了一些命令和shell用来dq程服务器。在默认情况下它不允怽拯文gQ但是还是提供了一?scp"命o?br>假定你想把本地计机当前目录下的一个名?dumb"的文件拷贝到q程服务?a ?br>可以用这个命令:scp dumb bilbo@www.foobar.com:.
把文件拷贝回来用q个命oQscp bilbo@www.foobar.com:dumb .
"scp"调用SSHq行dQ然后拷贝文Ӟ最后调用SSH关闭q个q接?br>如果在你?~/.ssh/config"文g中已lؓwww.foobar.com做了q样的配|:
Host *fbc
HostName www.foobar.com
User bilbo
ForwardAgent yes
那么你就可以?fbc"来代?bilbo@www.foobar.com"Q命令就化ؓ"scp dumb fbc:."?br>"scp"假定你在q程L上的家目录ؓ你的工作目录。如果你使用相对目录p相对于家目录?br>?scp"命o?-r"参数允许递归地拷贝目录?scp"也可以在两个不同的远E主Z间拷贝文件?br>有时候你可能会试图作q样的事Q用SSHd?a scp [local machine]:dumb ."想用它把本地?dumb"文g拯C当前d的远E服务器上。这时候你会看C面的出错信息Q?br>ssh: secure connection to [local machine] refused
之所以会出现q样的出错信息是因ؓ你运行的是远E的"scp"命oQ它试图d到在你本地计机上运行的SSH服务E序……所以最好在本地q行"scp"除非你的本地计算Zq行SSH服务E序?/p>
如果你习(fn)惯用ftp的方式拷贝文Ӟ可以试着?sftp"?sftp"建立用SSH加密的安全的FTPq接通道Q允怋用标准的ftp命o。还有一个好处就?sftp"允许你通过"exec"命oq行q程的程序。从2.0.7版以后,囑Ş化的ftp客户软g"gftp"支?sftp"?br>如果q程的服务器没有安装sftp服务器Y?sftpserv"Q可以把"sftpserv"的可执行文g拯C的远E的家目录中Q或者在q程计算机的$PATH环境变量中设|的路径Q?sftp"会自动激z这个服务YӞ你没有必要在q程服务器上有什么特D的权限?/p>
"rsync"是用来拷贝、更新和Udq程和本地文件的一个有用的工具Q很Ҏ(gu)可以用"-e ssh"参数和SSHl合h使用?rsync"的一个优点就是,不会拯全部的文Ӟ只会拯本地目录和远E目录中有区别的文g。而且它还使用很高效的压羃法Q这h贝的速度很快?/p>
如果你坚持要用传l的FTP客户软g。SSH可以为几乎所有的协议提供"安全通道"。FTP是一个有一点奇怪的协议Q例如需要两个端口)而且不同的服务程序和服务E序之间、客L(fng)序和客户E序之间q有一些差别?br>实现"加密通道"的方法是使用"端口转发"。你可以把一个没有用到的本地端口Q通常大于1000Q设|成转发C个远E服务器上,然后只要q接本地计算Z的这个端口就行了。有一点复杂是吗?
其实一个基本的x是Q{发一个端口,让SSH在后台运行,用下面的命oQ?br>ssh [user@remote host] -f -L 1234:[remote host]:21 tail -f /etc/motd
接着q行FTP客户Q把它设|到指定的端口:
lftp -u [username] -p 1234 localhost
当然Q用q种Ҏ(gu)很麻烦而且很容易出错。所以最好用前三种Ҏ(gu)?/p>
7.1 "加密通道"的基知识
SSH?加密通道"是通过"端口转发"来实现的。你可以在本地端口(没有用到的)和在q程服务器上q行的某个服务的端口之间建立"加密通道"。然后只要连接到本地端口。所有对本地端口的请求都被SSH加密q且转发到远E服务器的端口。当然只有远E服务器上运行SSH服务器Y件的时?加密通道"才能工作。可以用下面命o查一些远E服务器是否q行SSH服务Q?br>telnet [full name of remote host] 22
ssh -f [username@remote host] -L [local port]:[full name of remote host]:[remote port] [some command]
你不仅可以{发多个端口而且可以?~/.ssh/config"文g中用"LocalForward"讄l常使用的一些{发端口?/p>
你可以用POP协议从服务器上取email。ؓPOP加上"加密通道"可以防止POP的密码被|络监听器(snifferQ监听到。还有一个好处就是SSH的压~方式可以让邮g传输得更快?br>假定你在pop.foobar.com上有一个POP帐号Q你的用户名?bilbo"你的POP口o?topsecret"。用来徏立SSH"加密通道"的命令是Q?br>ssh -f -C bilbo@pop.foobar.com -L 1234:pop.foobar.com:110 sleep 5
Q如果要试Q可以把"sleep"的值加?00Q。运行这个命令之后会提示你输入POP口oQ?br>bilbo@pop.foobar.com's password:
输入口o之后可以用"telnet"q接到本地的转发端口了?br>telnet localhost 1234
你会收到q程mail服务器的"READY"消息?br>当然Q这个方法要求你手工输入所有的POP命oQ这是很不方便的。可以用FetchmailQ参考how to configure FetchmailQ。Secure POP via SSH mini-HOWTO、man fetchmail和在"/usr/doc/fetchmail-[…]"目录下的Fetchmail的FAQ都提供了一些具体的例子?br>h意IMAP协议使用的是不同的端口:IMAP v2的端口号?43而IMAP v3的端口号?20?/p>
如果你打在本地计算Zq行q程SSH服务器上的XE序Q那么登录到q程的计机上,创徏一个名?~/.ssh/environment"的文件ƈ加上q一行:
XAUTHORITY=/home/[remote user name]/.Xauthority
ssh -f -X -l [remote user name] [remote machine] xterm
q将在远E运行xtermq个E序。其它的XE序也是用相同的Ҏ(gu)?/p>
Linuxconf(http://www.solucorp.qc.ca/linuxconf/)是Linux的配|工P它支持远E管理。Linuxconf的FAQ重说明了如何通过SSH使用linuxconfQ?br>其命令ؓQremadmin --exec [link_command] linuxconf --guiproto
如果你想在两台计机之间用加密的方式传送信息,那么最好用ssh。命令是Q?br>remadmin --exec ssh -l [account] linuxconf --guiproto
q是非常有效的而且q行用图形界面管理计机?br>q种Ҏ(gu)需要在客户端安装linuxconf。其它的Ҏ(gu)q有直接d到服务器上用"X11Forwarding"或字W界面运行linuxconf?/p>
Webmin(ssh -f -l [remote user name] [remote host] -L 1234:[remote host]:10000 tail -f /etc/motd
把浏览器指向http://localhost:1234
]]>