Hide Forgot
Description of problem: 4th vsyscall (venosys_1) is supposed to return -ENOSYS when called. GCC is optimizing it away, leaving random data instead. These 2 commit might be of interest: commit 2e8ad43ec07545780ce7992cb18e2d82c7abd24c [PATCH] x86-64: Prevent gcc 4 from optimizing away vsyscalls commit a4928cffe6435caf427ae673131a633c1329dbf3 "make namespacecheck" fixes I'm not aware of any useful 4th vsyscall being ever present in kernel - initial priority and severity set to low. Version-Release number of selected component (if applicable): 2.6.32-150.el6.x86_64 How reproducible: 100% Steps to Reproduce: 1. --- cut b.c --- #include <stdio.h> #include <stdlib.h> #define vsyscall_venosys 0xffffffffff600000+1024*3 typedef long (* venosys_proto)(void); int run_venosys() { venosys_proto venosys; venosys = (venosys_proto) vsyscall_venosys; return venosys(); } int main() { int ret = run_venosys(); printf("ret: %d\n", ret); return 0; } --- cut --- 2. gcc b.c 3. ./a.out Segmentation fault 4. gdb ./a.out Notice first 3 vsyscalls have correct function prologue, 4th is just random data. (gdb) disassemble 0xffffffffff600000+1024*0, 0xffffffffff600000+1024*0+10 Dump of assembler code from 0xffffffffff600000 to 0xffffffffff60000a: 0xffffffffff600000: push %rbp 0xffffffffff600001: mov %rsp,%rbp 0xffffffffff600004: push %r13 0xffffffffff600006: push %r12 0xffffffffff600008: mov %rdi,%r12 End of assembler dump. (gdb) disassemble 0xffffffffff600000+1024*1, 0xffffffffff600000+1024*1+10 Dump of assembler code from 0xffffffffff600400 to 0xffffffffff60040a: 0xffffffffff600400: push %rbp 0xffffffffff600401: mov %rsp,%rbp 0xffffffffff600404: push %rbx 0xffffffffff600405: mov %rdi,%rbx 0xffffffffff600408: sub $0x18,%rsp End of assembler dump. (gdb) disassemble 0xffffffffff600000+1024*2, 0xffffffffff600000+1024*2+10 Dump of assembler code from 0xffffffffff600800 to 0xffffffffff60080a: 0xffffffffff600800: push %rbp 0xffffffffff600801: test %rdx,%rdx 0xffffffffff600804: mov %rdx,%r8 0xffffffffff600807: mov %rsp,%rbp End of assembler dump. (gdb) disassemble 0xffffffffff600000+1024*3, 0xffffffffff600000+1024*3+10 Dump of assembler code from 0xffffffffff600c00 to 0xffffffffff600c0a: 0xffffffffff600c00: (bad) 0xffffffffff600c01: movslq 0x6f(%rcx,%rbp,2),%esi 0xffffffffff600c05: outsb %ds%rsi),(%dx) 0xffffffffff600c06: cmp (%rax),%ah 0xffffffffff600c08: and $0xa646c,%eax >>> End of assembler dump. Actual results: 4th vsyscall is unusable and can crash any user space application, which tries to call it. Expected results: 4th vsyscall is valid and returns -ENOSYS. Additional info: With 2.6.18-257.el5 it works as expected.
> 4th vsyscall (venosys_1) is supposed to return -ENOSYS when called. GCC is > optimizing it away, leaving random data instead. I was about to post a patch to change venosys_1() back to not being static, but looking a bit more, I'm wondering whether it's actually supposed to be exported to user space. The kernel's "arch/x86/include/asm/vsyscall.h" doesn't create a system call number for it: enum vsyscall_num { __NR_vgettimeofday, __NR_vtime, __NR_vgetcpu, }; And it's not verified by vsyscall_init(): static int __init vsyscall_init(void) { BUG_ON(((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday))); BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)); BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu)); #ifdef CONFIG_SYSCTL register_sysctl_table(kernel_root_table2); #endif on_each_cpu(cpu_vsyscall_init, NULL, 1); hotcpu_notifier(cpu_vsyscall_notifier, 0); return 0; } Do you have some documentation or reference somewhere that says that the system call should actually be made available to user-space?
Can't find anything in current Documentation. The only reference, which I found is at top of arch/x86/kernel/vsyscall_64.c: * vsyscall 1 is located at -10Mbyte, vsyscall 2 is located * at virtual address -10Mbyte+1024bytes etc... There are at max 4 * vsyscalls. One vsyscall can reserve more than 1 slot to avoid * jumping out of line if necessary. We cannot add more with this * mechanism because older kernels won't return -ENOSYS. Looking at history, vsyscall(2) also used to return -ENOSYS: http://lwn.net/Articles/13141/ My assumption was, that user-space application could check and see if some vsyscall is supported or not, and it would do so by trying to call it. The main reason for this bz was, that it used to work in RHEL5.
> The main reason for this bz was, that it used to work in RHEL5. OK, I understand. I'm wondering whether that's the bug, i.e., that it should never have been exported to begin with. Anyway, I sent an email off to Ingo and Andi to get their take on the matter.
Andi's response was: "The original design was that they should be there." Ingo did not respond. Anyway, I posted it on LKML: https://lkml.org/lkml/2011/6/3/216 If it gets accepted, it can go into RHEL6; otherwise it should be closed NOTABUG.
> If it gets accepted, it can go into RHEL6; otherwise it should be > closed NOTABUG. As it turns out, this patch steps all over patch #6 of this 10-part series posted on 5/31/11, which removes venosys_1() entirely: [PATCH v3 00/10] Remove syscall instructions at fixed addresses https://lkml.org/lkml/2011/5/31/181 ... [PATCH v3 06/10] x86-64: Remove vsyscall number 3 (venosys) https://lkml.org/lkml/2011/5/31/187
And also given that it's already been removed from Ingo's tip tree, it's pretty obvious that it's never going to be resurrected. Can we just close this BZ? Thanks, Dave
Agreed, closing as NOTABUG.