Skip to content

Commit 52cd14b

Browse files
author
Roman Rashchupkin
committed
Add error return codes to libcare-ctl.
1 parent 9752ec3 commit 52cd14b

File tree

5 files changed

+99
-52
lines changed

5 files changed

+99
-52
lines changed

src/kpatch_log.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ void kpfatal(const char *fmt, ...)
5252
__valog(LOG_ERR, "FATAL! ", fmt, va);
5353
va_end(va);
5454

55-
exit(1);
55+
#ifdef STRESS_TEST
56+
if (parent_pid >= 0)
57+
stress_test_notify_parent();
58+
#endif
59+
exit(ERROR_FATAL);
5660
}
5761

5862
extern int elf_errno(void) __attribute__((weak));
@@ -98,5 +102,5 @@ void _kpfatalerror(const char *file, int line, const char *fmt, ...)
98102
__valogerror(file, line, fmt, va);
99103
va_end(va);
100104

101-
exit(EXIT_FAILURE);
105+
exit(ERROR_FATAL);
102106
}

src/kpatch_log.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@
33

44
#include <stdio.h>
55

6+
#define ERROR_CODE(return_code) (return_code - 256)
7+
8+
#define ERROR_SUCCESS 0
9+
#define ERROR_GENERAL ERROR_CODE(1)
10+
// ERROR_FATAL: libcare-ctl encountered fatal error and terminated execution
11+
#define ERROR_FATAL ERROR_CODE(2)
12+
// ERROR_ARGUMENTS: libcare-ctl was invoked with wrong arguments
13+
#define ERROR_ARGUMENTS ERROR_CODE(3)
14+
// ERROR_PROCESS_NOT_FOUND: process with specified pid does not exist or have already exited
15+
#define ERROR_PROCESS_NOT_FOUND ERROR_CODE(4)
16+
// ERROR_PATCH_NOT_FOUND: patch file not found, or patch of same or higher patch level is already applied to the process
17+
#define ERROR_PATCH_NOT_FOUND ERROR_CODE(5)
18+
// ERROR_PATCH_FAILURE: libcare-ctl failed to apply patch
19+
#define ERROR_PATCH_FAILURE ERROR_CODE(6)
20+
// ERROR_UNPATCH_FAILURE: libcare-ctl failed to cancel patch
21+
// ERROR_UNPATCH_FAILURE can also be returned in case of error during unpatch after unsuccessful patching
22+
#define ERROR_UNPATCH_FAILURE ERROR_CODE(8)
23+
// ERROR_RESOURCE_ACCESS: libcare-ctl was not able to attach to process(PTRACE_ATTACH, write access to /proc/PID/mem or stack unwind)
24+
#define ERROR_RESOURCE_ACCESS ERROR_CODE(9)
25+
// ERROR_RESOURCE_BUSY: process is currently executing code that must be modified and can't be patched at this moment
26+
#define ERROR_RESOURCE_BUSY ERROR_CODE(10)
27+
628
extern int log_level, log_indent;
729

830
void kplog(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));

src/kpatch_patch.c

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,20 @@ patch_ensure_safety(struct object_file *o,
256256
ret = kpatch_ptrace_execute_until(o->proc, 3000, 0);
257257

258258
/* OK, at this point we may have new threads, discover them */
259-
if (ret == 0)
259+
if (ret == 0) {
260260
ret = kpatch_process_attach(o->proc);
261+
if (ret == ERROR_RESOURCE_ACCESS) {
262+
free(retips);
263+
return ret;
264+
}
265+
}
261266
if (ret == 0)
262267
ret = patch_verify_safety(o, NULL, action);
263268
}
264269

265270
free(retips);
266271

267-
return ret ? -1 : 0;
272+
return ret ? ERROR_RESOURCE_BUSY : 0;
268273
}
269274

