1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "BpfUtils" 18 19 #include "bpf/BpfUtils.h" 20 21 #include <elf.h> 22 #include <inttypes.h> 23 #include <linux/bpf.h> 24 #include <linux/if_ether.h> 25 #include <linux/in.h> 26 #include <linux/pfkeyv2.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <sys/mman.h> 30 #include <sys/resource.h> 31 #include <sys/socket.h> 32 #include <sys/stat.h> 33 #include <sys/utsname.h> 34 #include <sstream> 35 #include <string> 36 37 #include <android-base/unique_fd.h> 38 #include <log/log.h> 39 #include <processgroup/processgroup.h> 40 41 using android::base::unique_fd; 42 43 // The buffer size for the buffer that records program loading logs, needs to be large enough for 44 // the largest kernel program. 45 46 namespace android { 47 namespace bpf { 48 49 uint64_t getSocketCookie(int sockFd) { 50 uint64_t sock_cookie; 51 socklen_t cookie_len = sizeof(sock_cookie); 52 int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len); 53 if (res < 0) { 54 res = -errno; 55 ALOGE("Failed to get socket cookie: %s\n", strerror(errno)); 56 errno = -res; 57 // 0 is an invalid cookie. See sock_gen_cookie. 58 return NONEXISTENT_COOKIE; 59 } 60 return sock_cookie; 61 } 62 63 int synchronizeKernelRCU() { 64 // This is a temporary hack for network stats map swap on devices running 65 // 4.9 kernels. The kernel code of socket release on pf_key socket will 66 // explicitly call synchronize_rcu() which is exactly what we need. 67 int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); 68 69 if (pfSocket < 0) { 70 int ret = -errno; 71 ALOGE("create PF_KEY socket failed: %s", strerror(errno)); 72 return ret; 73 } 74 75 // When closing socket, synchronize_rcu() gets called in sock_release(). 76 if (close(pfSocket)) { 77 int ret = -errno; 78 ALOGE("failed to close the PF_KEY socket: %s", strerror(errno)); 79 return ret; 80 } 81 return 0; 82 } 83 84 int setrlimitForTest() { 85 // Set the memory rlimit for the test process if the default MEMLOCK rlimit is not enough. 86 struct rlimit limit = { 87 .rlim_cur = 1073741824, // 1 GiB 88 .rlim_max = 1073741824, // 1 GiB 89 }; 90 int res = setrlimit(RLIMIT_MEMLOCK, &limit); 91 if (res) { 92 ALOGE("Failed to set the default MEMLOCK rlimit: %s", strerror(errno)); 93 } 94 return res; 95 } 96 97 unsigned kernelVersion() { 98 struct utsname buf; 99 int ret = uname(&buf); 100 if (ret) return 0; 101 102 unsigned kver_major; 103 unsigned kver_minor; 104 unsigned kver_sub; 105 char dummy; 106 ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &dummy); 107 // Check the device kernel version 108 if (ret < 3) return 0; 109 110 return KVER(kver_major, kver_minor, kver_sub); 111 } 112 113 } // namespace bpf 114 } // namespace android 115