mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
cf9b1199de
This example shows using a kprobe to act as a dnat mechanism to divert traffic for arbitrary endpoints. It rewrite the arguments to a syscall while they're still in userspace, and before the syscall has a chance to copy the argument into kernel space. Although this is an example, it also acts as a test because the mapped address is 255.255.255.255:555 -> real address, and that's not a legal address to connect to. If the helper is broken, the example will fail on the intermediate steps, as well as the final step to verify the rewrite of userspace memory succeeded. Signed-off-by: Sargun Dhillon <sargun@sargun.me> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
52 lines
1.6 KiB
C
52 lines
1.6 KiB
C
/* Copyright (c) 2016 Sargun Dhillon <sargun@sargun.me>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General Public
|
|
* License as published by the Free Software Foundation.
|
|
*/
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netdevice.h>
|
|
#include <uapi/linux/bpf.h>
|
|
#include <linux/version.h>
|
|
#include "bpf_helpers.h"
|
|
|
|
struct bpf_map_def SEC("maps") dnat_map = {
|
|
.type = BPF_MAP_TYPE_HASH,
|
|
.key_size = sizeof(struct sockaddr_in),
|
|
.value_size = sizeof(struct sockaddr_in),
|
|
.max_entries = 256,
|
|
};
|
|
|
|
/* kprobe is NOT a stable ABI
|
|
* kernel functions can be removed, renamed or completely change semantics.
|
|
* Number of arguments and their positions can change, etc.
|
|
* In such case this bpf+kprobe example will no longer be meaningful
|
|
*
|
|
* This example sits on a syscall, and the syscall ABI is relatively stable
|
|
* of course, across platforms, and over time, the ABI may change.
|
|
*/
|
|
SEC("kprobe/sys_connect")
|
|
int bpf_prog1(struct pt_regs *ctx)
|
|
{
|
|
struct sockaddr_in new_addr, orig_addr = {};
|
|
struct sockaddr_in *mapped_addr;
|
|
void *sockaddr_arg = (void *)PT_REGS_PARM2(ctx);
|
|
int sockaddr_len = (int)PT_REGS_PARM3(ctx);
|
|
|
|
if (sockaddr_len > sizeof(orig_addr))
|
|
return 0;
|
|
|
|
if (bpf_probe_read(&orig_addr, sizeof(orig_addr), sockaddr_arg) != 0)
|
|
return 0;
|
|
|
|
mapped_addr = bpf_map_lookup_elem(&dnat_map, &orig_addr);
|
|
if (mapped_addr != NULL) {
|
|
memcpy(&new_addr, mapped_addr, sizeof(new_addr));
|
|
bpf_probe_write_user(sockaddr_arg, &new_addr,
|
|
sizeof(new_addr));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char _license[] SEC("license") = "GPL";
|
|
u32 _version SEC("version") = LINUX_VERSION_CODE;
|