diff options
author | Daniel Mentz <danielmentz@google.com> | 2018-11-27 11:00:29 -0800 |
---|---|---|
committer | Daniel Mentz <danielmentz@google.com> | 2018-12-03 18:39:24 +0000 |
commit | 41aa2c3703ece8c7e8f869dbb74aaf68aeca2310 (patch) | |
tree | d462f0a1d7b9110b6e83768328c79b04bac2def1 /libcutils/uevent.cpp | |
parent | 67fe6f09d571401f5aff8c4ad4f814cb95089366 (diff) | |
download | system_core-41aa2c3703ece8c7e8f869dbb74aaf68aeca2310.tar.gz system_core-41aa2c3703ece8c7e8f869dbb74aaf68aeca2310.tar.bz2 system_core-41aa2c3703ece8c7e8f869dbb74aaf68aeca2310.zip |
Increase netlink uevent rcvbuf size to 16M
Increase size of the NETLINK_KOBJECT_UEVENT socket receive buffer to
16M. Also, use SO_RCVBUFFORCE to override any limits set by
/proc/sys/net/core/rmem_max.
We had a couple of instances, where we lost critical uevent messages due
to receive buffer overflows.
Bug: 119933843
Change-Id: I6aab183aa0194e173f9175b47c6beb0835cf6675
Diffstat (limited to 'libcutils/uevent.cpp')
-rw-r--r-- | libcutils/uevent.cpp | 16 |
1 files changed, 14 insertions, 2 deletions
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)); |