github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/kfilefields/kfilefields.go (about)

     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 kfilefields provides functions to read kernel "struct file" fields against a file descriptor.
    16  //
    17  // This is done:
    18  //   - without using bpf iterators in order to work on old kernels.
    19  //   - without comparing pids from userspace and ebpf in order to work from
    20  //     different pid namespaces.
    21  package kfilefields
    22  
    23  import "fmt"
    24  
    25  // ReadPrivateDataFromFd uses ebpf to read the private_data pointer from the
    26  // kernel "struct file" associated with the given fd.
    27  func ReadPrivateDataFromFd(fd int) (uint64, error) {
    28  	t, err := creatAndInstallTracer()
    29  	if err != nil {
    30  		return 0, fmt.Errorf("creating and installing tracer: %w", err)
    31  	}
    32  	defer t.close()
    33  	ff, err := t.readStructFileFields(fd)
    34  	if err != nil {
    35  		return 0, fmt.Errorf("reading file fields: %w", err)
    36  	}
    37  	return ff.PrivateData, nil
    38  }
    39  
    40  // ReadFOpForFdType uses ebpf to read the f_op pointer from the kernel "struct file"
    41  // associated with the given fd type.
    42  func ReadFOpForFdType(ft FdType) (uint64, error) {
    43  	if _, ok := supportedFdTypesForFOp[ft]; !ok {
    44  		return 0, fmt.Errorf("unsupported fd type %s", ft.String())
    45  	}
    46  	t, err := creatAndInstallTracer()
    47  	if err != nil {
    48  		return 0, fmt.Errorf("creating and installing tracer: %w", err)
    49  	}
    50  	defer t.close()
    51  	fd, err := t.getFdFromType(ft)
    52  	if err != nil {
    53  		return 0, fmt.Errorf("getting fd from type %s: %w", ft.String(), err)
    54  	}
    55  	ff, err := t.readStructFileFields(fd)
    56  	if err != nil {
    57  		return 0, fmt.Errorf("reading file fields: %w", err)
    58  	}
    59  	return ff.FOp, nil
    60  }
    61  
    62  // ReadRealInodeFromFd uses ebpf to read the f_inode pointer from the
    63  // kernel "struct file" associated with the given fd.
    64  // Specifically, if fd belongs to overlayFS, it will return the underlying, real inode.
    65  //
    66  // This feature makes it possible to check if two fds come from the same
    67  // underlying file, even if they come from two different overlay filesystems.
    68  // This is useful for uprobes because they get attached to the underlying file.
    69  func ReadRealInodeFromFd(fd int) (uint64, error) {
    70  	t, err := creatAndInstallTracer()
    71  	if err != nil {
    72  		return 0, fmt.Errorf("creating and installing tracer: %w", err)
    73  	}
    74  	defer t.close()
    75  	ff, err := t.readStructFileFields(fd)
    76  	if err != nil {
    77  		return 0, fmt.Errorf("reading file fields: %w", err)
    78  	}
    79  	return ff.RealInode, nil
    80  }