2012-04-26 59 views
16

内核升级后(从2.6.24到2.6.33),我的xinetd守护进程突然停止工作。 我已经运行了strace的,发现这个:close()x86_64系统调用怪异返回值

[...] 
close(3)        = 0 
munmap(0x7f1a93b43000, 4096)   = 0 
getrlimit(RLIMIT_NOFILE, {rlim_cur=8*1024, rlim_max=16*1024}) = 0 
setrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0 
close(3)        = 4294967287 
exit_group(1)       = ? 

所以基本上,它看起来像close系统调用返回不同的东西比0或-1

我做了一些测试,似乎它发生只有64位可执行文件:

$ file closetest32 
closetest32: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped 
$ strace closetest32 
execve("./closetest32", ["closetest32"], [/* 286 vars */]) = 0 
[ Process PID=4731 runs in 32 bit mode. ] 
open("/proc/mounts", O_RDONLY)   = 3 
close(3)        = 0 
close(3)        = -1 EBADF (Bad file descriptor) 
_exit(0)        = ? 


$ file closetest64 
closetest64: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), statically linked, not stripped 
$ strace closetest64 
execve("./closetest64", ["closetest64"], [/* 286 vars */]) = 0 
open("/proc/mounts", O_RDONLY)   = 3 
close(3)        = 0 
close(3)        = 4294967287 
_exit(0)        = ? 

我运行下面的内核:

Linux foobar01 2.6.33.9-rt31.64.el5rt #1 SMP PREEMPT RT Wed May 4 10:34:12 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux 

最糟糕的部分是我无法在具有相同内核的另一台计算机上重现该错误。

任何想法?

编辑:为请求:这里的closetest64用于closetest32代码和

closetest32.asm:

.section .data 

filename: 
    .ascii "/proc/mounts" 

.section .text 
.globl _start 
_start: 
    xorl %edi, %edi 
    movl $5, %eax # open() i386 system call 
    leal filename, %ebx # %ebx ---> filename 
    movl $0, %esi # O_RDONLY flag into esi 
    int $0x80 

    xorl %edi, %edi 
    movl $6, %eax # close() i386 system call 
    movl $3, %ebx # fd 3 
    int $0x80 

    xorl %edi, %edi 
    movl $6, %eax # close() i386 system call 
    movl $3, %ebx # fd 3 
    int $0x80 

    ## terminate program via _exit() system call 
    movl $1, %eax # %eax = _exit() i386 system call 
    xorl %ebx, %ebx # %ebx = 0 normal program return code 
    int $0x80 

编译为:

as test32.asm -o test32.o --32 
ld -m elf_i386 test32.o -o closetest32 

closetest64.asm:

.section .data 

filename: 
    .ascii "/proc/mounts" 

.section .text 
.globl _start 
_start: 
    xorq %rdi, %rdi 
    movq $2, %rax # open() system call 
    leaq filename, %rdi # %rdi ---> filename 
    movq $0, %rsi # O_RDONLY flag into rsi 
    syscall 

    xorq %rdi, %rdi 
    movq $3, %rax # close() system call 
    movq $3, %rdi # fd 3 
    syscall 

    xorq %rdi, %rdi 
    movq $3, %rax # close() system call 
    movq $3, %rdi # fd 3 
    syscall 

    ## terminate program via _exit() system call 
    movq $60, %rax # %rax = _exit() system call 
    xorq %rdi, %rdi # %rdi = 0 normal program return code 
    syscall 

汇编:

as test64.asm -o test64.o 
ld test64.o -o closetest64 
+6

不确定它是否相关,但可能巧合的是,返回值0xFFFFFFF7 = -9。而EBADF = +9。好奇。 – 2012-04-26 15:00:58

+0

你可以显示closetest64/32的源代码吗? – JeremyP 2012-04-26 15:18:48

+0

两台机器上的strace二进制和glibc版本是什么?我只做了一个简单的测试,并为两个32/64打印4.5.20打印-1 EBADF。 libc - 2.13 – strkol 2012-04-26 15:25:49

回答

1

正如所料,回滚到以前的内核版本解决了这个问题。我不是一个真正的内核专家,但据我了解,通过@R给出了答案..是有道理的:

这是一个64位的机器,所以1 < < 32-9应该不会出现。问题是内核在内部使用unsigned而不是int来获得这些函数的返回值,然后返回-EBADF,它得到的模2^32减2而不是模2^64

问题在于通用处理系统调用错误返回的libc系统调用包装中的代码必须将返回值视为long(因为它可能是一个指针,或者对于某些系统调用很长),因此在进行比较时要查看它是否为表示错误的小负值。但是内核返回(long)(unsigned)-9,这与(long)-9非常不同。或(无符号长整型)-9(其中任何一个都可以工作)。