/ src / message.cpp
message.cpp
  1  /**
  2   * This file is part of Darling.
  3   *
  4   * Copyright (C) 2021 Darling developers
  5   *
  6   * Darling is free software: you can redistribute it and/or modify
  7   * it under the terms of the GNU General Public License as published by
  8   * the Free Software Foundation, either version 3 of the License, or
  9   * (at your option) any later version.
 10   *
 11   * Darling is distributed in the hope that it will be useful,
 12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14   * GNU General Public License for more details.
 15   *
 16   * You should have received a copy of the GNU General Public License
 17   * along with Darling.  If not, see <http://www.gnu.org/licenses/>.
 18   */
 19  
 20  #include <darlingserver/message.hpp>
 21  #include <unistd.h>
 22  #include <cstdlib>
 23  #include <stdexcept>
 24  #include <new>
 25  #include <mutex>
 26  #include <system_error>
 27  
 28  DarlingServer::Address::Address() {
 29  	_address.sun_family = AF_UNIX;
 30  	memset(_address.sun_path, 0, sizeof(_address.sun_path));
 31  	_size = sizeof(_address);
 32  };
 33  
 34  DarlingServer::Address::Address(const struct sockaddr_un& rawAddress, size_t addressLength) {
 35  	_address = rawAddress;
 36  	_size = addressLength;
 37  };
 38  
 39  struct sockaddr_un& DarlingServer::Address::raw() {
 40  	return _address;
 41  };
 42  
 43  const struct sockaddr_un& DarlingServer::Address::raw() const {
 44  	return _address;
 45  };
 46  
 47  size_t DarlingServer::Address::rawSize() const {
 48  	return _size;
 49  };
 50  
 51  void DarlingServer::Address::setRawSize(size_t newRawSize) {
 52  	_size = newRawSize;
 53  };
 54  
 55  DarlingServer::Message::Message(size_t bufferSpace, size_t descriptorSpace, std::function<void()> sendNotificationCallback):
 56  	_sendNotificationCallback(sendNotificationCallback)
 57  {
 58  	size_t controlLen = CMSG_SPACE(sizeof(struct ucred)) + (descriptorSpace > 0 ? CMSG_SPACE(sizeof(int) * descriptorSpace) : 0);
 59  	_controlHeader = static_cast<decltype(_controlHeader)>(malloc(controlLen));
 60  
 61  	if (!_controlHeader) {
 62  		throw std::bad_alloc();
 63  	}
 64  
 65  	_controlHeader->cmsg_len = CMSG_LEN(sizeof(struct ucred));
 66  	_controlHeader->cmsg_level = SOL_SOCKET;
 67  	_controlHeader->cmsg_type = SCM_CREDENTIALS;
 68  	struct ucred ourCreds;
 69  	ourCreds.pid = getpid();
 70  	ourCreds.uid = getuid();
 71  	ourCreds.gid = getgid();
 72  	// the cmsg man page says memcpy should be used with CMSG_DATA instead of direct pointer access
 73  	memcpy(CMSG_DATA(_controlHeader), &ourCreds, sizeof(ourCreds));
 74  
 75  	if (descriptorSpace > 0) {
 76  		auto fdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred)));
 77  		fdHeader->cmsg_len = CMSG_LEN(sizeof(int) * descriptorSpace);
 78  		fdHeader->cmsg_level = SOL_SOCKET;
 79  		fdHeader->cmsg_type = SCM_RIGHTS;
 80  		for (size_t i = 0; i < descriptorSpace; ++i) {
 81  			const int fd = -1;
 82  			memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int));
 83  		}
 84  	}
 85  
 86  	_buffer.resize(bufferSpace);
 87  
 88  	_header.msg_name = &_socketAddress.raw();
 89  	_header.msg_namelen = _socketAddress.rawSize();
 90  	_header.msg_iov = &_dataDescriptor;
 91  	_header.msg_iovlen = 1;
 92  	_header.msg_control = _controlHeader;
 93  	_header.msg_controllen = controlLen;
 94  	_header.msg_flags = 0;
 95  
 96  	_dataDescriptor.iov_base = _buffer.data();
 97  	_dataDescriptor.iov_len = _buffer.size();
 98  };
 99  
