小编Amm*_*izi的帖子

Linux 可执行文件 .data 部分的默认行为在 5.4 和 5.9 之间发生了变化?

故事

情况1

我不小心在该.data部分中编写了我的汇编代码。我编译并执行了它。该程序在Linux下正常运行5.4.0-53-generic,即使我没有指定就像一面旗帜execstack

案例2:

之后,我在 Linux 下执行了该程序5.9.0-050900rc5-generic。该程序得到了SIGSEGV。我通过阅读检查了虚拟内存权限/proc/$pid/maps。事实证明,该部分不可执行。

我认为 Linux 上有一个配置可以管理该权限。但我不知道在哪里可以找到。

代码

[Linux 5.4.0-53-通用]

运行(正常)

ammarfaizi2@integral:/tmp$ uname -r
5.4.0-53-generic
ammarfaizi2@integral:/tmp$ cat test.asm
[section .data]
global _start
_start:
  mov eax, 60
  xor edi, edi
  syscall
ammarfaizi2@integral:/tmp$ nasm --version
NASM version 2.14.02
ammarfaizi2@integral:/tmp$ nasm -felf64 test.asm -o test.o
ammarfaizi2@integral:/tmp$ ld test.o -o test
ammarfaizi2@integral:/tmp$ ./test
ammarfaizi2@integral:/tmp$ echo $?
0
ammarfaizi2@integral:/tmp$ md5sum test
7ffff5fd44e6ff0a278e881732fba525  test
ammarfaizi2@integral:/tmp$ 
Run Code Online (Sandbox Code Playgroud)

检查权限(00400000-00402000 rwxp),所以它是可执行的。

## Debug
gef?  shell …
Run Code Online (Sandbox Code Playgroud)

linux assembly x86-64 nasm elf

9
推荐指数
2
解决办法
411
查看次数

Linux x86-64 系统调用何时破坏 %r8、%r9 和 %r10?

我刚刚浏览了Linux内核源代码树并阅读了文件tools/include/nolibc/nolibc.h

syscall在这个文件中看到了 use %r8%r9以及%r10在 clobber 列表中。
还有一条评论说:

rcx 和 r8..r11 可能会被破坏,其他的则被保留。

据我所知,syscall只有 clobbers%rax%rcx%r11和记忆)。

有没有syscall真实%r8的例子%r9%r10

linux assembly x86-64 system-calls

7
推荐指数
1
解决办法
1036
查看次数

Linux x86-64 fork 系统调用对 C 标准 libc 文件 I/O 的奇怪行为(关键字:fork、fclose、linux)

故事

我试图在 Linux 上诊断用 C 编写的应用程序中的错误。原来这个bug是由于在父进程中句柄仍然打开时在子进程中忘记 引起的。fcloseFILE *

文件操作只是read. 没有写操作。

情况1

该应用程序正在运行Linux 5.4.0-58-generic。在这种情况下,错误发生了。

案例二

该应用程序正在运行Linux 5.10.0-051000-generic。在这种情况下,没有错误,这正是我所期望的。

什么是错误?

fork如果fclose子进程中没有,则父进程执行随机数的系统调用。

案例2肯定

我完全知道忘记 fclose会导致内存泄漏,但是:

  • 我认为,只是在这种情况下,并不是绝对必要的,因为子进程会尽快退出,而我使用的退出exit(3)不是_exit(2)
  • 奇怪的是,为什么在子进程中忘记 fclose会影响父进程?

我目前的猜测:

这是一个 Linux 内核错误,已在5.4. 然而我没有证据,但我的测试向我证明了这一点。


我已经能够通过fclose在退出之前调用子进程来修复这个应用程序错误。但是,我想知道在这种情况下实际发生了什么。所以我的问题是如何fclose在子进程中忘记影响父进程?


重现问题的非常简单的代码(附上 3 个文件)。

注意:test1.c 和 test2.c 的区别只fclose在于子进程。test2.c 不会fclose在子进程中调用。

文件测试.txt

123123123
123123123
123123123
123123123
123123123 …
Run Code Online (Sandbox Code Playgroud)

c linux fork x86-64 stdio

6
推荐指数
1
解决办法
155
查看次数

为什么 `read()` 系统调用的缓冲区溢出只在 GDB 中导致 `EFAULT`?

短篇故事

我正在用 Assembly 编写一个简单的程序来模拟缓冲区溢出。缓冲区只是从 512 字节堆栈中分配的内存,然后read()使用来自 stdin fd 的 4096 字节调用系统调用。

当我在 GDB 之外执行有效负载时,缓冲区溢出工作正常。但是当我在 GDB 中时,系统调用read()返回EFAULT.

