/* IRQs are off. */ movq %rsp, %rdi /* Sign extend the lower 32bit as syscall numbers are treated as int */ movslq %eax, %rsi
/* clobbers %rax, make sure it is after saving the syscall nr */ IBRS_ENTER UNTRAIN_RET CLEAR_BRANCH_HISTORY
call do_syscall_64 /* returns with IRQs disabled */
/* * Try to use SYSRET instead of IRET if we're returning to * a completely clean 64-bit userspace context. If we're not, * go to the slow exit path. * In the Xen PV case we must use iret anyway. */
ALTERNATIVE "testb %al, %al; jz swapgs_restore_regs_and_return_to_usermode", \ "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
/* * We win! This label is here just for ease of understanding * perf profiles. Nothing jumps here. */ syscall_return_via_sysret: IBRS_EXIT POP_REGS pop_rdi=0
/* * Now all regs are restored except RSP and RDI. * Save old stack pointer and switch to trampoline stack. */ movq %rsp, %rdi movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp UNWIND_HINT_END_OF_STACK
structpt_regs { /* * C ABI says these regs are callee-preserved. They aren't saved on * kernel entry unless syscall needs a complete, fully filled * "struct pt_regs". */ unsignedlong r15; unsignedlong r14; unsignedlong r13; unsignedlong r12; unsignedlong bp; unsignedlong bx;
/* These regs are callee-clobbered. Always saved on kernel entry. */ unsignedlong r11; unsignedlong r10; unsignedlong r9; unsignedlong r8; unsignedlong ax; unsignedlong cx; unsignedlong dx; unsignedlong si; unsignedlong di;
/* * orig_ax is used on entry for: * - the syscall number (syscall, sysenter, int80) * - error_code stored by the CPU on traps and exceptions * - the interrupt number for device interrupts * * A FRED stack frame starts here: * 1) It _always_ includes an error code; * * 2) The return frame for ERET[US] starts here, but * the content of orig_ax is ignored. */ unsignedlong orig_ax;
/* The IRETQ return frame starts here */ unsignedlong ip;
union { /* CS selector */ u16 cs; /* The extended 64-bit data slot containing CS */ u64 csx; /* The FRED CS extension */ structfred_csfred_cs; };
unsignedlong flags; unsignedlong sp;
union { /* SS selector */ u16 ss; /* The extended 64-bit data slot containing SS */ u64 ssx; /* The FRED SS extension */ structfred_ssfred_ss; };
/* * Top of stack on IDT systems, while FRED systems have extra fields * defined above for storing exception related information, e.g. CR2 or * DR6. */ };
TOCTOU(Time-of-check to time-of-use)
简单地说是程序在检查某个条件和使用该条件之前存在一个时间窗口,条件发生了改变。
pipe_buffer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/** * struct pipe_buffer - a linux kernel pipe buffer * @page: the page containing the data for the pipe buffer * @offset: offset of data inside the @page * @len: length of data inside the @page * @ops: operations associated with this buffer. See @pipe_buf_operations. * @flags: pipe buffer flags. See above. * @private: private data owned by the ops. **/ structpipe_buffer { structpage *page; unsignedint offset, len; conststructpipe_buf_operations *ops; unsignedint flags; unsignedlong private; };
structpipe_buf_operations { /* * ->confirm() verifies that the data in the pipe buffer is there * and that the contents are good. If the pages in the pipe belong * to a file system, we may need to wait for IO completion in this * hook. Returns 0 for good, or a negative error value in case of * error. If not present all pages are considered good. */ int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *);
/* * When the contents of this pipe buffer has been completely * consumed by a reader, ->release() is called. */ void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
/* * Attempt to take ownership of the pipe buffer and its contents. * ->try_steal() returns %true for success, in which case the contents * of the pipe (the buf->page) is locked and now completely owned by the * caller. The page may then be transferred to a different mapping, the * most often used case is insertion into different file address space * cache. */ bool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);
/* * Get a reference to the pipe buffer. */ bool (*get)(struct pipe_inode_info *, struct pipe_buffer *); };