summaryrefslogtreecommitdiff
path: root/src/rfkill.c
diff options
context:
space:
mode:
authorBenjamin Berg <bberg@redhat.com>2021-05-03 15:12:10 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2021-06-23 15:33:45 -0700
commitc939747f543a76ffd556312f753cf9d36c047c94 (patch)
treef3f495a195e929479fe196203e6beae347fcef72 /src/rfkill.c
parent4da8cec318185fdf2039f766113a12848c12d09b (diff)
downloadbluez-c939747f543a76ffd556312f753cf9d36c047c94.tar.gz
rfkill: Fix reading from rfkill socket
The kernel will always send exactly one event, but the size of the passed struct will depend on the length of the submitted read() and the kernel version. i.e. the interface can be extended and we need to expect for a read to be longer than expected if we ask for it. Fix this by only requesting the needed length and explicitly check the length against the V1 version of the structure to make the code a bit more future proof in case the internal copy of the struct is updated to contain new fields.
Diffstat (limited to 'src/rfkill.c')
-rw-r--r--src/rfkill.c24
1 files changed, 11 insertions, 13 deletions
diff --git a/src/rfkill.c b/src/rfkill.c
index ec9fcdfdd..2099c5ac5 100644
--- a/src/rfkill.c
+++ b/src/rfkill.c
@@ -53,12 +53,12 @@ struct rfkill_event {
uint8_t soft;
uint8_t hard;
};
+#define RFKILL_EVENT_SIZE_V1 8
static gboolean rfkill_event(GIOChannel *chan,
GIOCondition cond, gpointer data)
{
- unsigned char buf[32];
- struct rfkill_event *event = (void *) buf;
+ struct rfkill_event event = { 0 };
struct btd_adapter *adapter;
char sysname[PATH_MAX];
ssize_t len;
@@ -69,34 +69,32 @@ static gboolean rfkill_event(GIOChannel *chan,
fd = g_io_channel_unix_get_fd(chan);
- memset(buf, 0, sizeof(buf));
-
- len = read(fd, buf, sizeof(buf));
+ len = read(fd, &event, sizeof(event));
if (len < 0) {
if (errno == EAGAIN)
return TRUE;
return FALSE;
}
- if (len != sizeof(struct rfkill_event))
+ if (len < RFKILL_EVENT_SIZE_V1)
return TRUE;
DBG("RFKILL event idx %u type %u op %u soft %u hard %u",
- event->idx, event->type, event->op,
- event->soft, event->hard);
+ event.idx, event.type, event.op,
+ event.soft, event.hard);
- if (event->soft || event->hard)
+ if (event.soft || event.hard)
return TRUE;
- if (event->op != RFKILL_OP_CHANGE)
+ if (event.op != RFKILL_OP_CHANGE)
return TRUE;
- if (event->type != RFKILL_TYPE_BLUETOOTH &&
- event->type != RFKILL_TYPE_ALL)
+ if (event.type != RFKILL_TYPE_BLUETOOTH &&
+ event.type != RFKILL_TYPE_ALL)
return TRUE;
snprintf(sysname, sizeof(sysname) - 1,
- "/sys/class/rfkill/rfkill%u/name", event->idx);
+ "/sys/class/rfkill/rfkill%u/name", event.idx);
fd = open(sysname, O_RDONLY);
if (fd < 0)