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 // LeakPipe implements a pipe that can transfer vectors of simple objects
30 // between processes.  The pipe is created in the sending process and
31 // transferred over a socketpair that was created before forking.  This ensures
32 // that only the sending process can have the send side of the pipe open, so if
33 // the sending process dies the pipe will close.
34 class LeakPipe {
35  public:
LeakPipe()36   LeakPipe() {
37     int ret = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv_);
38     if (ret < 0) {
39       LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
40     }
41   }
42 
~LeakPipe()43   ~LeakPipe() {
44     Close();
45   }
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() {
81       Close();
82     }
83 
SetFd(int fd)84     void SetFd(int fd) {
85       fd_ = fd;
86     }
87 
Close()88     void Close() {
89       close(fd_);
90       fd_ = -1;
91     }
92 
93    protected:
94     int fd_;
95 
96    private:
97     DISALLOW_COPY_AND_ASSIGN(LeakPipeBase);
98   };
99 
100   class LeakPipeSender : public LeakPipeBase {
101    public:
102     using LeakPipeBase::LeakPipeBase;
103 
104     template<typename T>
Send(const T & value)105     bool Send(const T& value) {
106       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, &value, sizeof(T)));
107       if (ret < 0) {
108         ALOGE("failed to send value: %s", strerror(errno));
109         return false;
110       } else if (static_cast<size_t>(ret) != sizeof(T)) {
111         ALOGE("eof while writing value");
112         return false;
113       }
114 
115       return true;
116     }
117 
118     template<class T, class Alloc = std::allocator<T>>
SendVector(const std::vector<T,Alloc> & vector)119     bool SendVector(const std::vector<T, Alloc>& vector) {
120       size_t size = vector.size() * sizeof(T);
121       if (!Send(size)) {
122         return false;
123       }
124 
125       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, vector.data(), size));
126       if (ret < 0) {
127         ALOGE("failed to send vector: %s", strerror(errno));
128         return false;
129       } else if (static_cast<size_t>(ret) != size) {
130         ALOGE("eof while writing vector");
131         return false;
132       }
133 
134       return true;
135     }
136   };
137 
138   class LeakPipeReceiver : public LeakPipeBase {
139    public:
140     using LeakPipeBase::LeakPipeBase;
141 
142     template<typename T>
Receive(T * value)143     bool Receive(T* value) {
144       ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, reinterpret_cast<void*>(value), sizeof(T)));
145       if (ret < 0) {
146         ALOGE("failed to receive value: %s", strerror(errno));
147         return false;
148       } else if (static_cast<size_t>(ret) != sizeof(T)) {
149         ALOGE("eof while receiving value");
150         return false;
151       }
152 
153       return true;
154     }
155 
156     template<class T, class Alloc = std::allocator<T>>
ReceiveVector(std::vector<T,Alloc> & vector)157     bool ReceiveVector(std::vector<T, Alloc>& vector) {
158       size_t size = 0;
159       if (!Receive(&size)) {
160         return false;
161       }
162 
163       vector.resize(size / sizeof(T));
164 
165       char* ptr = reinterpret_cast<char*>(vector.data());
166       while (size > 0) {
167         ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, ptr, size));
168         if (ret < 0) {
169           ALOGE("failed to send vector: %s", strerror(errno));
170           return false;
171         } else if (ret == 0) {
172           ALOGE("eof while reading vector");
173           return false;
174         }
175         size -= ret;
176         ptr += ret;
177       }
178 
179       return true;
180     }
181 
182   };
183 
Receiver()184   LeakPipeReceiver& Receiver() {
185     return receiver_;
186   }
187 
Sender()188   LeakPipeSender& Sender() {
189     return sender_;
190   }
191 
192  private:
193   LeakPipeReceiver receiver_;
194   LeakPipeSender sender_;
195   bool SendFd(int sock, int fd);
196   int ReceiveFd(int sock);
197   DISALLOW_COPY_AND_ASSIGN(LeakPipe);
198   int sv_[2];
199 };
200 
201 #endif // LIBMEMUNREACHABLE_LEAK_PIPE_H_
202