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,
};
|