forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sargun Dhillon says: ==================== bpf: add bpf_probe_write_user helper & example This patch series contains two patches that add support for a probe_write helper to BPF programs. This allows them to manipulate user memory during the course of tracing. The second patch in the series has an example that uses it, in one the intended ways to divert execution. Thanks to Alexei Starovoitov, and Daniel Borkmann for being patient, review, and helping me get familiar with the code base. I've made changes based on their recommendations. This helper should be considered for experimental usage and debugging, so we print a warning to dmesg when it is along with the command and pid when someone tries to install a proglet that uses it. A follow-up patchset will contain a mechanism to verify the safety of the probe beyond what was done by hand. ---- v1->v2: restrict writing to user space, as opposed to globally v2->v3: Fixed formatting issues v3->v4: Rename copy_to_user -> bpf_probe_write Simplify checking of whether or not it's safe to write Add warnings to dmesg v4->v5: Raise warning level Cleanup location of warning code Make test fail when helper is broken v5->v6: General formatting cleanup Rename bpf_probe_write -> bpf_probe_write_user v6->v7: More formatting cleanup. Clarifying a few comments Clarified log message ==================== Signed-off-by: David S. Miller <[email protected]>
- Loading branch information
Showing
6 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* Copyright (c) 2016 Sargun Dhillon <[email protected]> | ||
* | ||
* 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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#include <stdio.h> | ||
#include <assert.h> | ||
#include <linux/bpf.h> | ||
#include <unistd.h> | ||
#include "libbpf.h" | ||
#include "bpf_load.h" | ||
#include <sys/socket.h> | ||
#include <string.h> | ||
#include <netinet/in.h> | ||
#include <arpa/inet.h> | ||
|
||
int main(int ac, char **argv) | ||
{ | ||
int serverfd, serverconnfd, clientfd; | ||
socklen_t sockaddr_len; | ||
struct sockaddr serv_addr, mapped_addr, tmp_addr; | ||
struct sockaddr_in *serv_addr_in, *mapped_addr_in, *tmp_addr_in; | ||
char filename[256]; | ||
char *ip; | ||
|
||
serv_addr_in = (struct sockaddr_in *)&serv_addr; | ||
mapped_addr_in = (struct sockaddr_in *)&mapped_addr; | ||
tmp_addr_in = (struct sockaddr_in *)&tmp_addr; | ||
|
||
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); | ||
|
||
if (load_bpf_file(filename)) { | ||
printf("%s", bpf_log_buf); | ||
return 1; | ||
} | ||
|
||
assert((serverfd = socket(AF_INET, SOCK_STREAM, 0)) > 0); | ||
assert((clientfd = socket(AF_INET, SOCK_STREAM, 0)) > 0); | ||
|
||
/* Bind server to ephemeral port on lo */ | ||
memset(&serv_addr, 0, sizeof(serv_addr)); | ||
serv_addr_in->sin_family = AF_INET; | ||
serv_addr_in->sin_port = 0; | ||
serv_addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); | ||
|
||
assert(bind(serverfd, &serv_addr, sizeof(serv_addr)) == 0); | ||
|
||
sockaddr_len = sizeof(serv_addr); | ||
assert(getsockname(serverfd, &serv_addr, &sockaddr_len) == 0); | ||
ip = inet_ntoa(serv_addr_in->sin_addr); | ||
printf("Server bound to: %s:%d\n", ip, ntohs(serv_addr_in->sin_port)); | ||
|
||
memset(&mapped_addr, 0, sizeof(mapped_addr)); | ||
mapped_addr_in->sin_family = AF_INET; | ||
mapped_addr_in->sin_port = htons(5555); | ||
mapped_addr_in->sin_addr.s_addr = inet_addr("255.255.255.255"); | ||
|
||
assert(!bpf_update_elem(map_fd[0], &mapped_addr, &serv_addr, BPF_ANY)); | ||
|
||
assert(listen(serverfd, 5) == 0); | ||
|
||
ip = inet_ntoa(mapped_addr_in->sin_addr); | ||
printf("Client connecting to: %s:%d\n", | ||
ip, ntohs(mapped_addr_in->sin_port)); | ||
assert(connect(clientfd, &mapped_addr, sizeof(mapped_addr)) == 0); | ||
|
||
sockaddr_len = sizeof(tmp_addr); | ||
ip = inet_ntoa(tmp_addr_in->sin_addr); | ||
assert((serverconnfd = accept(serverfd, &tmp_addr, &sockaddr_len)) > 0); | ||
printf("Server received connection from: %s:%d\n", | ||
ip, ntohs(tmp_addr_in->sin_port)); | ||
|
||
sockaddr_len = sizeof(tmp_addr); | ||
assert(getpeername(clientfd, &tmp_addr, &sockaddr_len) == 0); | ||
ip = inet_ntoa(tmp_addr_in->sin_addr); | ||
printf("Client's peer address: %s:%d\n", | ||
ip, ntohs(tmp_addr_in->sin_port)); | ||
|
||
/* Is the server's getsockname = the socket getpeername */ | ||
assert(memcmp(&serv_addr, &tmp_addr, sizeof(struct sockaddr_in)) == 0); | ||
|
||
return 0; | ||
} |