File: execve.c

package info (click to toggle)
trinity 1.9%2Bgit20200331.4d2343bd18c7b-2%2Bdeb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 3,080 kB
  • sloc: ansic: 32,746; sh: 536; makefile: 164
file content (132 lines) | stat: -rw-r--r-- 2,961 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * SYSCALL_DEFINE3(execve,
 *                const char __user *, filename,
 *                const char __user *const __user *, argv,
 *                const char __user *const __user *, envp)
 *
 * On success, execve() does not return
 * on error -1 is returned, and errno is set appropriately.
 *
 * TODO: Redirect stdin/stdout.
 */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "arch.h"	// page_size
#include "random.h"	// generate_rand_bytes
#include "sanitise.h"
#include "shm.h"
#include "syscall.h"
#include "tables.h"
#include "trinity.h"	// __unused__
#include "utils.h"
#include "compat.h"

static unsigned int argvcount;
static unsigned int envpcount;

static unsigned long ** gen_ptrs_to_crap(unsigned int count)
{
	void **ptr;
	unsigned int i;

	/* Fabricate argv */
	ptr = zmalloc(count * sizeof(void *));

	for (i = 0; i < count; i++) {
		ptr[i] = zmalloc(page_size);
		generate_rand_bytes((unsigned char *) ptr[i], rnd() % page_size);
	}

	return (unsigned long **) ptr;
}

static void sanitise_execve(struct syscallrecord *rec)
{
	unsigned long **argv, **envp;

	/* we don't want to block if something tries to read from stdin */
	fclose(stdin);

	/* Fabricate argv */
	argvcount = rnd() % 32;
	argv = gen_ptrs_to_crap(argvcount);

	/* Fabricate envp */
	envpcount = rnd() % 32;
	envp = gen_ptrs_to_crap(envpcount);

	if (this_syscallname("execve") == FALSE) {
		rec->a2 = (unsigned long) argv;
		rec->a3 = (unsigned long) envp;
	} else {
		rec->a3 = (unsigned long) argv;
		rec->a4 = (unsigned long) envp;
	}
}

/* if execve succeeds, we'll never get back here, so this only
 * has to worry about the case where execve returned a failure.
 */

static void free_execve_ptrs(void **argv, void **envp)
{
	unsigned int i;

	for (i = 0; i < argvcount; i++)
		free(argv[i]);
	free(argv);

	for (i = 0; i < envpcount; i++)
		free(envp[i]);
	free(envp);
}

static void post_execve(struct syscallrecord *rec)
{
	free_execve_ptrs((void **) rec->a2, (void **) rec->a3);
}

static void post_execveat(struct syscallrecord *rec)
{
	free_execve_ptrs((void **) rec->a3, (void **) rec->a4);
}

struct syscallentry syscall_execve = {
	.name = "execve",
	.num_args = 3,
	.arg1name = "name",
	.arg1type = ARG_PATHNAME,
	.arg2name = "argv",
	.arg2type = ARG_ADDRESS,
	.arg3name = "envp",
	.arg3type = ARG_ADDRESS,
	.sanitise = sanitise_execve,
	.post = post_execve,
	.group = GROUP_VFS,
	.flags = EXTRA_FORK,
};

static unsigned long execveat_flags[] = {
	AT_EMPTY_PATH, AT_SYMLINK_NOFOLLOW,
};

struct syscallentry syscall_execveat = {
	.name = "execveat",
	.num_args = 5,
	.arg1name = "fd",
	.arg1type = ARG_FD,
	.arg2name = "name",
	.arg2type = ARG_PATHNAME,
	.arg3name = "argv",
	.arg3type = ARG_ADDRESS,
	.arg4name = "envp",
	.arg4type = ARG_ADDRESS,
	.arg5name = "flags",
	.arg5type = ARG_LIST,
	.arg5list = ARGLIST(execveat_flags),
	.sanitise = sanitise_execve,
	.post = post_execveat,
	.group = GROUP_VFS,
	.flags = EXTRA_FORK,
};