← Documents Documentation/bpf/prog_lsm.rst GitHub 원문 ↗

Linux 6.18.37 · BPF

LSM BPF Programs

LSM 훅에 eBPF 프로그램을 연결해 시스템 전체 접근 제어와 감사 정책을 구현하는 방법, BTF 기반 형식 선언, 적재 및 연결 수명 주기를 설명합니다.

Source pathDocumentation/bpf/prog_lsm.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

prog_lsm.rst:1-143

LSM BPF 프로그램은 권한 있는 사용자가 `file_mprotect` 같은 LSM 훅에 런타임 정책을 연결하도록 합니다. 훅 체인의 앞선 반환값을 보존하면서 접근을 허용하거나 `-EPERM`으로 거부하고 감사 정보를 기록할 수 있습니다.

BTF와 `__attribute__((preserve_access_index))`를 사용하면 필요한 필드만 선언해도 verifier가 실제 커널 형식의 오프셋을 맞추고 접근을 검증합니다. `vmlinux.h`를 생성하면 형식 선언을 직접 유지하는 부담도 줄어듭니다.

프로그램은 `BPF_PROG_LOAD` 또는 libbpf 스켈레톤으로 적재하고 `bpf_program__attach_lsm`이나 생성된 스켈레톤 도우미로 연결합니다. 반환된 BPF 링크를 파괴하면 훅에서 안전하게 분리됩니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0+
2 .. Copyright (C) 2020 Google LLC.
3
4 ================
5 LSM BPF Programs
6 ================
7
8 These BPF programs allow runtime instrumentation of the LSM hooks by privileged
9 users to implement system-wide MAC (Mandatory Access Control) and Audit
10 policies using eBPF.
11
12 Structure
13 ---------
14
15 The example shows an eBPF program that can be attached to the ``file_mprotect``
16 LSM hook:
17
18 .. c:function:: int file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot);
19
20 Other LSM hooks which can be instrumented can be found in
21 ``security/security.c``.
22
23 eBPF programs that use Documentation/bpf/btf.rst do not need to include kernel
24 headers for accessing information from the attached eBPF program's context.
25 They can simply declare the structures in the eBPF program and only specify
26 the fields that need to be accessed.
27
28 .. code-block:: c
29
30 struct mm_struct {
31 unsigned long start_brk, brk, start_stack;
32 } __attribute__((preserve_access_index));
33
34 struct vm_area_struct {
35 unsigned long start_brk, brk, start_stack;
36 unsigned long vm_start, vm_end;
37 struct mm_struct *vm_mm;
38 } __attribute__((preserve_access_index));
39
40
41 .. note:: The order of the fields is irrelevant.
42
43 This can be further simplified (if one has access to the BTF information at
44 build time) by generating the ``vmlinux.h`` with:
45
46 .. code-block:: console
47
48 # bpftool btf dump file <path-to-btf-vmlinux> format c > vmlinux.h
49
50 .. note:: ``path-to-btf-vmlinux`` can be ``/sys/kernel/btf/vmlinux`` if the
51 build environment matches the environment the BPF programs are
52 deployed in.
53
54 The ``vmlinux.h`` can then simply be included in the BPF programs without
55 requiring the definition of the types.
56
57 The eBPF programs can be declared using the``BPF_PROG``
58 macros defined in `tools/lib/bpf/bpf_tracing.h`_. In this
59 example:
60
61 * ``"lsm/file_mprotect"`` indicates the LSM hook that the program must
62 be attached to
63 * ``mprotect_audit`` is the name of the eBPF program
64
65 .. code-block:: c
66
67 SEC("lsm/file_mprotect")
68 int BPF_PROG(mprotect_audit, struct vm_area_struct *vma,
69 unsigned long reqprot, unsigned long prot, int ret)
70 {
71 /* ret is the return value from the previous BPF program
72 * or 0 if it's the first hook.
73 */
74 if (ret != 0)
75 return ret;
76
77 int is_heap;
78
79 is_heap = (vma->vm_start >= vma->vm_mm->start_brk &&
80 vma->vm_end <= vma->vm_mm->brk);
81
82 /* Return an -EPERM or write information to the perf events buffer
83 * for auditing
84 */
85 if (is_heap)
86 return -EPERM;
87 }
88
89 The ``__attribute__((preserve_access_index))`` is a clang feature that allows
90 the BPF verifier to update the offsets for the access at runtime using the
91 Documentation/bpf/btf.rst information. Since the BPF verifier is aware of the
92 types, it also validates all the accesses made to the various types in the
93 eBPF program.
94
95 Loading
96 -------
97
98 eBPF programs can be loaded with the :manpage:`bpf(2)` syscall's
99 ``BPF_PROG_LOAD`` operation:
100
101 .. code-block:: c
102
103 struct bpf_object *obj;
104
105 obj = bpf_object__open("./my_prog.o");
106 bpf_object__load(obj);
107
108 This can be simplified by using a skeleton header generated by ``bpftool``:
109
110 .. code-block:: console
111
112 # bpftool gen skeleton my_prog.o > my_prog.skel.h
113
114 and the program can be loaded by including ``my_prog.skel.h`` and using
115 the generated helper, ``my_prog__open_and_load``.
116
117 Attachment to LSM Hooks
118 -----------------------
119
120 The LSM allows attachment of eBPF programs as LSM hooks using :manpage:`bpf(2)`
121 syscall's ``BPF_RAW_TRACEPOINT_OPEN`` operation or more simply by
122 using the libbpf helper ``bpf_program__attach_lsm``.
123
124 The program can be detached from the LSM hook by *destroying* the ``link``
125 link returned by ``bpf_program__attach_lsm`` using ``bpf_link__destroy``.
126
127 One can also use the helpers generated in ``my_prog.skel.h`` i.e.
128 ``my_prog__attach`` for attachment and ``my_prog__destroy`` for cleaning up.
129
130 Examples
131 --------
132
133 An example eBPF program can be found in
134 `tools/testing/selftests/bpf/progs/lsm.c`_ and the corresponding
135 userspace code in `tools/testing/selftests/bpf/prog_tests/test_lsm.c`_
136
137 .. Links
138 .. _tools/lib/bpf/bpf_tracing.h:
139 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/lib/bpf/bpf_tracing.h
140 .. _tools/testing/selftests/bpf/progs/lsm.c:
141 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/progs/lsm.c
142 .. _tools/testing/selftests/bpf/prog_tests/test_lsm.c:
143 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/prog_tests/test_lsm.c
144

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

