Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit f76ef06

Browse files
committed
Better detection of error codes in syscall return values
It was problematic before, especially e.g. the case in xmmap_anon: the function checked for MMAP_FAILED, but that is only correct while using the libc mmap interface. The raw syscall on Linux can return one of several negative integers to indicate errors.
1 parent d38dbc7 commit f76ef06

File tree

8 files changed

+139
-45
lines changed

8 files changed

+139
-45
lines changed

doc/generated/libsyscall_intercept.3

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,32 @@ after a clone syscall creating a thread returns in a child thread:
9898
.IP
9999
.nf
100100
\f[C]
101-
long\ (*intercept_hook_point_clone_child)(void);
101+
void\ (*intercept_hook_point_clone_child)(void);
102102
\f[]
103103
.fi
104104
.PP
105105
Using \f[C]intercept_hook_point_clone_child\f[], one can be notified of
106-
thread creations easily, and even override the syscall\[aq]s return
107-
value in the child thread (which is normally zero).
108-
Note: overriding the zero return value is discouraged \-\- this syscall
109-
is usually issued by libc, and a non\-zero return value is interpreted
110-
as the execution remaining in the parent thread, thus using attempting
111-
to use the same stack space as the actual parent thread.
106+
thread creations.
107+
.PP
108+
To make it easy to detect syscall return values indicating errors, one
109+
can use the syscall_error_code function:
110+
.IP
111+
.nf
112+
\f[C]
113+
int\ syscall_error_code(long\ result);
114+
\f[]
115+
.fi
116+
.PP
117+
When passed a return value from syscall_no_intercept, this function can
118+
translate it to an error code equivalent to a libc error code:
119+
.IP
120+
.nf
121+
\f[C]
122+
int\ fd\ =\ (int)syscall_no_intercept(SYS_open,\ "file",\ O_RDWR);
123+
if\ (syscall_error_code(fd)\ !=\ 0)
124+
\ \ \ \ fprintf(stderr,\ strerror(syscall_error_code(fd)));
125+
\f[]
126+
.fi
112127
.SH ENVIRONMENT VARIABLES
113128
.PP
114129
Three environment variables control the operation of the library:

doc/libsyscall_intercept.3.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,19 @@ void (*intercept_hook_point_clone_child)(void);
101101
Using `intercept_hook_point_clone_child`, one can be notified of thread
102102
creations.
103103

104+
To make it easy to detect syscall return values indicating errors, one
105+
can use the syscall_error_code function:
106+
```c
107+
int syscall_error_code(long result);
108+
```
109+
When passed a return value from syscall_no_intercept, this function
110+
can translate it to an error code equivalent to a libc error code:
111+
```c
112+
int fd = (int)syscall_no_intercept(SYS_open, "file", O_RDWR);
113+
if (syscall_error_code(fd) != 0)
114+
fprintf(stderr, strerror(syscall_error_code(fd)));
115+
```
116+
104117
# ENVIRONMENT VARIABLES #
105118
Three environment variables control the operation of the library:
106119

include/libsyscall_intercept_hook_point.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ extern void (*intercept_hook_point_clone_child)(void);
6969
*/
7070
long syscall_no_intercept(long syscall_number, ...);
7171