270275
/*****************************************************************************
@@ -347,12 +352,12 @@ object_apply_patch(struct object_file *o)
347352
ret = duplicate_kp_file(o);
348353
if (ret < 0) {
349354
kplogerror("can't duplicate kp_file\n");
350-
return -1;
355+
return ERROR_PATCH_FAILURE;
351356
}
352357

353358
ret = kpatch_elf_load_kpatch_info(o);
354359
if (ret < 0)
355-
return ret;
360+
return ERROR_PATCH_FAILURE;
356361

357362
kp = o->kpfile.patch;
358363

@@ -379,26 +384,26 @@ object_apply_patch(struct object_file *o)
379384
*/
380385
ret = kpatch_object_allocate_patch(o, sz);
381386
if (ret < 0)
382-
return ret;
387+
return ERROR_PATCH_FAILURE;
383388
ret = kpatch_resolve(o);
384389
if (ret < 0)
385-
return ret;
390+
return ERROR_PATCH_FAILURE;
386391
ret = kpatch_relocate(o);
387392
if (ret < 0)
388-
return ret;
393+
return ERROR_PATCH_FAILURE;
389394
ret = kpatch_process_mem_write(o->proc,
390395
kp,
391396
o->kpta,
392397
kp->total_size);
393398
if (ret < 0)
394-
return -1;
399+
return ERROR_PATCH_FAILURE;
395400
if (o->jmp_table) {
396401
ret = kpatch_process_mem_write(o->proc,
397402
o->jmp_table,
398403
o->kpta + kp->jmp_offset,
399404
o->jmp_table->size);
400405
if (ret < 0)
401-
return ret;
406+
return ERROR_PATCH_FAILURE;
402407
}
403408

404409
ret = patch_ensure_safety(o, ACTION_APPLY_PATCH);
@@ -408,7 +413,7 @@ object_apply_patch(struct object_file *o)
408413
for (i = 0; i < o->ninfo; i++) {
409414
ret = patch_apply_hunk(o, i);
410415
if (ret < 0)
411-
return ret;
416+
return ERROR_PATCH_FAILURE;
412417
}
413418

414419
return 1;
@@ -442,9 +447,10 @@ object_unapply_old_patch(struct object_file *o)
442447
kpatch_applied->user_level,
443448
kpatch_storage->user_level);
444449
ret = object_unapply_patch(o, /* check_flag */ 0);
445-
if (ret < 0)
450+
if (ret < 0) {
446451
kperr("can't unapply patch for %s\n", o->name);
447-
else {
452+
ret = ERROR_UNPATCH_FAILURE;
453+
} else {
448454
/* TODO(pboldin): handle joining the holes here */
449455
o->applied_patch = NULL;
450456
o->info = NULL;
@@ -464,7 +470,7 @@ kpatch_apply_patches(kpatch_process_t *proc)
464470

465471
ret = object_unapply_old_patch(o);
466472
if (ret < 0)
467-
break;
473+
return ret;
468474

469475
ret = object_apply_patch(o);
470476
if (ret < 0)
@@ -480,11 +486,11 @@ kpatch_apply_patches(kpatch_process_t *proc)
480486
* TODO(pboldin): close the holes so the state is the same
481487
* after unpatch
482488
*/
483-
ret = object_unapply_patch(o, /* check_flag */ 1);
484-
if (ret < 0) {
489+
if (object_unapply_patch(o, /* check_flag */ 1) < 0) {
490+
ret = ERROR_UNPATCH_FAILURE;
485491
kperr("Can't unapply patch for %s\n", o->name);
486492
}
487-
return -1;
493+
return ret;
488494
}
489495

490496
int process_patch(int pid, void *_data)
@@ -565,16 +571,18 @@ int process_patch(int pid, void *_data)
565571

566572
out:
567573
if (ret < 0) {
568-
printf("Failed to apply patch '%s'\n", storage->path);
574+
if (ret == -1)
575+
return ERROR_PATCH_FAILURE;
576+
kpinfo("Failed to apply patch '%s'\n", storage->path);
569577
kperr("Failed to apply patch '%s'\n", storage->path);
570-
} else if (ret == 0)
571-
printf("No patch(es) applicable to PID '%d' have been found\n", pid);
572-
else {
573-
printf("%d patch hunk(s) have been successfully applied to PID '%d'\n", ret, pid);
574-
ret = 0;
578+
return ret;
579+
} else if (ret == 0) {
580+
kpinfo("No patch(es) applicable to PID '%d' have been found\n", pid);
581+
return ERROR_PATCH_NOT_FOUND;
582+
} else {
583+
kpinfo("%d patch hunk(s) have been successfully applied to PID '%d'\n", ret, pid);
584+
return ERROR_SUCCESS;
575585
}
576-
577-
return ret;
578586
}
579587

580588

@@ -592,6 +600,8 @@ object_find_applied_patch_info(struct object_file *o)
592600

593601
if (o->info != NULL)
594602
return 0;
603+
if (!o->kpta || !o->kpfile.patch)
604+
return -1;
595605

596606
iter = kpatch_process_mem_iter_init(o->proc);
597607
if (iter == NULL)
@@ -617,6 +627,8 @@ object_find_applied_patch_info(struct object_file *o)
617627
o->ninfo++;
618628
} while (1);
619629