在这种情况下,我们的缓冲区溢出应该替换返回地址并使%rip到达secret_func


为什么在这种情况下缓冲区溢出在 GDB 中不起作用?


资源

代码测试.S

.section .rodata
str1:
    .ascii "Enter the input: "
str2:
    .ascii "\nYou find a secret function!\n"
str_end:

.section .text
.global _start

_start:
    xorl    %ebp, %ebp
    andq    $-16, %rsp
    callq   main
_exit:
    movl    %eax, %edi
    movl    $60, %eax
    syscall

main:
    subq    $512, %rsp

    movl    $1, %eax
    movl    $1, %edi …
Run Code Online (Sandbox Code Playgroud)

linux assembly x86-64 buffer-overflow

6
推荐指数
0
解决办法
67
查看次数

如何防止 gcc 优化破坏 rep movsb 代码?

我试图用rep movsb指令创建我的 memcpy 代码。当优化被禁用时,它适用于任何尺寸。但是,当我启用优化时,它没有按预期工作。

问题

  1. 如何防止 gcc 优化破坏 rep movsb 代码?
  2. 我的代码有问题所以导致未定义的行为吗?

创建我自己的 memcpy 的动机:

我从Intel® 64 and IA-32 Architectures Optimization Reference Manual section 3.7.6 中阅读了有关 memcpy 的增强 movsb 。我来到了 libc 源代码,我看到 libc 的默认 memcpy 使用 SSE 而不是movsb.

因此,我想比较memcpy 的SSE 指令rep movsb之间的性能。但是现在,我发现它有些不对劲。

重现问题的简单代码(test.c)

#include <stdio.h>
#include <string.h>