72+
/*
73+
* syscall_error_code - examines a return value from
74+
* syscall_no_intercept, and returns an error code if said
75+
* return value indicates an error.
76+
*/
77+
static inline int
78+
syscall_error_code(long result)
79+
{
80+
if (result < 0 && result >= -0x1000)
81+
return (int)-result;
82+
83+
return 0;
84+
}
85+
7286
/*
7387
* The syscall intercepting library checks for the
7488
* INTERCEPT_HOOK_CMDLINE_FILTER environment variable, with which one can

src/intercept.c

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -448,21 +448,65 @@ log_header(void)
448448
}
449449

450450
/*
451-
* xabort - speaks for itself
451+
* xabort_errno - print a message to stderr, and exit the process.
452452
* Calling abort() in libc might result other syscalls being called
453453
* by libc.
454+
*
455+
* If error_code is not zero, it is also printed.
454456
*/
455457
void
456-
xabort(const char *msg)
458+
xabort_errno(int error_code, const char *msg)
457459
{
458460
static const char main_msg[] = " libsyscall_intercept error\n";
459461

460-
if (msg != NULL)
461-
syscall_no_intercept(SYS_write, 2, msg, strlen(msg));
462-
syscall_no_intercept(SYS_write, 2, main_msg, sizeof(main_msg));
462+
if (msg != NULL) {
463+
/* not using libc - inline strlen */
464+
size_t len = 0;
465+
while (msg[len] != '\0')
466+
++len;
467+
syscall_no_intercept(SYS_write, 2, msg, len);
468+
}
469+
470+
if (error_code != 0) {
471+
char buf[0x10];
472+
size_t len = 1;
473+
char *c = buf + sizeof(buf) - 1;
474+
475+
/* not using libc - inline sprintf */
476+
do {
477+
*c-- = error_code % 10;
478+
++len;
479+
error_code /= 10;
480+
} while (error_code != 0);
481+
*c = ' ';
482+
483+
syscall_no_intercept(SYS_write, 2, c, len);
484+
}
485+
486+
syscall_no_intercept(SYS_write, 2, main_msg, sizeof(main_msg) - 1);
463487
syscall_no_intercept(SYS_exit_group, 1);
464488

465-
__builtin_trap();
489+
__builtin_unreachable();
490+
}
491+
492+
/*
493+
* xabort - print a message to stderr, and exit the process.
494+
*/
495+
void
496+
xabort(const char *msg)
497+
{
498+
xabort_errno(0, msg);
499+
}
500+
501+
/*
502+
* xabort_on_syserror -- examines the return value of syscall_no_intercept,
503+
* and calls xabort_errno if the said return value indicates an error.
504+
*/
505+
void
506+
xabort_on_syserror(long syscall_result, const char *msg)
507+
{
508+
if (syscall_error_code(syscall_result) != 0)
509+
xabort_errno(syscall_error_code(syscall_result), msg);
466510
}
467511

