Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix storage_lookup_patches return code in case process already termin… #35

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ kpatch_make: kpatch_make.o
LIBUNWIND_LIBS := $(shell pkg-config --libs libunwind libunwind-ptrace)


libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_patch.c kpatch_elf.o kpatch_ptrace.o kpatch_coro.o
libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_patch.o kpatch_elf.o kpatch_ptrace.o kpatch_coro.o
libcare-ctl: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o
libcare-ctl: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS)

libcare-stresstest: kpatch_user-stresstest.o kpatch_storage.o kpatch_patch.c kpatch_elf.o kpatch_ptrace.o kpatch_coro.o
libcare-stresstest: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o
libcare-stresstest: kpatch_user-stresstest.o kpatch_log-stresstest.o kpatch_storage.o kpatch_patch.o kpatch_elf.o kpatch_ptrace.o kpatch_coro.o
libcare-stresstest: kpatch_process.o kpatch_common.o rbtree.o
libcare-stresstest: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS)

libcare-client: libcare-client.o
Expand Down
35 changes: 35 additions & 0 deletions src/kpatch_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,29 @@

#include "kpatch_log.h"

#ifdef STRESS_TEST
#include "kpatch_user.h"
extern int parent_pid;
#endif

int log_level = LOG_INFO;
int log_indent;
static FILE *log_file;

static void __valog(int level, const char *prefix, const char *fmt, va_list va)
{
FILE *f = level <= LOG_WARN ? stderr : stdout;
if (prefix)
fprintf(f, "%s", prefix);

if (log_file) {
va_list vaf;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please print prefix as well.

va_copy(vaf, va);
if (prefix)
fprintf(log_file, "%s", prefix);
vfprintf(log_file, fmt, vaf);
fflush(log_file);
}
vfprintf(f, fmt, va);
}

Expand Down Expand Up @@ -52,6 +66,10 @@ void kpfatal(const char *fmt, ...)
__valog(LOG_ERR, "FATAL! ", fmt, va);
va_end(va);

#ifdef STRESS_TEST
if (parent_pid >= 0)
stress_test_notify_parent();
#endif
exit(1);
}

Expand Down Expand Up @@ -100,3 +118,20 @@ void _kpfatalerror(const char *file, int line, const char *fmt, ...)

exit(EXIT_FAILURE);
}

int log_file_init(char *fname)
{
if (!fname)
return -1;
log_file = fopen(fname, "a");
if (!log_file)
return -1;
return 0;
}

void log_file_free()
{
if (log_file)
fclose(log_file);
log_file = NULL;
}
3 changes: 3 additions & 0 deletions src/kpatch_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ void _kplogerror(const char *filename, int line, const char *fmt, ...)
#define LOG_DEBUG 3
#define LOG_TRACE 5

int log_file_init(char *fname);
void log_file_free();

#endif
14 changes: 7 additions & 7 deletions src/kpatch_patch.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ object_unapply_old_patch(struct object_file *o)
return 1;
}

printf("%s: replacing patch level %d with level %d\n",
kpinfo("%s: replacing patch level %d with level %d\n",
o->name,
kpatch_applied->user_level,
kpatch_storage->user_level);
Expand Down Expand Up @@ -565,12 +565,12 @@ int process_patch(int pid, void *_data)

out:
if (ret < 0) {
printf("Failed to apply patch '%s'\n", storage->path);
kpinfo("Failed to apply patch '%s'\n", storage->path);
kperr("Failed to apply patch '%s'\n", storage->path);
} else if (ret == 0)
printf("No patch(es) applicable to PID '%d' have been found\n", pid);
kpinfo("No patch(es) applicable to PID '%d' have been found\n", pid);
else {
printf("%d patch hunk(s) have been successfully applied to PID '%d'\n", ret, pid);
kpinfo("%d patch hunk(s) have been successfully applied to PID '%d'\n", ret, pid);
ret = 0;
}

Expand Down Expand Up @@ -750,11 +750,11 @@ int process_unpatch(int pid, void *_data)
kpatch_process_free(proc);

if (ret < 0)
printf("Failed to cancel patches for %d\n", pid);
kpinfo("Failed to cancel patches for %d\n", pid);
else if (ret == 0)
printf("No patch(es) cancellable from PID '%d' were found\n", pid);
kpinfo("No patch(es) cancellable from PID '%d' were found\n", pid);
else
printf("%d patch hunk(s) were successfully cancelled from PID '%d'\n", ret, pid);
kpinfo("%d patch hunk(s) were successfully cancelled from PID '%d'\n", ret, pid);

return ret;
}
Expand Down
14 changes: 7 additions & 7 deletions src/kpatch_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -746,9 +746,9 @@ process_print_cmdline(kpatch_process_t *proc)