100  void DarlingServer::Message::_initWithOther(Message&& other) {
101  	_sendNotificationCallback = std::move(other._sendNotificationCallback);
102  	other._sendNotificationCallback = nullptr;
103  
104  	_buffer = std::move(other._buffer);
105  	_socketAddress = std::move(other._socketAddress);
106  	_controlHeader = std::move(other._controlHeader);
107  
108  	other._controlHeader = nullptr;
109  
110  	_header = std::move(other._header);
111  	_header.msg_name = &_socketAddress.raw();
112  	_header.msg_iov = &_dataDescriptor;
113  
114  	_dataDescriptor.iov_base = _buffer.data();
115  	_dataDescriptor.iov_len = _buffer.size();
116  };
117  
118  void DarlingServer::Message::_cleanupSelf() {
119  	if (_controlHeader) {
120  		auto fdHeader = _descriptorHeader();
121  		if (fdHeader) {
122  			for (size_t i = 0; i < _descriptorSpace(); ++i) {
123  				int fd = -1;
124  				memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int));
125  				if (fd != -1) {
126  					close(fd);
127  				}
128  			}
129  		}
130  		free(_controlHeader);
131  		_controlHeader = nullptr;
132  	}
133  };
134  
135  struct cmsghdr* DarlingServer::Message::_credentialsHeader() {
136  	return const_cast<struct cmsghdr*>(const_cast<const Message*>(this)->_credentialsHeader());
137  };
138  
139  const struct cmsghdr* DarlingServer::Message::_credentialsHeader() const {
140  	const struct cmsghdr* hdr = CMSG_FIRSTHDR(&_header);
141  
142  	while (hdr) {
143  		if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_CREDENTIALS) {
144  			return hdr;
145  		}
146  
147  		hdr = CMSG_NXTHDR(const_cast<struct msghdr*>(&_header), const_cast<struct cmsghdr*>(hdr));
148  	}
149  
150  	return nullptr;
151  };
152  
153  struct cmsghdr* DarlingServer::Message::_descriptorHeader() {
154  	return const_cast<struct cmsghdr*>(const_cast<const Message*>(this)->_descriptorHeader());
155  };
156  
157  const struct cmsghdr* DarlingServer::Message::_descriptorHeader() const {
158  	const struct cmsghdr* hdr = CMSG_FIRSTHDR(&_header);
159  
160  	while (hdr) {
161  		if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
162  			return hdr;
163  		}
164  
165  		hdr = CMSG_NXTHDR(const_cast<struct msghdr*>(&_header), const_cast<struct cmsghdr*>(hdr));
166  	}
167  
168  	return nullptr;
169  };
170  
171  size_t DarlingServer::Message::_descriptorSpace() const {
172  	auto hdr = _descriptorHeader();
173  
174  	if (!hdr) {
175  		return 0;
176  	}
177  
178  	return (hdr->cmsg_len - (reinterpret_cast<uintptr_t>(CMSG_DATA(hdr)) - reinterpret_cast<uintptr_t>(hdr))) / sizeof(int);
179  };
180  
181  DarlingServer::Message::~Message() {
182  	_cleanupSelf();
183  };
184  
185  DarlingServer::Message::Message(Message&& other) {
186  	_initWithOther(std::move(other));
187  };
188  
189  DarlingServer::Message& DarlingServer::Message::operator=(Message&& other) {
190  	_cleanupSelf();
191  	_initWithOther(std::move(other));
192  	return *this;
193  };
194  
195  struct msghdr& DarlingServer::Message::rawHeader() {
196  	return _header;
197  };
198  
199  const struct msghdr& DarlingServer::Message::rawHeader() const {
200  	return _header;
201  };
202  
203  std::vector<uint8_t>& DarlingServer::Message::data() {
204  	return _buffer;
205  };
206  
207  const std::vector<uint8_t>& DarlingServer::Message::data() const {
208  	return _buffer;
209  };
210  
211  DarlingServer::Address DarlingServer::Message::address() const {
212  	return _socketAddress;
213  };
214  
215  void DarlingServer::Message::setAddress(Address address) {
216  	_socketAddress = address;
217  	_header.msg_namelen = _socketAddress.rawSize();
218  };
219  
220  std::vector<int> DarlingServer::Message::descriptors() const {
221  	std::vector<int> descriptors;
222  	auto fdHeader = _descriptorHeader();
223  
224  	if (fdHeader) {
225  		for (size_t i = 0; i < _descriptorSpace(); ++i) {
226  			int fd = -1;
227  			memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int));
228  			if (fd != -1) {
229  				descriptors.push_back(fd);
230  			}
231  		}
232  	}
233  
234  	return descriptors;
235  };
236  
237  void DarlingServer::Message::pushDescriptor(int descriptor) {
238  	if (auto fdHeader = _descriptorHeader()) {
239  		for (size_t i = 0; i < _descriptorSpace(); ++i) {
240  			int fd = -1;
241  			memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int));
242  			if (fd != -1) {
243  				continue;
244  			}
245  
246  			memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &descriptor, sizeof(int));
247  			return;
248  		}
249  	}
250  
251  	auto oldSpace = _descriptorSpace();
252  	_ensureDescriptorHeader(oldSpace + 1);
253  	memcpy(CMSG_DATA(_descriptorHeader()) + (sizeof(int) * oldSpace), &descriptor, sizeof(int));
254  };
255  
256  int DarlingServer::Message::extractDescriptor(int descriptor) {
257  	if (auto fdHeader = _descriptorHeader()) {
258  		for (size_t i = 0; i < _descriptorSpace(); ++i) {
259  			int fd = -1;
260  			memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int));
261  			if (fd != descriptor) {
262  				continue;
263  			}
264  
265  			fd = -1;
266  			memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int));
267  			return descriptor;
268  		}
269  	}
270  
271  	return -1;
272  };
273  
274  int DarlingServer::Message::extractDescriptorAtIndex(size_t index) {
275  	if (auto fdHeader = _descriptorHeader()) {
276  		for (size_t i = 0, presentIndex = 0; i < _descriptorSpace(); ++i) {
277  			int fd = -1;
278  			memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int));
279  			if (fd == -1) {
280  				continue;
281  			}
282  
283  			if (presentIndex++ != index) {
284  				continue;
285  			}
286  
287  			int tmp = -1;
288  			memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &tmp, sizeof(int));
289  			return fd;
290  		}
291  	}
292  
293  	return -1;
294  };
295  
296  void DarlingServer::Message::replaceDescriptors(const std::vector<int>& newDescriptors) {
297  	_ensureDescriptorHeader(newDescriptors.size());
298  	memcpy(CMSG_DATA(_descriptorHeader()), newDescriptors.data(), sizeof(int) * newDescriptors.size());
299  };
300  
301  bool DarlingServer::Message::copyCredentialsOut(struct ucred& outputCredentials) const {
302  	auto credHeader = _credentialsHeader();
303  
304  	if (credHeader) {
305  		memcpy(&outputCredentials, CMSG_DATA(credHeader), sizeof(outputCredentials));
306  		return true;
307  	} else {
308  		return false;
309  	}
310  };
311  
312  void DarlingServer::Message::copyCredentialsIn(const struct ucred& inputCredentials) {
313  	_ensureCredentialsHeader();
314  	memcpy(CMSG_DATA(_credentialsHeader()), &inputCredentials, sizeof(inputCredentials));
315  };
316  
317  void DarlingServer::Message::_ensureCredentialsHeader() {
318  	if (_credentialsHeader()) {
319  		return;
320  	}
321  
322  	auto fdHeader = _descriptorHeader();
323  	auto descSpace = _descriptorSpace();
324  	size_t controlLen = CMSG_SPACE(sizeof(struct ucred)) + (descSpace > 0 ? CMSG_SPACE(sizeof(int) * descSpace) : 0);
325  	auto tmp = static_cast<decltype(_controlHeader)>(malloc(controlLen));
326  	auto old = _controlHeader;
327  	struct cmsghdr* credHeader = nullptr;
328  
329  	if (!tmp) {
330  		throw std::bad_alloc();
331  	}
332  
333  	_controlHeader = tmp;
334  	_header.msg_control = _controlHeader;
335  
336  	credHeader = _controlHeader;
337  
338  	if (descSpace > 0) {
339  		auto newFdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred)));
340  		memcpy(newFdHeader, fdHeader, CMSG_SPACE(sizeof(int) * descSpace));
341  	}
342  
343  	free(old);
344  
345  	_header.msg_controllen = controlLen;
346  
347  	credHeader->cmsg_len = CMSG_LEN(sizeof(struct ucred));
348  	credHeader->cmsg_level = SOL_SOCKET;
349  	credHeader->cmsg_type = SCM_CREDENTIALS;
350  
351  	struct ucred creds;
352  	creds.pid = getpid();
353  	creds.uid = getuid();
354  	creds.gid = getgid();
355  	memcpy(CMSG_DATA(credHeader), &creds, sizeof(struct ucred));
356  };
357  
358  void DarlingServer::Message::_ensureDescriptorHeader(size_t newSpace) {
359  	if (_descriptorSpace() == newSpace) {
360  		return;
361  	}
362  
363  	auto credHeader = _credentialsHeader();
364  	size_t oldSpace = _descriptorSpace();
365  	size_t controlLen = (credHeader ? CMSG_SPACE(sizeof(struct ucred)) : 0) + (newSpace == 0 ? 0 : CMSG_SPACE(sizeof(int) * newSpace));
366  
367  	if (controlLen == 0) {
368  		free(_controlHeader);
369  		_controlHeader = nullptr;
370  		_header.msg_control = nullptr;
371  		_header.msg_controllen = 0;
372  		return;
373  	}
374  
375  	auto tmp = static_cast<decltype(_controlHeader)>(malloc(controlLen));
376  	auto old = _controlHeader;
377  	struct cmsghdr* fdHeader = nullptr;
378  
379  	if (!tmp) {
380  		throw std::bad_alloc();
381  	}
382  
383  	_controlHeader = tmp;
384  	_header.msg_control = _controlHeader;
385  
386  	if (credHeader) {
387  		memcpy(_controlHeader, credHeader, CMSG_SPACE(sizeof(struct ucred)));
388  		fdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred)));
389  	} else {
390  		fdHeader = _controlHeader;
391  	}
392  
393  	free(old);
394  
395  	_header.msg_controllen = controlLen;
396  
397  	if (newSpace > 0) {
398  		fdHeader->cmsg_len = CMSG_LEN(sizeof(int) * newSpace);
399  		fdHeader->cmsg_level = SOL_SOCKET;
400  		fdHeader->cmsg_type = SCM_RIGHTS;
401  
402  		for (size_t i = oldSpace; i < newSpace; ++i) {
403  			int fd = -1;
404  			memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int));
405  		}
406  	}
407  };
408  
409  pid_t DarlingServer::Message::pid() const {
410  	struct ucred creds;
411  
412  	if (copyCredentialsOut(creds)) {
413  		return creds.pid;
414  	} else {
415  		return -1;
416  	}
417  };
418  
419  void DarlingServer::Message::setPID(pid_t pid) {
420  	_ensureCredentialsHeader();
421  	struct ucred creds;
422  	copyCredentialsOut(creds);
423  	creds.pid = pid;
424  	copyCredentialsIn(creds);
425  };
426  
427  uid_t DarlingServer::Message::uid() const {
428  	struct ucred creds;
429  
430  	if (copyCredentialsOut(creds)) {
431  		return creds.uid;
432  	} else {
433  		return -1;
434  	}
435  };
436  
437  void DarlingServer::Message::setUID(uid_t uid) {
438  	_ensureCredentialsHeader();
439  	struct ucred creds;
440  	copyCredentialsOut(creds);
441  	creds.uid = uid;
442  	copyCredentialsIn(creds);
443  };
444  
445  gid_t DarlingServer::Message::gid() const {
446  	struct ucred creds;
447  
448  	if (copyCredentialsOut(creds)) {
449  		return creds.gid;
450  	} else {
451  		return -1;
452  	}
453  };
454  
455  void DarlingServer::Message::setGID(gid_t gid) {
456  	_ensureCredentialsHeader();
457  	struct ucred creds;
458  	copyCredentialsOut(creds);
459  	creds.gid = gid;
460  	copyCredentialsIn(creds);
461  };
462  
463  std::function<void()> DarlingServer::Message::sendNotificationCallback() const {
464  	return _sendNotificationCallback;
465  };
466  
467  void DarlingServer::Message::setSendNotificationCallback(std::function<void()> sendNotificationCallback) {
468  	_sendNotificationCallback = sendNotificationCallback;
469  };
470  
471  //
472  // message queue
473  //
474  
475  void DarlingServer::MessageQueue::push(Message&& message) {
476  	std::unique_lock lock(_lock);
477  	_messages.push_back(std::move(message));
478  
479  	if (_messages.size() > 0) {
480  		auto callback = _messageArrivalNotificationCallback;
481  		lock.unlock();
482  		if (callback) {
483  			callback();
484  		}
485  	}
486  };
487  
488  std::optional<DarlingServer::Message> DarlingServer::MessageQueue::pop() {
489  	std::scoped_lock lock(_lock);
490  	if (_messages.size() > 0) {
491  		Message message = std::move(_messages.front());
492  		_messages.pop_front();
493  		return message;
494  	} else {
495  		return std::nullopt;
496  	}
497  };
498  
499  bool DarlingServer::MessageQueue::sendMany(int socket) {
500  	bool canSendMore = true;
501  	std::scoped_lock lock(_lock);
502  	struct mmsghdr mmsgs[16];
503  	size_t len = 0;
504  	int ret = 0;
505  
506  	while (ret >= 0) {
507  		len = 0;
508  		for (size_t i = 0; i < _messages.size() && i < sizeof(mmsgs) / sizeof(*mmsgs); ++i) {
509  			mmsgs[i].msg_hdr = _messages[i].rawHeader();
510  			mmsgs[i].msg_len = 0;
511  
512  			// some systems report EINVAL when sending to an address filled with null bytes.
513  			auto address = reinterpret_cast<sockaddr_un*>(mmsgs[i].msg_hdr.msg_name);
514  			bool isAddressEmpty = true;
515  			for (size_t j = 0; j < sizeof(address->sun_path); ++j) {
516  				if (address->sun_path[j] != '\0') {
517  					isAddressEmpty = false;
518  					break;
519  				}
520  			}
521  			if (isAddressEmpty) {
522  				mmsgs[i].msg_hdr.msg_name = nullptr;
523  				mmsgs[i].msg_hdr.msg_namelen = 0;
524  			}
525  
526  			++len;
527  		}
528  
529  		if (len == 0) {
530  			break;
531  		}
532  
533  		ret = sendmmsg(socket, mmsgs, len, MSG_DONTWAIT);
534  
535  		if (ret < 0) {
536  			if (errno == EAGAIN) {
537  				canSendMore = false;
538  				break;
539  			} else if (errno == EINTR) {
540  				ret = 0;
541  			} else if (errno == EPIPE || errno == ECONNREFUSED) {
542  				// this means that peer of the first message we tried to send has died.
543  				// we'll just drop that message and try the others.
544  				_messages.pop_front();
545  				ret = 0;
546  			} else {
547  				throw std::system_error(errno, std::generic_category(), "Failed to send messages through socket");
548  			}
549  		}
550  
551  		for (size_t i = 0; i < ret; ++i) {
552  			auto cb = _messages.front().sendNotificationCallback();
553  			_messages.pop_front();
554  			if (cb) {
555  				cb();
556  			}
557  		}
558  	}
559  
560  	return canSendMore;
561  };
562  
563  bool DarlingServer::MessageQueue::receiveMany(int socket) {
564  	bool canReadMore = true;
565  	std::unique_lock lock(_lock);
566  	struct mmsghdr mmsgs[16];
567  	int ret = 0;
568  
569  	while (ret >= 0) {
570  		std::array<Message, sizeof(mmsgs) / sizeof(*mmsgs)> messages;
571  
572  		for (size_t i = 0; i < messages.size(); ++i) {
573  			mmsgs[i].msg_hdr = messages[i].rawHeader();
574  			mmsgs[i].msg_len = 0;
575  		}
576  
577  		ret = recvmmsg(socket, mmsgs, sizeof(mmsgs) / sizeof(*mmsgs), MSG_CMSG_CLOEXEC | MSG_DONTWAIT, nullptr);
578  
579  		if (ret < 0) {
580  			if (errno == EAGAIN) {
581  				canReadMore = false;
582  				break;
583  			} else if (errno == EINTR) {
584  				ret = 0;
585  			} else {
586  				throw std::system_error(errno, std::generic_category(), "Failed to receive messages through socket");
587  			}
588  		}
589  
590  		for (size_t i = 0; i < ret; ++i) {
591  			messages[i].rawHeader() = mmsgs[i].msg_hdr;
592  			messages[i].data().resize(mmsgs[i].msg_len);
593  			messages[i].setAddress(Address(*(const struct sockaddr_un*)mmsgs[i].msg_hdr.msg_name, mmsgs[i].msg_hdr.msg_namelen));
594  			_messages.push_back(std::move(messages[i]));
595  		}
596  	}
597  
598  	if (_messages.size() > 0) {
599  		auto callback = _messageArrivalNotificationCallback;
600  		lock.unlock();
601  		if (callback) {
602  			callback();
603  		}
604  	}
605  
606  	return canReadMore;
607  };
608  
609  void DarlingServer::MessageQueue::setMessageArrivalNotificationCallback(std::function<void()> messageArrivalNotificationCallback) {
610  	std::unique_lock lock(_lock);
611  	_messageArrivalNotificationCallback = messageArrivalNotificationCallback;
612  };
613  
614  bool DarlingServer::MessageQueue::empty() const {
615  	std::unique_lock lock(_lock);
616  	return _messages.empty();
617  };