inline static void *my_memcpy(
  register void *dest,
  register const void *src,
  register size_t n
) {
  __asm__ volatile(
    "mov %0, %%rdi;"
    "mov %1, …
Run Code Online (Sandbox Code Playgroud)

c optimization gcc x86-64 inline-assembly

5
推荐指数
1
解决办法
342
查看次数

是什么阻止编译器优化手写的 memcmp()?

鉴于:

#include <string.h>

bool test_data(void *data)
{
    return memcmp(data, "abcd", 4) == 0;
}
Run Code Online (Sandbox Code Playgroud)

编译器可以将其优化为:

test_data:
    cmpl    $1684234849, (%rdi)
    sete    %al
    ret
Run Code Online (Sandbox Code Playgroud)

这很好。

但如果我使用我自己的memcmp()(而不是来自<string.h>),编译器无法将其优化为单个cmpl指令。相反,它这样做:

test_data:
    cmpl    $1684234849, (%rdi)
    sete    %al
    ret
Run Code Online (Sandbox Code Playgroud)
test_data:
    cmpb    $97, (%rdi)
    jne     .L5
    cmpb    $98, 1(%rdi)
    jne     .L5
    cmpb    $99, 2(%rdi)
    jne     .L5
    cmpb    $100, 3(%rdi)
    sete    %al
    ret
.L5:
    xorl    %eax, %eax
    ret
Run Code Online (Sandbox Code Playgroud)

链接: https: //godbolt.org/z/Kfhchr45a

  • 是什么阻止编译器进一步优化它?
  • 我是否做了一些阻碍优化的事情?

c optimization assembly x86-64 memcmp

5
推荐指数
2
解决办法
333
查看次数

带有 TCP 流的 TLS/SSL 中的 ssl_read() 不返回 BIO_write() 写入的整个缓冲区

以下代码部分的目的是轮询套接字 fd-set,如果数据(ssl 加密)可用,则读取它并通过 openssl 库解密。底层传输层是 TCP Stream,因此数据以流的形式出现(而不是数据包)。

现在,如果从对等方快速连续发送了多个数据包(假设有 2 个长度为 85 字节的数据包),那么 TCP 接收将返回同一缓冲区中的两个数据包,接收的字节数为 170。因此,我们有一个携带 2 个 ssl 加密数据包(或 n 个数据包)的缓冲区。对于 ssl 解密,我们需要调用 BIO_write() 将缓冲区写入 ssl_bio,然后调用 ssl_read() 来检索解密的缓冲区。但是,尽管 BIO_write() 正在向 bio 中写入 170 个字节,但 ssl_read() 似乎只返回一个解密的数据包(43 个字节)。没有返回错误。如何知道 bio 中是否还有未处理的字节。有什么出路吗或者代码中有什么错误?

当在 tcp recv() 中接收到单个数据包时,代码工作正常。

int iReadyFds = poll( PollFdSet, iFdCount, iTimeout);

for(iFdIndx = 0; iFdIndx < (iFdCount) && (iReadyFds>0); ++iFdIndx)
{
    if((PollFdSet[iFdIndx].events == 0) ||
       (PollFdSet[iFdIndx].fd == 0) ||
       (PollFdSet[iFdIndx].revents != POLLIN)
       )
    {
        continue;
    }

    /* we have data to …
Run Code Online (Sandbox Code Playgroud)

c sockets openssl tcp polling

4
推荐指数
1
解决办法
4154
查看次数

为什么 clang 的尾声使用 `add $N, %rsp` 而不是 `mov %rbp, %rsp` 来恢复 `%rsp`?

考虑以下:

ammarfaizi2@integral:/tmp$ vi test.c
ammarfaizi2@integral:/tmp$ cat test.c

extern void use_buffer(void *buf);

void a_func(void)
{
    char buffer[4096];
    use_buffer(buffer);
}

__asm__("emit_mov_rbp_to_rsp:\n\tmovq %rbp, %rsp");

ammarfaizi2@integral:/tmp$ clang -Wall -Wextra -c -O3 -fno-omit-frame-pointer test.c -o test.o
ammarfaizi2@integral:/tmp$ objdump -d test.o

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <emit_mov_rbp_to_rsp>:
   0: 48 89 ec              mov    %rbp,%rsp
   3: 66 2e 0f 1f 84 00 00  cs nopw 0x0(%rax,%rax,1)
   a: 00 00 00 
   d: 0f 1f 00              nopl   (%rax)

0000000000000010 <a_func>:
  10: 55                    push   %rbp
  11: 48 …
Run Code Online (Sandbox Code Playgroud)

assembly x86-64 clang micro-optimization

3
推荐指数
1
解决办法
288
查看次数

通过“LD_PRELOAD”替换“malloc”、“calloc”、“realloc”和“free”时出现分段错误

背景

我尝试更换malloc(3)/ calloc(3)/ realloc(3)/free(3)通过LD_PRELOAD环境变量。我尝试使用静态链接的自定义函数,它们工作得很好。

但是,当我将它作为共享库附加到 时LD_PRELOAD,它总是会导致段错误。


关于功能的简短技术说明

  • 我使用 Linux x86-64mmap(2)munmap(2)syscall for malloc(3)and free(3)
  • calloc(3)只是对malloc(3)乘法溢出检查的调用。
  • realloc(3)电话malloc(3),然后复制旧的数据到新分配的内存和取消映射旧内存。

问题

  • 我的方法有什么问题,以至于它总是导致段错误?
  • 我该如何调试它(gdb 和 valgrind 也有段错误)?
  • 我在这里错过了什么?

笔记

我完全意识到mmap每次malloc调用时总是使用是一个坏主意,尤其是对于性能而言。我只想知道为什么我的方法不起作用。


输出

ammarfaizi2@integral:~$ gcc -shared mem.c -O3 -o my_mem.so
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so ls
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so cat
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so w
Segmentation fault (core …
Run Code Online (Sandbox Code Playgroud)

c linux malloc x86-64 ld-preload

2
推荐指数
1
解决办法
161
查看次数

线程永远不会获得锁(pthread_mutex_lock)

故事

根据手册页https://linux.die.net/man/3/pthread_mutex_lock

互斥锁引用的互斥锁对象应通过调用 pthread_mutex_lock() 锁定。如果互斥锁已被锁定,则调用线程应阻塞,直到互斥锁可用。

我有一个带线程的程序。这是程序流程:

  1. 主进程线程随时调用pthread_mutex_lock一个循环内。
  2. 主进程持有锁时,请求锁的线程会阻塞(等待授予锁)。
  3. 主进程用释放锁时pthread_mutex_unlock线程应该突然获得锁。
  4. 主进程再次请求锁时,主进程应该等待线程释放锁。

问题是,在第 3 点,线程不会在主进程释放锁后立即获得锁。主进程pthread_mutex_lock在下一个循环周期(在第 4 点)调用时首先获得它。

如何处理这种情况?

如何让线程主进程释放锁后立即获得锁?

重现问题的简单代码

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;

void *
my_thread(void *p)
{
  (void)p;

  while (1) {
    pthread_mutex_lock(&my_mutex);
    printf("The thread is holding the lock...\n");
    sleep(1);
    pthread_mutex_unlock(&my_mutex); …
Run Code Online (Sandbox Code Playgroud)

c multithreading mutex locking pthreads

1
推荐指数
1
解决办法
110
查看次数