for (i = 0; i < rv; i++) {
if (buf[i] != '\n' && isprint(buf[i]))
putchar(buf[i]);
kpinfo("%c", buf[i]);
else
printf("\\x%02x", (unsigned char)buf[i]);
kpinfo("\\x%02x", (unsigned char)buf[i]);
}
}

Expand Down Expand Up @@ -860,9 +860,9 @@ kpatch_process_kickstart_execve_wrapper(kpatch_process_t *proc)
if (ret < 0)
return -1;

printf("kpatch_ctl real cmdline=\"");
kpinfo("kpatch_ctl real cmdline=\"");
process_print_cmdline(proc);
printf("\"\n");
kpinfo("\"\n");

return 0;
}
Expand Down Expand Up @@ -1137,11 +1137,11 @@ kpatch_process_init(kpatch_process_t *proc,
void
kpatch_process_print_short(kpatch_process_t *proc)
{
printf("kpatch_ctl targeting pid %d\n", proc->pid);
kpinfo("kpatch_ctl targeting pid %d\n", proc->pid);
if (proc->send_fd == -1) {
printf("kpatch_ctl cmdline=\"");
kpinfo("kpatch_ctl cmdline=\"");
process_print_cmdline(proc);
printf("\"\n");
kpinfo("\"\n");
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/kpatch_storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ int storage_lookup_patches(kpatch_storage_t *storage, kpatch_process_t *proc)
struct kp_file *pkpfile;
struct object_file *o;
const char *bid;
int found = 0, ret;
int found = -1, ret;

list_for_each_entry(o, &proc->objs, list) {
if (!o->is_elf || is_kernel_object_name(o->name))
Expand All @@ -410,6 +410,8 @@ int storage_lookup_patches(kpatch_storage_t *storage, kpatch_process_t *proc)
o->name);
continue;
}
if (found < 0)
found = 0;

ret = storage_load_patch(storage, bid, &pkpfile);
if (ret == PATCH_OPEN_ERROR) {
Expand Down
118 changes: 103 additions & 15 deletions src/kpatch_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/types.h>

#include <gelf.h>
#include <libunwind.h>
Expand Down Expand Up @@ -566,7 +567,12 @@ cmd_update(int argc, char *argv[])

#ifdef STRESS_TEST

struct test_data {
int parent_pid = -1;
static int process_pid = -1;
static char test_log_base[PATH_MAX-sizeof("-4194304")];
static char test_log_name[PATH_MAX];

static struct test_data {
int option_period;
int stat_cycle_num;
} test_info = { .option_period = 0, .stat_cycle_num = 0 };
Expand All @@ -581,26 +587,20 @@ server_wait(int pid, int period)
for (i=0; i<period; i++) {
nanosleep(&req, &rem);
if (kill(pid, 0) != 0) {
fprintf(stderr, "Process %d terminated.\n", pid);
kpinfo("Process %d terminated.\n", pid);
return -1;
}
}
return 0;
}

static int
server_stress_test(int fd, int argc, char *argv[])
server_stress_test(int fd, int pid)
{
int pid;
int delay;
test_info.stat_cycle_num = 0;
srand(time(NULL));

if (sscanf(argv[1], "%d", &pid) != 1) {
kperr("Can't parse pid from %s\n", argv[1]);
return -1;
}

while (1) {
while (patch_user(storage_dir, pid, 0, fd) < 0)
if (server_wait(pid, 1) < 0)
Expand All @@ -627,20 +627,95 @@ server_stress_test(int fd, int argc, char *argv[])
return 0;
}

static int stress_test_log_init(int is_base_process)
{
if (!strlen(test_log_base))
return 0;
if (is_base_process) {
if (snprintf(test_log_name, PATH_MAX, "%s-base", test_log_base) >= PATH_MAX) {
kplogerror("Can't initialize log \'%s\'-<PID>\n", test_log_base);
return -1;
}
} else
if (snprintf(test_log_name, PATH_MAX, "%s-%d", test_log_base, getpid()) >= PATH_MAX) {
kplogerror("Can't initialize log \'%s\'-<PID>\n", test_log_base);
return -1;
}
if (log_file_init(test_log_name)) {
kplogerror("Can't open log file \'%s\'\n", test_log_name);
return -1;
}
return 0;
}

void stress_test_notify_parent()
{
if (parent_pid < 0)
return;
union sigval code;
code.sival_int = process_pid;
sigqueue(parent_pid, SIGCHLD, code);
}

void stress_test_signal_handler(int sig, siginfo_t *info, void *ucontext)
{
switch (sig) {
case SIGCHLD: {
if (info->si_code == SI_QUEUE) {
kpinfo("Child process pid %d fatal error.\n", info->si_pid);
return;
} else {
int pid, status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
kpinfo("Process pid %d exited.\n", pid);
return;
}
break;
}
}
}

void stress_test_install_sigaction()
{
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO | SA_RESTART;
sigact.sa_sigaction = &stress_test_signal_handler;
sigaction(SIGCHLD, &sigact, NULL);
}

static int cmd_stress_test(int fd, int argc, char *argv[])
{
if (sscanf(argv[1], "%d", &process_pid) != 1) {
kplogerror("Can't parse pid from %s\n", argv[1]);
return -1;
}

parent_pid = getpid();
int child = fork();
if (child == 0) {
int rv = server_stress_test(fd, argc, argv);
signal(SIGCHLD, SIG_DFL);
log_file_free();
if (stress_test_log_init(0))
kpfatal("Can't initialize log.\n");

int rv = server_stress_test(fd, process_pid);

log_file_free();
exit(rv);
}
kpinfo("Spawned child %d to patch pid %d\n", child, process_pid);
close(fd);
return 0;
}

static int usage_stresstest()
{
fprintf(stderr, "usage: libcare-stresstest PERIOD(ms, 0 - only patch) <UNIX socket> [STORAGE ROOT]\n");
fprintf(stderr, "usage: libcare-stresstest [args] PERIOD(ms, 0 - only patch) <UNIX socket> [STORAGE ROOT]\n");
fprintf(stderr, "\nOptions:\n");
fprintf(stderr, " -v - verbose mode\n");
fprintf(stderr, " -l <BASE> - log file name <BASE>-PID\n");
fprintf(stderr, " -h - this message\n");
return -1;
}

Expand Down Expand Up @@ -828,9 +903,11 @@ cmd_server(int argc, char *argv[])
}

#ifdef STRESS_TEST
if (sscanf(argv[0], "%d", &test_info.option_period) != 1) {
if (stress_test_log_init(1))
kpfatal("Can't initialize log.\n");
if (sscanf(argv[0], "%d", &test_info.option_period) != 1)
kplogerror("Can't parse period from %s\n", argv[0]);
}
kpinfo("Starting libcare-stresstest: period=%d\n", test_info.option_period);
#endif

sfd = server_bind_socket(argv[1]);
Expand Down Expand Up @@ -954,13 +1031,23 @@ int main(int argc, char *argv[])
{
int opt;

while ((opt = getopt(argc, argv, "+vh")) != EOF) {
while ((opt = getopt(argc, argv, "+vl:h")) != EOF) {
switch (opt) {
case 'v':
log_level += 1;
break;
case 'h':
return usage(NULL);
case 'l':
#ifdef STRESS_TEST
strncpy(test_log_base, optarg, sizeof(test_log_base));
if (test_log_base[sizeof(test_log_base)-1]) {
usage_stresstest();
kpfatal("Can't initialize log\n");
break;
}
break;
#endif
default:
return usage("unknown option");
}
Expand All @@ -972,7 +1059,8 @@ int main(int argc, char *argv[])
#ifdef STRESS_TEST
if (argc < 3)
return usage("not enough arguments.");
signal(SIGCHLD, SIG_IGN);

stress_test_install_sigaction();
return cmd_server(argc, argv);
#else
if (argc < 1)
Expand Down
1 change: 1 addition & 0 deletions src/kpatch_user.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@

int cmd_patch_user(int argc, char *argv[]);
int cmd_unpatch_user(int argc, char *argv[]);
void stress_test_notify_parent();

#endif