1 /*
2  * Copyright (C) 2016 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 #ifndef LIBMEMUNREACHABLE_LEAK_PIPE_H_
18 #define LIBMEMUNREACHABLE_LEAK_PIPE_H_
19 
20 #include <sys/socket.h>
21 
22 #include <vector>
23 
24 #include "android-base/macros.h"
25 
26 #include "ScopedPipe.h"
27 #include "log.h"
28 
29 namespace android {
30 
31 // LeakPipe implements a pipe that can transfer vectors of simple objects
32 // between processes.  The pipe is created in the sending process and
33 // transferred over a socketpair that was created before forking.  This ensures
34 // that only the sending process can have the send side of the pipe open, so if
35 // the sending process dies the pipe will close.
36 class LeakPipe {
37  public:
LeakPipe()38   LeakPipe() {
39     int ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv_);
40     if (ret < 0) {
41       MEM_LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
42     }
43   }
44 
~LeakPipe()45   ~LeakPipe() { Close(); }
46 
Close()47   void Close() {
48     close(sv_[0]);
49     close(sv_[1]);
50     sv_[0] = -1;
51     sv_[1] = -1;
52   }
53 
OpenReceiver()54   bool OpenReceiver() {
55     int fd = ReceiveFd(sv_[0]);
56     if (fd < 0) {
57       return false;
58     }
59 
60     receiver_.SetFd(fd);
61     return true;
62   }
63 
OpenSender()64   bool OpenSender() {
65     ScopedPipe pipe;
66 
67     if (!SendFd(sv_[1], pipe.Receiver())) {
68       return false;
69     }
70     pipe.ReleaseReceiver();
71 
72     sender_.SetFd(pipe.ReleaseSender());
73     return true;
74   }
75 
76   class LeakPipeBase {
77    public:
LeakPipeBase()78     LeakPipeBase() : fd_(-1) {}
79 
~LeakPipeBase()80     ~LeakPipeBase() { Close(); }
81 
SetFd(int fd)82     void SetFd(int fd) { fd_ = fd; }
83 
Close()84     void Close() {
85       close(fd_);
86       fd_ = -1;
87     }
88 
89    protected:
90     int fd_;
91 
92    private:
93     DISALLOW_COPY_AND_ASSIGN(LeakPipeBase);
94   };
95 
96   class LeakPipeSender : public LeakPipeBase {
97    public:
98     using LeakPipeBase::LeakPipeBase;
99 
100     template <typename T>
Send(const T & value)101     bool Send(const T& value) {
102       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, &value, sizeof(T)));
103       if (ret < 0) {
104         MEM_ALOGE("failed to send value: %s", strerror(errno));
105         return false;
106       } else if (static_cast<size_t>(ret) != sizeof(T)) {
107         MEM_ALOGE("eof while writing value");
108         return false;
109       }
110 
111       return true;
112     }
113 
114     template <class T, class Alloc = std::allocator<T>>
SendVector(const std::vector<T,Alloc> & vector)115     bool SendVector(const std::vector<T, Alloc>& vector) {
116       size_t size = vector.size() * sizeof(T);
117       if (!Send(size)) {
118         return false;
119       }
120 
121       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, vector.data(), size));
122       if (ret < 0) {
123         MEM_ALOGE("failed to send vector: %s", strerror(errno));
124         return false;
125       } else if (static_cast<size_t>(ret) != size) {
126         MEM_ALOGE("eof while writing vector");
127         return false;
128       }
129 
130       return true;
131     }
132   };
133 
134   class LeakPipeReceiver : public LeakPipeBase {
135    public:
136     using LeakPipeBase::LeakPipeBase;
137 
138     template <typename T>
Receive(T * value)139     bool Receive(T* value) {
140       ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, reinterpret_cast<void*>(value), sizeof(T)));
141       if (ret < 0) {
142         MEM_ALOGE("failed to receive value: %s", strerror(errno));
143         return false;
144       } else if (static_cast<size_t>(ret) != sizeof(T)) {
145         MEM_ALOGE("eof while receiving value");
146         return false;
147       }
148 
149       return true;
150     }
151 
152     template <class T, class Alloc = std::allocator<T>>
ReceiveVector(std::vector<T,Alloc> & vector)153     bool ReceiveVector(std::vector<T, Alloc>& vector) {
154       size_t size = 0;
155       if (!Receive(&size)) {
156         return false;
157       }
158 
159       vector.resize(size / sizeof(T));
160 
161       char* ptr = reinterpret_cast<char*>(vector.data());
162       while (size > 0) {
163         ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, ptr, size));
164         if (ret < 0) {
165           MEM_ALOGE("failed to send vector: %s", strerror(errno));
166           return false;
167         } else if (ret == 0) {
168           MEM_ALOGE("eof while reading vector");
169           return false;
170         }
171         size -= ret;
172         ptr += ret;
173       }
174 
175       return true;
176     }
177   };
178 
Receiver()179   LeakPipeReceiver& Receiver() { return receiver_; }
180 
Sender()181   LeakPipeSender& Sender() { return sender_; }
182 
183  private:
184   LeakPipeReceiver receiver_;
185   LeakPipeSender sender_;
186   bool SendFd(int sock, int fd);
187   int ReceiveFd(int sock);
188   DISALLOW_COPY_AND_ASSIGN(LeakPipe);
189   int sv_[2];
190 };
191 
192 }  // namespace android
193 
194 #endif  // LIBMEMUNREACHABLE_LEAK_PIPE_H_
195