File: setsockopt.c

package info (click to toggle)
trinity 1.3-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 3,252 kB
  • ctags: 2,738
  • sloc: ansic: 24,011; sh: 322; makefile: 141
file content (150 lines) | stat: -rw-r--r-- 3,762 bytes parent folder | download
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, char __user *, optval, int, optlen)
 */

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/types.h>
#include "sanitise.h"
#include "compat.h"
#include "maps.h"
#include "log.h"
#include "shm.h"
#include "net.h"
#include "config.h"
#include "random.h"
#include "utils.h"

struct sso_funcptr {
	void (*func)(struct sockopt *so);
};

static const struct sso_funcptr ssoptrs[] = {
	{ .func = &ip_setsockopt },
	{ .func = &socket_setsockopt },
	{ .func = &tcp_setsockopt },
	{ .func = &udp_setsockopt },
	{ .func = &inet6_setsockopt },
	{ .func = &icmpv6_setsockopt },
	{ .func = &sctp_setsockopt },
	{ .func = &udplite_setsockopt },
	{ .func = &raw_setsockopt },
	{ .func = &ipx_setsockopt },
	{ .func = &ax25_setsockopt },
	{ .func = &atalk_setsockopt },
	{ .func = &netrom_setsockopt },
	{ .func = &rose_setsockopt },
	{ .func = &decnet_setsockopt },
	{ .func = &x25_setsockopt },
	{ .func = &packet_setsockopt },
	{ .func = &atm_setsockopt },
	{ .func = &aal_setsockopt },
	{ .func = &irda_setsockopt },
	{ .func = &netbeui_setsockopt },
	{ .func = &llc_setsockopt },
	{ .func = &dccp_setsockopt },
	{ .func = &netlink_setsockopt },
	{ .func = &tipc_setsockopt },
	{ .func = &rxrpc_setsockopt },
	{ .func = &pppol2tp_setsockopt },
	{ .func = &bluetooth_setsockopt },
	{ .func = &pnpipe_setsockopt },
	{ .func = &rds_setsockopt },
	{ .func = &iucv_setsockopt },
	{ .func = &caif_setsockopt },
	{ .func = &alg_setsockopt },
	{ .func = &nfc_setsockopt },
};

/*
 * Call a proto specific setsockopt routine from the table above.
 */
static void do_setsockopt(struct sockopt *so)
{
	so->optval = (unsigned long) page_rand;
	// pick a size for optlen. At the minimum, we want an int (overridden below)
	if (rand_bool())
		so->optlen = sizeof(int);
	else
		so->optlen = rand() % 256;

	if (rand() % 100 > 0) {
		ssoptrs[rand() % ARRAY_SIZE(ssoptrs)].func(so);
	} else {
		so->level = rand();
		so->optname = (rand() % 0x100);	/* random operation. */
	}

	/*
	 * 10% of the time, mangle the options.
	 * This should catch new options we don't know about, and also maybe some missing bounds checks.
	 */
	if ((rand() % 100) < 10)
		so->optname |= (1 << (rand() % 32));

	/* optval should be nonzero to enable a boolean option, or zero if the option is to be disabled.
	 * Let's disable it half the time.
	 */
	if (rand_bool())
		so->optval = 0;
}

/*
 * This is called during socket creation at startup, on each socket,
 * and also periodically from regenerate()
 */
void sso_socket(struct socket_triplet *triplet, struct sockopt *so, int fd)
{
	int ret;
	unsigned int tries = 0;

	/* skip over bluetooth due to weird linger bug */
	if (triplet->family == PF_BLUETOOTH)
		return;

retry:
	do_setsockopt(so);

	ret = setsockopt(fd, so->level, so->optname, (void *)so->optval, so->optlen);
	if (ret == 0) {
		output(1, "Setsockopt(%lx %lx %lx %lx) on fd %d [%d:%d:%d]\n",
			so->level, so->optname, so->optval, so->optlen, fd,
			triplet->family, triplet->type, triplet->protocol);
	} else {
		tries++;
		if (tries == 100) {
			return;
		}
		goto retry;
	}
}

static void sanitise_setsockopt(int childno)
{
	struct sockopt so = { 0, 0, 0, 0 };

	do_setsockopt(&so);

	/* copy the generated values to the shm. */
	shm->a2[childno] = so.level;
	shm->a3[childno] = so.optname;
	shm->a4[childno] = so.optval;
	shm->a5[childno] = so.optlen;
}

struct syscall syscall_setsockopt = {
	.name = "setsockopt",
	.num_args = 5,
	.arg1name = "fd",
	.arg1type = ARG_FD,
	.arg2name = "level",
	.arg3name = "optname",
	.arg4name = "optval",
	.arg4type = ARG_ADDRESS,
	.arg5name = "optlen",
	.sanitise = sanitise_setsockopt,
	.flags = NEED_ALARM,
};