1
#pragma once
2

            
3
#if !defined(__linux__)
4
#error "Linux platform file is part of non-Linux build."
5
#endif
6

            
7
#include <linux/capability.h>
8
#include <cstdint>
9
#include <cstring>
10
#include <stdio.h>	// NOLINT
11
#include <stdlib.h>	// NOLINT
12
#include <sys/socket.h>
13

            
14
// Use Envoy version of this if defined, otherwise roll a simple stderr one without further
15
// dependencies
16
#ifndef RELEASE_ASSERT
17
#define _ASSERT_IMPL(CONDITION, CONDITION_STR, DETAILS)                                            \
18
  do {                                                                                             \
19
    if (!(CONDITION)) {                                                                            \
20
      fprintf(stderr, "assert failure: %s. Details: %s", CONDITION_STR, (DETAILS));                \
21
      ::abort();                                                                                   \
22
    }                                                                                              \
23
  } while (false)
24
#define RELEASE_ASSERT(X, DETAILS) _ASSERT_IMPL(X, #X, DETAILS)
25
#endif
26

            
27
// Kernel headers may miss CAP_BPF added in Linux 5.8
28
#ifndef CAP_BPF
29
#define CAP_BPF 39
30
#endif
31

            
32
#ifndef _SYS_CAPABILITY_H
33
// These are normally defined in <sys/capability.h> added in libcap-dev package. Define these here
34
// to avoid that dependency due to complications in cross-compilation for Intel/Arm.
35
typedef enum {                                             // NOLINT(modernize-use-using)
36
  CAP_EFFECTIVE = 0,  /* Specifies the effective flag */   // NOLINT(readability-identifier-naming)
37
  CAP_PERMITTED = 1,  /* Specifies the permitted flag */   // NOLINT(readability-identifier-naming)
38
  CAP_INHERITABLE = 2 /* Specifies the inheritable flag */ // NOLINT(readability-identifier-naming)
39
} cap_flag_t;
40
#endif
41

            
42
namespace Envoy {
43
namespace Cilium {
44
namespace PrivilegedService {
45

            
46
uint64_t getCapabilities(cap_flag_t kind);
47
size_t dumpCapabilities(cap_flag_t kind, char* buf, size_t buf_size);
48

            
49
#define CILIUM_PRIVILEGED_SERVICE_FD 3
50

            
51
// Communication with the privileged service is performed with a simple message protocol over a Unix
52
// domain socket pair using the SOCK_SEQPACKET type, preserving record boundaries without explicitly
53
// encoding a length field.
54
// Each message starts with a 4-byte type and a 4-byte sequence number, both in the host byte order,
55
// which are followed by message type specific variable length data.
56

            
57
// Supported message types
58
using MessageType = enum {
59
  TypeResponse = 1,
60
  TypeDumpRequest = 2,
61
  TypeBpfOpenRequest = 3,
62
  TypeBpfLookupRequest = 4,
63
  TypeSetSockOpt32Request = 5,
64
};
65

            
66
// Common message header
67
// Note that C++ inheritance can not be used as all the data members need to be on the same struct
68
// definition. This means that we must contain the MessageHeader as the first member of each message
69
// definition.
70
struct MessageHeader {
71
  uint32_t msg_type_ = 0;
72
  uint32_t msg_seq_ = 0; // reflected in response
73

            
74
  MessageHeader() = default;
75
  MessageHeader(MessageType t) : msg_type_(t) {}
76
};
77

            
78
// Response passes the return value and errno code from the system call.
79
// Note that file descriptor return value is passed using the message control channel (ref. man 2
80
// recvmsg).
81
struct Response {
82
  struct MessageHeader hdr_{};
83
  int return_value_ = 0;
84
  int errno_ = 0;
85
};
86

            
87
// Dump requests consists only of the message header, but with the TYPE_DUMP_REQUEST.
88
// Response contains the effective capabilitites in a string form.
89
struct DumpRequest {
90
  DumpRequest() : hdr_(TypeDumpRequest) {}
91

            
92
  struct MessageHeader hdr_;
93
};
94

            
95
// BpfOpenRequest has a variable length path after the message header.
96
// Path need not be 0-terminated.
97
// Response must be a SyscallResponse. The file descriptor is returned in the message control
98
// channel (see man 2 recvmsg).
99
struct BpfOpenRequest {
100
  BpfOpenRequest() : hdr_(TypeBpfOpenRequest) {}
101

            
102
  struct MessageHeader hdr_;
103
  char path_[];
104
};
105

            
106
// BpfLookupRequest passes the expected value size and a variable length key.
107
// Key size is not explicitly passed, as it is deduced from the message length.
108
// In a successful case the response contains the value returned by the bpf map lookup.
109
struct BpfLookupRequest {
110
  BpfLookupRequest(uint32_t value_size) : hdr_(TypeBpfLookupRequest), value_size_(value_size) {}
111

            
112
  struct MessageHeader hdr_;
113
  uint32_t value_size_;
114
  uint8_t key_[];
115
};
116

            
117
// SetSockOptRequest only supports setting 4-byte options.
118
// Response is SyscallResponse.
119
struct SetSockOptRequest {
120
  SetSockOptRequest(int level, int optname, const void* optval, socklen_t optlen)
121
      : hdr_(TypeSetSockOpt32Request), level_(level), optname_(optname) {
122
    RELEASE_ASSERT(optlen == sizeof(uint32_t), "optlen must be 4 bytes");
123
    memcpy(&optval_, optval, optlen);
124
  }
125

            
126
  struct MessageHeader hdr_;
127
  int level_;
128
  int optname_;
129
  uint32_t optval_;
130
};
131

            
132
// Protocol implements the logic for communicating with the privileged service.
133
class Protocol {
134
public:
135
  Protocol(int fd);
136
  ~Protocol();
137

            
138
  void close();
139
  bool isOpen() const { return fd_ != -1; }
140

            
141
  ssize_t sendFdMsg(const void* header, ssize_t headerlen, const void* data = nullptr,
142
                      ssize_t datalen = 0, int fd = -1);
143
  ssize_t recvFdMsg(const void* header, ssize_t headersize, const void* data = nullptr,
144
                      ssize_t datasize = 0, int* fd = nullptr);
145

            
146
protected:
147
  int fd_;
148
};
149

            
150
} // namespace PrivilegedService
151
} // namespace Cilium
152
} // namespace Envoy