Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
sudo: required
language: bash
dist: bionic
services:
- docker

env:
global:
- PROJECT_NAME='libbpf'
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
- REPO_ROOT="$TRAVIS_BUILD_DIR"
- CI_ROOT="$REPO_ROOT/travis-ci"
- VMTEST_ROOT="$CI_ROOT/vmtest"

addons:
apt:
packages:
- qemu-kvm
- zstd
- binutils-dev
- elfutils
- libcap-dev
- libelf-dev
- libdw-dev
- python3-docutils

jobs:
include:
- stage: Builds & Tests
name: Kernel LATEST + selftests
language: bash
env: KERNEL=LATEST
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
16 changes: 16 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -3787,6 +3787,16 @@ union bpf_attr {
* *ARG_PTR_TO_BTF_ID* of type *task_struct*.
* Return
* Pointer to the current task.
*
* long bpf_bprm_opts_set(struct linux_binprm *bprm, u64 flags)
* Description
* Set or clear certain options on *bprm*:
*
* **BPF_F_BPRM_SECUREEXEC** Set the secureexec bit
* which sets the **AT_SECURE** auxv for glibc. The bit
* is cleared if the flag is not specified.
* Return
* **-EINVAL** if invalid *flags* are passed, zero otherwise.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
Expand Down Expand Up @@ -3948,6 +3958,7 @@ union bpf_attr {
FN(task_storage_get), \
FN(task_storage_delete), \
FN(get_current_task_btf), \
FN(bprm_opts_set), \
/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
Expand Down Expand Up @@ -4119,6 +4130,11 @@ enum bpf_lwt_encap_mode {
BPF_LWT_ENCAP_IP,
};

/* Flags for bpf_bprm_opts_set helper */
enum {
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
};

#define __bpf_md_ptr(type, name) \
union { \
type name; \
Expand Down
26 changes: 26 additions & 0 deletions kernel/bpf/bpf_lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/filter.h>
#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/binfmts.h>
#include <linux/lsm_hooks.h>
#include <linux/bpf_lsm.h>
#include <linux/kallsyms.h>
Expand Down Expand Up @@ -51,6 +52,29 @@ int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
return 0;
}

/* Mask for all the currently supported BPRM option flags */
#define BPF_F_BRPM_OPTS_MASK BPF_F_BPRM_SECUREEXEC

BPF_CALL_2(bpf_bprm_opts_set, struct linux_binprm *, bprm, u64, flags)
{
if (flags & ~BPF_F_BRPM_OPTS_MASK)
return -EINVAL;

bprm->secureexec = (flags & BPF_F_BPRM_SECUREEXEC);
return 0;
}

BTF_ID_LIST_SINGLE(bpf_bprm_opts_set_btf_ids, struct, linux_binprm)

const static struct bpf_func_proto bpf_bprm_opts_set_proto = {
.func = bpf_bprm_opts_set,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_bprm_opts_set_btf_ids[0],
.arg2_type = ARG_ANYTHING,
};

static const struct bpf_func_proto *
bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
Expand All @@ -71,6 +95,8 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_task_storage_get_proto;
case BPF_FUNC_task_storage_delete:
return &bpf_task_storage_delete_proto;
case BPF_FUNC_bprm_opts_set:
return &bpf_bprm_opts_set_proto;
default:
return tracing_prog_func_proto(func_id, prog);
}
Expand Down
2 changes: 2 additions & 0 deletions scripts/bpf_helpers_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ class PrinterHelpers(Printer):
'struct bpf_tcp_sock',
'struct bpf_tunnel_key',
'struct bpf_xfrm_state',
'struct linux_binprm',
'struct pt_regs',
'struct sk_reuseport_md',
'struct sockaddr',
Expand Down Expand Up @@ -465,6 +466,7 @@ class PrinterHelpers(Printer):
'struct bpf_tcp_sock',
'struct bpf_tunnel_key',
'struct bpf_xfrm_state',
'struct linux_binprm',
'struct pt_regs',
'struct sk_reuseport_md',
'struct sockaddr',
Expand Down
16 changes: 16 additions & 0 deletions tools/include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -3787,6 +3787,16 @@ union bpf_attr {
* *ARG_PTR_TO_BTF_ID* of type *task_struct*.
* Return
* Pointer to the current task.
*
* long bpf_bprm_opts_set(struct linux_binprm *bprm, u64 flags)
* Description
* Set or clear certain options on *bprm*:
*
* **BPF_F_BPRM_SECUREEXEC** Set the secureexec bit
* which sets the **AT_SECURE** auxv for glibc. The bit
* is cleared if the flag is not specified.
* Return
* **-EINVAL** if invalid *flags* are passed, zero otherwise.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
Expand Down Expand Up @@ -3948,6 +3958,7 @@ union bpf_attr {
FN(task_storage_get), \
FN(task_storage_delete), \
FN(get_current_task_btf), \
FN(bprm_opts_set), \
/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
Expand Down Expand Up @@ -4119,6 +4130,11 @@ enum bpf_lwt_encap_mode {
BPF_LWT_ENCAP_IP,
};

/* Flags for bpf_bprm_opts_set helper */
enum {
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
};

#define __bpf_md_ptr(type, name) \
union { \
type name; \
Expand Down
116 changes: 116 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/test_bprm_opts.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// SPDX-License-Identifier: GPL-2.0

/*
* Copyright (C) 2020 Google LLC.
*/

#include <test_progs.h>
#include <linux/limits.h>

#include "bprm_opts.skel.h"
#include "network_helpers.h"

#ifndef __NR_pidfd_open
#define __NR_pidfd_open 434
#endif

static const char * const bash_envp[] = { "TMPDIR=shouldnotbeset", NULL };

static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
{
return syscall(__NR_pidfd_open, pid, flags);
}

static int update_storage(int map_fd, int secureexec)
{
int task_fd, ret = 0;

task_fd = sys_pidfd_open(getpid(), 0);
if (task_fd < 0)
return errno;

ret = bpf_map_update_elem(map_fd, &task_fd, &secureexec, BPF_NOEXIST);
if (ret)
ret = errno;

close(task_fd);
return ret;
}

static int run_set_secureexec(int map_fd, int secureexec)
{
int child_pid, child_status, ret, null_fd;

child_pid = fork();
if (child_pid == 0) {
null_fd = open("/dev/null", O_WRONLY);
if (null_fd == -1)
exit(errno);
dup2(null_fd, STDOUT_FILENO);
dup2(null_fd, STDERR_FILENO);
close(null_fd);

/* Ensure that all executions from hereon are
* secure by setting a local storage which is read by
* the bprm_creds_for_exec hook and sets bprm->secureexec.
*/
ret = update_storage(map_fd, secureexec);
if (ret)
exit(ret);

/* If the binary is executed with securexec=1, the dynamic
* loader ingores and unsets certain variables like LD_PRELOAD,
* TMPDIR etc. TMPDIR is used here to simplify the example, as
* LD_PRELOAD requires a real .so file.
*
* If the value of TMPDIR is set, the bash command returns 10
* and if the value is unset, it returns 20.
*/
execle("/bin/bash", "bash", "-c",
"[[ -z \"${TMPDIR}\" ]] || exit 10 && exit 20", NULL,
bash_envp);
exit(errno);
} else if (child_pid > 0) {
waitpid(child_pid, &child_status, 0);
ret = WEXITSTATUS(child_status);

/* If a secureexec occurred, the exit status should be 20 */
if (secureexec && ret == 20)
return 0;

/* If normal execution happened, the exit code should be 10 */
if (!secureexec && ret == 10)
return 0;
}

return -EINVAL;
}

void test_test_bprm_opts(void)
{
int err, duration = 0;
struct bprm_opts *skel = NULL;

skel = bprm_opts__open_and_load();
if (CHECK(!skel, "skel_load", "skeleton failed\n"))
goto close_prog;

err = bprm_opts__attach(skel);
if (CHECK(err, "attach", "attach failed: %d\n", err))
goto close_prog;

/* Run the test with the secureexec bit unset */
err = run_set_secureexec(bpf_map__fd(skel->maps.secure_exec_task_map),
0 /* secureexec */);
if (CHECK(err, "run_set_secureexec:0", "err = %d\n", err))
goto close_prog;

/* Run the test with the secureexec bit set */
err = run_set_secureexec(bpf_map__fd(skel->maps.secure_exec_task_map),
1 /* secureexec */);
if (CHECK(err, "run_set_secureexec:1", "err = %d\n", err))
goto close_prog;

close_prog:
bprm_opts__destroy(skel);
}
34 changes: 34 additions & 0 deletions tools/testing/selftests/bpf/progs/bprm_opts.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0

/*
* Copyright 2020 Google LLC.
*/

#include "vmlinux.h"
#include <errno.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

char _license[] SEC("license") = "GPL";

struct {
__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, int);
__type(value, int);
} secure_exec_task_map SEC(".maps");

SEC("lsm/bprm_creds_for_exec")
int BPF_PROG(secure_exec, struct linux_binprm *bprm)
{
int *secureexec;

secureexec = bpf_task_storage_get(&secure_exec_task_map,
bpf_get_current_task_btf(), 0,
BPF_LOCAL_STORAGE_GET_F_CREATE);

if (secureexec && *secureexec)
bpf_bprm_opts_set(bprm, BPF_F_BPRM_SECUREEXEC);

return 0;
}
Loading