LSM 훅의 런타임 계측

1-27

`LSM BPF Programs` 문서는 `GPL-2.0+` 라이선스를 따르며, 저작권은 2020 Google LLC.에 있습니다.

LSM BPF 프로그램은 권한 있는 사용자가 런타임에 LSM 훅을 계측하여 eBPF로 시스템 전체 MAC (Mandatory Access Control) 정책과 감사 정책을 구현할 수 있게 합니다. MAC은 필수 접근 제어를 뜻합니다.

구조 예시는 `file_mprotect` LSM 훅에 연결할 수 있는 eBPF 프로그램을 다룹니다. 훅의 함수 원형은 `int file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot);`입니다.

계측할 수 있는 다른 LSM 훅은 `security/security.c`에서 찾을 수 있습니다.

`Documentation/bpf/btf.rst`의 BTF를 사용하는 eBPF 프로그램은 연결된 프로그램의 컨텍스트 정보를 읽기 위해 커널 헤더 전체를 포함할 필요가 없습니다. eBPF 프로그램 안에 구조체를 선언하고 실제로 접근할 필드만 지정하면 됩니다.

BTF 형식 선언과 BPF_PROG 매크로

28-64

다음 선언은 `struct mm_struct`와 `struct vm_area_struct`에서 이 프로그램이 읽는 필드만 기술합니다.

struct mm_struct {
        unsigned long start_brk, brk, start_stack;
} __attribute__((preserve_access_index));

struct vm_area_struct {
        unsigned long start_brk, brk, start_stack;
        unsigned long vm_start, vm_end;
        struct mm_struct *vm_mm;
} __attribute__((preserve_access_index));

필드의 선언 순서는 중요하지 않습니다.

빌드 시점에 BTF 정보에 접근할 수 있다면 다음 명령으로 `vmlinux.h`를 생성하여 선언을 더 간단하게 만들 수 있습니다.

# bpftool btf dump file <path-to-btf-vmlinux> format c > vmlinux.h