468512
/*

src/intercept.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ void intercept_patch_with_postfix(unsigned char *syscall_addr,
6262

6363
#define INTERCEPTOR_EXIT_CODE 111
6464

65-
__attribute__((noreturn)) void xabort(const char *);
65+
__attribute__((noreturn)) void xabort_errno(int error_code, const char *msg);
66+
67+
__attribute__((noreturn)) void xabort(const char *msg);
68+
69+
void xabort_on_syserror(long syscall_result, const char *msg);
6670

6771
struct range {
6872
unsigned char *address;

src/intercept_desc.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,7 @@ open_orig_file(const struct intercept_desc *desc)
6464

6565
fd = syscall_no_intercept(SYS_open, desc->path, O_RDONLY);
6666

67-
if (fd < 0) {
68-
syscall_no_intercept(SYS_write, 2,
69-
desc->path, strlen(desc->path));
70-
xabort(" open_orig_file");
71-
}
67+
xabort_on_syserror(fd, __func__);
7268

7369
return fd;
7470
}

src/intercept_util.c

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "intercept_util.h"
3434
#include "intercept.h"
35+
#include "libsyscall_intercept_hook_point.h"
3536

3637
#include <assert.h>
3738
#include <inttypes.h>
@@ -53,53 +54,52 @@ static int log_fd = -1;
5354
void *
5455
xmmap_anon(size_t size)
5556
{
56-
void *addr = (void *) syscall_no_intercept(SYS_mmap,
57+
long addr = syscall_no_intercept(SYS_mmap,
5758
NULL, size,
5859
PROT_READ | PROT_WRITE,
5960
MAP_PRIVATE | MAP_ANON, -1, (off_t)0);
6061

61-
if (addr == MAP_FAILED)
62-
xabort("xmmap_anon");
62+
xabort_on_syserror(addr, __func__);
6363

64-
return addr;
64+
return (void *) addr;
6565
}
6666

6767
void *
6868
xmremap(void *addr, size_t old, size_t new)
6969
{
70-
addr = (void *) syscall_no_intercept(SYS_mremap, addr,
70+
long new_addr = syscall_no_intercept(SYS_mremap, addr,
7171
old, new, MREMAP_MAYMOVE);
7272

73-
if (addr == MAP_FAILED)
74-
xabort("xmremap");
73+
xabort_on_syserror(new_addr, __func__);
7574

76-
return addr;
75+
return (void *) new_addr;
7776
}
7877

7978
void
8079
xmunmap(void *addr, size_t len)
8180
{
82-
if (syscall_no_intercept(SYS_munmap, addr, len) != 0)
83-
xabort("xmunmap");
81+
long result = syscall_no_intercept(SYS_munmap, addr, len);
82+
83+
xabort_on_syserror(result, __func__);
8484
}
8585

8686
long
8787
xlseek(long fd, unsigned long off, int whence)
8888
{
8989
long result = syscall_no_intercept(SYS_lseek, fd, off, whence);
9090

91-
if (result < 0)
92-
xabort("xlseek");
91+
xabort_on_syserror(result, __func__);
9392

9493
return result;
9594
}
9695

9796
void
9897
xread(long fd, void *buffer, size_t size)
9998
{
100-
if (syscall_no_intercept(SYS_read, fd,
101-
buffer, size) != (ssize_t)size)
102-
xabort("xread");
99+
long result = syscall_no_intercept(SYS_read, fd, buffer, size);
100+
101+
if (result != (long)size)
102+
xabort_errno(syscall_error_code(result), __func__);
103103
}
104104

105105
/*
@@ -132,8 +132,7 @@ intercept_setup_log(const char *path_base, const char *trunc)
132132

133133
log_fd = (int)syscall_no_intercept(SYS_open, path, flags, (mode_t)0700);
134134

135-
if (log_fd < 0)
136-
xabort("setup_log");
135+
xabort_on_syserror(log_fd, "opening log");
137136
}
138137

139138
/*

src/patcher.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,15 @@ after_nop(const struct range *nop)
808808
return nop->address + nop->size;
809809
}
810810

811+
static void
812+
mprotect_no_intercept(void *addr, size_t len, int prot,
813+
const char *msg_on_error)
814+
{
815+
long result = syscall_no_intercept(SYS_mprotect, addr, len, prot);
816+
817+
xabort_on_syserror(result, msg_on_error);
818+
}
819+
811820
/*
812821
* activate_patches()
813822
* Loop over all the patches, and and overwrite each syscall.
@@ -824,9 +833,9 @@ activate_patches(struct intercept_desc *desc)
824833
first_page = round_down_address(desc->text_start);
825834
size = (size_t)(desc->text_end - first_page);
826835

827-
if (syscall_no_intercept(SYS_mprotect, first_page, size,
828-
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
829-
xabort("mprotect PROT_READ | PROT_WRITE | PROT_EXEC");
836+
mprotect_no_intercept(first_page, size,
837+
PROT_READ | PROT_WRITE | PROT_EXEC,
838+
"mprotect PROT_READ | PROT_WRITE | PROT_EXEC");
830839

831840
for (unsigned i = 0; i < desc->count; ++i) {
832841
const struct patch_desc *patch = desc->items + i;
@@ -902,9 +911,9 @@ activate_patches(struct intercept_desc *desc)
902911
}
903912
}
904913

905-
if (syscall_no_intercept(SYS_mprotect, first_page, size,
906-
PROT_READ | PROT_EXEC) != 0)
907-
xabort("mprotect PROT_READ | PROT_EXEC");
914+
mprotect_no_intercept(first_page, size,
915+
PROT_READ | PROT_EXEC,
916+
"mprotect PROT_READ | PROT_EXEC");
908917
}
909918

910919
/*
@@ -941,9 +950,9 @@ next_asm_wrapper_space(void)
941950
void
942951
mprotect_asm_wrappers(void)
943952
{
944-
if (syscall_no_intercept(SYS_mprotect,
953+
mprotect_no_intercept(
945954
round_down_address(asm_wrapper_space + PAGE_SIZE),
946955
sizeof(asm_wrapper_space) - PAGE_SIZE,
947-
PROT_READ | PROT_EXEC) != 0)
948-
xabort("mprotect_asm_wrappers PROT_READ | PROT_EXEC");
956+
PROT_READ | PROT_EXEC,
957+
"mprotect_asm_wrappers PROT_READ | PROT_EXEC");
949958
}

0 commit comments

Comments
 (0)