630+
if (!o->applied_patch)
631+
return 0;
620632
o->applied_patch->info = o->info;
621633
o->applied_patch->ninfo = o->ninfo;
622634

@@ -641,6 +653,8 @@ object_unapply_patch(struct object_file *o, int check_flag)
641653
if (ret < 0)
642654
return ret;
643655

656+
if (!o->kpta || !o->kpfile.patch)
657+
return -1;
644658
orig_code_addr = o->kpta + o->kpfile.patch->user_undo;
645659

646660
for (i = 0; i < o->ninfo; i++) {
@@ -728,7 +742,7 @@ int process_unpatch(int pid, void *_data)
728742

729743
ret = kpatch_process_init(proc, pid, /* start */ 0, /* send_fd */ -1);
730744
if (ret < 0)
731-
return -1;
745+
return ret;
732746

733747
kpatch_process_print_short(proc);
734748

@@ -749,13 +763,17 @@ int process_unpatch(int pid, void *_data)
749763
out:
750764
kpatch_process_free(proc);
751765

752-
if (ret < 0)
753-
printf("Failed to cancel patches for %d\n", pid);
754-
else if (ret == 0)
755-
printf("No patch(es) cancellable from PID '%d' were found\n", pid);
756-
else
757-
printf("%d patch hunk(s) were successfully cancelled from PID '%d'\n", ret, pid);
758-
759-
return ret;
766+
if (ret < 0) {
767+
kpinfo("Failed to cancel patches for %d\n", pid);
768+
if (ret == -1)
769+
return ERROR_UNPATCH_FAILURE;
770+
return ret;
771+
} else if (ret == 0) {
772+
kpinfo("No patch(es) cancellable from PID '%d' were found\n", pid);
773+
return ERROR_PATCH_NOT_FOUND;
774+
} else {
775+
kpinfo("%d patch hunk(s) were successfully cancelled from PID '%d'\n", ret, pid);
776+
return 0;
777+
}
760778
}
761779

src/kpatch_process.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ kpatch_process_mem_open(kpatch_process_t *proc, int mode)
630630
proc->memfd = open(path, mode == MEM_WRITE ? O_RDWR : O_RDONLY);
631631
if (proc->memfd < 0) {
632632
kplogerror("can't open /proc/%d/mem", proc->pid);
633-
return -1;
633+
return ERROR_PROCESS_NOT_FOUND;
634634
}
635635

636636
return 0;
@@ -643,7 +643,7 @@ kpatch_process_attach(kpatch_process_t *proc)
643643
size_t i, npids = 0, alloc = 0, prevnpids = 0, nattempts;
644644

645645
if (kpatch_process_mem_open(proc, MEM_WRITE) < 0)
646-
return -1;
646+
return ERROR_RESOURCE_ACCESS;
647647

648648
for (nattempts = 0; nattempts < max_attach_attempts; nattempts++) {
649649
ret = process_list_threads(proc, &pids, &npids, &alloc);
@@ -713,7 +713,7 @@ kpatch_process_attach(kpatch_process_t *proc)
713713
process_detach(proc);
714714
dealloc:
715715
free(pids);
716-
return -1;
716+
return ERROR_RESOURCE_ACCESS;
717717
}
718718

719719
static void
@@ -890,7 +890,7 @@ kpatch_process_load_libraries(kpatch_process_t *proc)
890890
ret = kpatch_process_attach(proc);
891891
if (ret < 0) {
892892
kperr("unable to attach to just started process\n");
893-
return -1;
893+
return ret;
894894
}
895895