BPF 프로그램을 배포할 환경과 빌드 환경이 일치한다면 `path-to-btf-vmlinux`로 `/sys/kernel/btf/vmlinux`를 사용할 수 있습니다.

그 뒤 BPF 프로그램에서 `vmlinux.h`를 포함하면 필요한 형식을 직접 정의하지 않아도 됩니다.

eBPF 프로그램은 `tools/lib/bpf/bpf_tracing.h`에 정의된 `BPF_PROG` 매크로로 선언할 수 있습니다. 이 예에서 각 요소의 의미는 다음과 같습니다.

  • `"lsm/file_mprotect"`는 프로그램을 연결해야 하는 LSM 훅을 나타냅니다.
  • `mprotect_audit`는 eBPF 프로그램의 이름입니다.

file_mprotect 정책 프로그램

65-94
SEC("lsm/file_mprotect")
int BPF_PROG(mprotect_audit, struct vm_area_struct *vma,
             unsigned long reqprot, unsigned long prot, int ret)
{
        /* ret is the return value from the previous BPF program
         * or 0 if it's the first hook.
         */
        if (ret != 0)
                return ret;

        int is_heap;

        is_heap = (vma->vm_start >= vma->vm_mm->start_brk &&
                   vma->vm_end <= vma->vm_mm->brk);

        /* Return an -EPERM or write information to the perf events buffer
         * for auditing
         */
        if (is_heap)
                return -EPERM;
}

`ret`는 앞선 BPF 프로그램의 반환값이며 첫 번째 훅이면 0입니다. 앞선 프로그램이 오류를 반환했다면 그 값을 그대로 전달합니다. 그렇지 않으면 VMA가 힙 범위 안에 있는지 검사하고, 힙이면 `-EPERM`을 반환합니다. 실제 감사 정책에서는 대신 perf events 버퍼에 정보를 기록할 수도 있습니다.

`__attribute__((preserve_access_index))`는 BPF verifier가 `Documentation/bpf/btf.rst`의 BTF 정보를 사용해 런타임에 접근 오프셋을 갱신할 수 있게 하는 clang 기능입니다. verifier는 형식을 알고 있으므로 eBPF 프로그램이 여러 형식에 수행하는 모든 접근도 검증합니다.

프로그램 열기와 적재

95-116

eBPF 프로그램은 `bpf(2)` 시스템 호출의 `BPF_PROG_LOAD` 연산으로 적재할 수 있습니다. libbpf에서는 다음처럼 오브젝트를 열고 적재합니다.

struct bpf_object *obj;

obj = bpf_object__open("./my_prog.o");
bpf_object__load(obj);

`bpftool`이 생성한 스켈레톤 헤더를 사용하면 이 절차를 단순화할 수 있습니다.

# bpftool gen skeleton my_prog.o > my_prog.skel.h

프로그램은 `my_prog.skel.h`를 포함하고 생성된 도우미 `my_prog__open_and_load`를 호출하여 열고 적재할 수 있습니다.

LSM 훅 연결, 해제와 예제

117-143

LSM은 `bpf(2)` 시스템 호출의 `BPF_RAW_TRACEPOINT_OPEN` 연산으로 eBPF 프로그램을 LSM 훅에 연결할 수 있게 합니다. 더 간단하게는 libbpf 도우미 `bpf_program__attach_lsm`을 사용할 수 있습니다.

`bpf_program__attach_lsm`이 반환한 `link`를 `bpf_link__destroy`로 파괴하면 프로그램이 LSM 훅에서 분리됩니다.

`my_prog.skel.h`가 생성한 도우미도 사용할 수 있습니다. 연결에는 `my_prog__attach`, 정리에는 `my_prog__destroy`를 사용합니다.

eBPF 프로그램 예제는 `tools/testing/selftests/bpf/progs/lsm.c`에 있고, 대응하는 사용자 공간 코드는 `tools/testing/selftests/bpf/prog_tests/test_lsm.c`에 있습니다.

  • `tools/lib/bpf/bpf_tracing.h`: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/lib/bpf/bpf_tracing.h
  • `tools/testing/selftests/bpf/progs/lsm.c`: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/progs/lsm.c
  • `tools/testing/selftests/bpf/prog_tests/test_lsm.c`: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/prog_tests/test_lsm.c