inspektor-gadget

Форк
0
129 строк · 3.7 Кб
1
// Copyright 2023 The Inspektor Gadget authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package containerhook
16

17
import (
18
	"errors"
19
	"fmt"
20
	"os"
21
	"syscall"
22

23
	"github.com/cilium/ebpf"
24
	"github.com/cilium/ebpf/link"
25
	"golang.org/x/sys/unix"
26

27
	"github.com/inspektor-gadget/inspektor-gadget/pkg/btfgen"
28
	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
29
)
30

31
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags ${CFLAGS} -no-global-types privatedata ./bpf/privatedata.bpf.c -- -I./bpf/
32

33
// readPrivateDataFromFd use ebpf to read the private_data pointer from the
34
// kernel "struct file" associated with the given fd.
35
//
36
// It can then be used in other ebpf programs.
37
//
38
// This is done:
39
//   - without using bpf iterators in order to work on old kernels.
40
//   - without comparing pids from userspace and ebpf in order to work from
41
//     different pid namespaces.
42
func readPrivateDataFromFd(fd int) (uint64, error) {
43
	var objs privatedataObjects
44
	var links []link.Link
45
	var err error
46
	sock := [2]int{-1, -1}
47

48
	defer func() {
49
		for i := 0; i < 2; i++ {
50
			if sock[i] != -1 {
51
				unix.Close(sock[i])
52
			}
53
		}
54
		for _, l := range links {
55
			gadgets.CloseLink(l)
56
		}
57
		objs.Close()
58
	}()
59

60
	// Create a socket pair
61
	sock, err = unix.Socketpair(unix.AF_UNIX, unix.SOCK_DGRAM, 0)
62
	if err != nil {
63
		return 0, fmt.Errorf("creating socket pair: %w", err)
64
	}
65

66
	// Find the inode of the socket
67
	fdFileInfo, err := os.Stat(fmt.Sprintf("/proc/self/fd/%d", sock[0]))
68
	if err != nil {
69
		return 0, fmt.Errorf("reading file info from fd %d: %w", fd, err)
70
	}
71
	fdStat, ok := fdFileInfo.Sys().(*syscall.Stat_t)
72
	if !ok {
73
		return 0, errors.New("not a syscall.Stat_t")
74
	}
75
	fdIno := fdStat.Ino
76

77
	// Load ebpf program configured with the socket inode
78
	spec, err := loadPrivatedata()
79
	if err != nil {
80
		return 0, fmt.Errorf("load ebpf program for container-hook: %w", err)
81
	}
82
	consts := map[string]interface{}{
83
		"socket_ino": uint64(fdIno),
84
	}
85
	if err := spec.RewriteConstants(consts); err != nil {
86
		return 0, fmt.Errorf("RewriteConstants: %w", err)
87
	}
88

89
	opts := ebpf.CollectionOptions{
90
		Programs: ebpf.ProgramOptions{
91
			KernelTypes: btfgen.GetBTFSpec(),
92
		},
93
	}
94
	if err := spec.LoadAndAssign(&objs, &opts); err != nil {
95
		return 0, fmt.Errorf("loading maps and programs: %w", err)
96
	}
97

98
	// Attach ebpf programs
99
	l, err := link.Kprobe("__scm_send", objs.IgScmSndE, nil)
100
	if err != nil {
101
		return 0, fmt.Errorf("attaching kprobe __scm_send: %w", err)
102
	}
103
	links = append(links, l)
104

105
	l, err = link.Kretprobe("fget_raw", objs.IgFgetX, nil)
106
	if err != nil {
107
		return 0, fmt.Errorf("attaching kretprobe fget_raw: %w", err)
108
	}
109
	links = append(links, l)
110

111
	// Send the fd through the socket with SCM_RIGHTS.
112
	// This will trigger the __scm_send kprobe and fget_raw kretprobe
113
	buf := make([]byte, 1)
114
	err = unix.Sendmsg(sock[0], buf, unix.UnixRights(fd), nil, 0)
115
	if err != nil {
116
		return 0, fmt.Errorf("sending fd: %w", err)
117
	}
118

119
	// Read private_data from objs
120
	privateData := uint64(0)
121
	err = objs.IgPrivateData.Lookup(uint32(0), &privateData)
122
	if err != nil {
123
		return 0, fmt.Errorf("reading private_data: %w", err)
124
	}
125
	if privateData == 0 {
126
		return 0, fmt.Errorf("private_data is 0")
127
	}
128
	return privateData, nil
129
}
130

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.