896896
if (proc->send_fd != -1) {
@@ -1131,7 +1131,7 @@ kpatch_process_init(kpatch_process_t *proc,
11311131
out_unlock:
11321132
unlock_process(pid, fdmaps);
11331133
out_err:
1134-
return -1;
1134+
return ERROR_PROCESS_NOT_FOUND;
11351135
}
11361136

11371137
void

src/kpatch_user.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static char storage_dir[PATH_MAX] = "/var/lib/libcare";
3434
* Utilities.
3535
****************************************************************************/
3636

37-
/* Return -1 to indicate error, -2 to stop immediately */
37+
/* Return -1 to indicate error */
3838
typedef int (callback_t)(int pid, void *data);
3939

4040
static int
@@ -68,7 +68,7 @@ static int usage_patch(const char *err)
6868
fprintf(stderr, "\nOptions:\n");
6969
fprintf(stderr, " -h - this message\n");
7070
fprintf(stderr, " -p <PID> - target process\n");
71-
return err ? 0 : -1;
71+
return err ? 0 : ERROR_ARGUMENTS;
7272
}
7373

7474
static int
@@ -80,7 +80,7 @@ patch_user(const char *storage_path, int pid,
8080

8181
ret = storage_init(&storage, storage_path);
8282
if (ret < 0)
83-
return ret;
83+
return ERROR_PATCH_NOT_FOUND;
8484

8585
ret = processes_patch(&storage, pid, is_just_started, send_fd);
8686

@@ -337,7 +337,7 @@ process_info(int pid, void *_data)
337337

338338
ret = kpatch_process_init(proc, pid, /* start */ 0, /* send_fd */ -1);
339339
if (ret < 0)
340-
return -1;
340+
return ret;
341341

342342
ret = kpatch_process_mem_open(proc, MEM_READ);
343343
if (ret < 0)
@@ -631,6 +631,7 @@ static int cmd_stress_test(int fd, int argc, char *argv[])
631631
{
632632
int child = fork();
633633
if (child == 0) {
634+
signal(SIGCHLD, SIG_DFL);
634635
int rv = server_stress_test(fd, argc, argv);
635636
exit(rv);
636637
}
@@ -640,8 +641,12 @@ static int cmd_stress_test(int fd, int argc, char *argv[])
640641

641642
static int usage_stresstest()
642643
{
643-
fprintf(stderr, "usage: libcare-stresstest PERIOD(ms, 0 - only patch) <UNIX socket> [STORAGE ROOT]\n");
644-
return -1;
644+
fprintf(stderr, "usage: libcare-stresstest [args] PERIOD(ms, 0 - only patch) <UNIX socket> [STORAGE ROOT]\n");
645+
fprintf(stderr, "\nOptions:\n");
646+
fprintf(stderr, " -v - verbose mode\n");
647+
fprintf(stderr, " -l <BASE> - log file name <BASE>-PID\n");
648+
fprintf(stderr, " -h - this message\n");
649+
return ERROR_ARGUMENTS;
645650
}
646651

647652
#endif
@@ -745,7 +750,7 @@ static int usage_server(const char *err)
745750
if (err)
746751
fprintf(stderr, "err: %s\n", err);
747752
fprintf(stderr, "usage: libcare-ctl server <UNIX socket> [STORAGE ROOT]\n");
748-
return -1;
753+
return ERROR_ARGUMENTS;
749754
}
750755

751756
#define LISTEN_BACKLOG 1
@@ -904,9 +909,7 @@ processes_do(int pid, callback_t callback, void *data)
904909

905910
rv = callback(pid, data);
906911
if (rv < 0)
907-
ret = -1;
908-
if (rv == -2)
909-
break;
912+
ret = rv;
910913
}
911914

912915
closedir(dir);
@@ -930,7 +933,7 @@ static int usage(const char *err)
930933
fprintf(stderr, " unpatch- unapply patch from a user-space process\n");
931934
fprintf(stderr, " info - show info on applied patches\n");
932935
fprintf(stderr, " server - listen on a unix socket for commands\n");
933-
return -1;
936+
return ERROR_ARGUMENTS;
934937
}
935938

936939
static int
@@ -960,7 +963,7 @@ int main(int argc, char *argv[])
960963
log_level += 1;
961964
break;
962965
case 'h':
963-
return usage(NULL);
966+
return usage(0);
964967
default:
965968
return usage("unknown option");
966969
}

0 commit comments

Comments
 (0)