diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp index 8cf212867..d6765b7a1 100644 --- a/init/uevent_listener.cpp +++ b/init/uevent_listener.cpp @@ -87,8 +87,8 @@ static void ParseEvent(const char* msg, Uevent* uevent) { } UeventListener::UeventListener() { - // is 2MB enough? udev uses 128MB! - device_fd_.reset(uevent_open_socket(2 * 1024 * 1024, true)); + // is 16MB enough? udev uses 128MB! + device_fd_.reset(uevent_open_socket(16 * 1024 * 1024, true)); if (device_fd_ == -1) { LOG(FATAL) << "Could not open uevent socket"; } diff --git a/libcutils/uevent.cpp b/libcutils/uevent.cpp index 2dfceede5..721de7c47 100644 --- a/libcutils/uevent.cpp +++ b/libcutils/uevent.cpp @@ -95,6 +95,8 @@ out: int uevent_open_socket(int buf_sz, bool passcred) { struct sockaddr_nl addr; int on = passcred; + int buf_sz_readback = 0; + socklen_t optlen = sizeof(buf_sz_readback); int s; memset(&addr, 0, sizeof(addr)); @@ -105,11 +107,21 @@ int uevent_open_socket(int buf_sz, bool passcred) { s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); if (s < 0) return -1; - /* buf_sz should be less than net.core.rmem_max for this to succeed */ - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0 || + getsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz_readback, &optlen) < 0) { close(s); return -1; } + /* Only if SO_RCVBUF was not effective, try SO_RCVBUFFORCE. Generally, we + * want to avoid SO_RCVBUFFORCE, because it generates SELinux denials in + * case we don't have CAP_NET_ADMIN. This is the case, for example, for + * healthd. */ + if (buf_sz_readback < 2 * buf_sz) { + if (setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz)) < 0) { + close(s); + return -1; + } + } setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));