Bug Summary

File:plugins/udisks2/udisks2-plugin.c
Warning:line 325, column 97
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name udisks2-plugin.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/plugins/udisks2 -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D HAVE_CONFIG_H -I . -I ../../sensors-applet -D CAFELOCALEDIR="/usr/local/share/locale/" -D G_LOG_DOMAIN="sensors-applet" -D PIXMAPS_DIR="/usr/local/share/pixmaps/cafe-sensors-applet/" -D DATADIR="/usr/local/share" -D LIBDIR="/usr/local/lib" -D SYSCONFDIR="/usr/local/etc" -D PREFIX="/usr/local" -I ../.. -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D PIC -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/plugins/udisks2 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-07-21-121743-79066-1 -x c udisks2-plugin.c
1/*
2 * Copyright (C) 2017 info-cppsp <info@cppsp.de>
3 * Copyright (C) 2005-2009 Alex Murray <murray.alex@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21Udisks2 plugin for the cafe-sensors-applet
22
23written using the structure and code of the previous version
24from Pramod Dematagoda <pmd.lotr.gandalf@gmail.com>
25
26dbus-glib documentation
27https://dbus.freedesktop.org/doc/dbus-glib/
28GDBUS documentation
29https://developer.gnome.org/gio/stable/index.html
30
31*/
32
33
34#ifdef HAVE_CONFIG_H1
35#include "config.h"
36#endif /* HAVE_CONFIG_H */
37
38#include <stdio.h>
39#include <gio/gio.h>
40#include "udisks2-plugin.h"
41
42
43/* remove // from next line for syslog debug */
44//#define UD2PD 1
45
46#ifdef UD2PD
47#include <syslog.h>
48#endif
49
50
51#define UDISKS2_BUS_NAME"org.freedesktop.UDisks2" "org.freedesktop.UDisks2"
52#define UDISKS2_INTERFACE_NAME"org.freedesktop.DBus.ObjectManager" "org.freedesktop.DBus.ObjectManager"
53#define UDISKS2_DEVICE_INTERFACE_NAME"org.freedesktop.UDisks2.Drive" "org.freedesktop.UDisks2.Drive"
54#define UDISKS2_DEVICE_INTERFACE2_NAME"org.freedesktop.UDisks2.Drive.Ata" "org.freedesktop.UDisks2.Drive.Ata"
55
56#define UDISKS2_PROPERTIES_INTERFACE"org.freedesktop.DBus.Properties" "org.freedesktop.DBus.Properties"
57#define UDISKS2_OBJECT_PATH"/org/freedesktop/UDisks2" "/org/freedesktop/UDisks2"
58
59
60/* Info about a single sensor */
61typedef struct _DevInfo {
62 gchar *path;
63 gchar *id;
64 gdouble temp;
65 GDBusProxy *sensor_proxy; /* dbus object */
66 GError *error;
67} DevInfo;
68
69
70const gchar *plugin_name = "udisks2";
71
72/* a container for the devices found to have smart enabled */
73GHashTable *devices = NULL((void*)0);
74
75/* This is a global variable for convenience */
76GDBusConnection *connection = NULL((void*)0);
77
78
79static void update_device (DevInfo *info) {
80 GError *error = NULL((void*)0);
81 GVariant *tempgvar = NULL((void*)0);
82 GVariant *tempgvar2 = NULL((void*)0);
83 gdouble temp;
84
85 /* check valid input parameter */
86 g_return_if_fail (info != NULL)do { if ((info != ((void*)0))) { } else { g_return_if_fail_warning
("sensors-applet", ((const char*) (__func__)), "info != NULL"
); return; } } while (0)
;
87
88 /* check connection too */
89 g_return_if_fail (connection != NULL)do { if ((connection != ((void*)0))) { } else { g_return_if_fail_warning
("sensors-applet", ((const char*) (__func__)), "connection != NULL"
); return; } } while (0)
;
90
91 g_clear_error (&info->error);
92
93 /* check for sensor_proxy, which should exist at this point, make one if necessary and save it into DevInfo
94 * this is used to get the temp value the direct way */
95 if (NULL((void*)0) == info->sensor_proxy) {
96 info->sensor_proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL((void*)0),
97 UDISKS2_BUS_NAME"org.freedesktop.UDisks2",
98 info->path,
99 UDISKS2_PROPERTIES_INTERFACE"org.freedesktop.DBus.Properties",
100 NULL((void*)0), &error);
101
102 /* check, just to be sure */
103 if (NULL((void*)0) == info->sensor_proxy) {
104
105#ifdef UD2PD
106syslog(LOG_ERR, "Failed to get drive temperature 1");
107#endif
108 g_debug ("Failed to get drive temperature 1: %s", error->message);
109 g_clear_error (&error);
110 return;
111 }
112 }
113
114/* note on timing:
115 * it seems to me that smart updates occur automatically every 10 minutes
116 * cafe-sensor-applet has a default refresh of 2 seconds...
117 * it is possible to force a smart update with udisks2: SmartUpdate (IN a{sv} options); */
118
119 /* directly asking the device's DBus object for the temp */
120 tempgvar = g_dbus_proxy_call_sync (info->sensor_proxy, "Get",
121 g_variant_new ("(ss)",
122 UDISKS2_DEVICE_INTERFACE2_NAME"org.freedesktop.UDisks2.Drive.Ata",
123 "SmartTemperature"), /* parameters */
124 G_DBUS_CALL_FLAGS_NONE, /* flags */
125 -1, /* timeout */
126 NULL((void*)0), /* cancellable */
127 &error);
128
129 if (NULL((void*)0) == tempgvar) {
130
131#ifdef UD2PD
132syslog(LOG_ERR, "Failed to get drive temperature 2");
133#endif
134 g_debug ("Failed to get drive temperature 2: %s", error->message);
135 g_clear_error (&error);
136 /* throw away proxy, maybe next time it will be better */
137 g_clear_object (&info->sensor_proxy)do { _Static_assert (sizeof *((&info->sensor_proxy)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&info->sensor_proxy))) _pp = ((&info->sensor_proxy
)); __typeof__ (*((&info->sensor_proxy))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
138 return;
139
140 } else {
141
142#ifdef UD2PD
143syslog(LOG_ERR, "tempgvar value: %s", g_variant_print(tempgvar, TRUE(!(0))));
144/* leaks memory! */
145//syslog(LOG_ERR, "tempgvar value: %s", g_variant_print(g_variant_get_variant(g_variant_get_child_value(tempgvar, 0)), TRUE));
146#endif
147
148 /* tempgvar comes back as something along the lines of array(gvariant(tempasdouble))
149 * hence unpacking
150 * need to free up every param / return value, so can't do it like:
151 * temp = g_variant_get_double(g_variant_get_variant(g_variant_get_child_value(tempgvar, 0))); */
152 tempgvar2 = g_variant_get_child_value (tempgvar, 0);
153 g_variant_unref (tempgvar);
154 tempgvar = g_variant_get_variant (tempgvar2);
155 g_variant_unref (tempgvar2);
156 temp = g_variant_get_double (tempgvar);
157 g_variant_unref (tempgvar);
158
159 /* temp in K */
160 info->temp = temp - 273.15;
161
162#ifdef UD2PD
163syslog(LOG_ERR, "Refresh udisks2 device temp: '%f'\n", info->temp);
164#endif
165
166 }
167
168}
169
170/* in this function we would like to get a list of device (hdd/ssd) paths
171 * then with each path we get the temperature
172 * it is possible with udisks2 to get all the above information in one g_dbus_proxy_call_sync(), so that is how I did it
173 * maybe a better version would be to use GDBusObjectManager Server + Client ?? */
174static void udisks2_plugin_get_sensors (GList **sensors) {
175
176#ifdef UD2PD
177syslog(LOG_ERR, "fstart");
178#endif
179
180 GDBusProxy *proxy = NULL((void*)0);
181 GError *error = NULL((void*)0);
182
183 DevInfo *info;
184
185 /* This connection will be used for everything, including the obtaining of sensor data */
186 connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL((void*)0), &error);
187 if (NULL((void*)0) == connection) {
188
189#ifdef UD2PD
190syslog(LOG_ERR, "dbus conn fail");
191#endif
192
193 g_debug ("Failed to open connection to DBUS: %s", error->message);
194 g_clear_error (&error);
195 return;
196 }
197
198#ifdef UD2PD
199syslog(LOG_ERR, "dbus conn success");
200#endif
201
202 /* I use this proxy to get all info of all devices at once */
203 proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL((void*)0),
204 UDISKS2_BUS_NAME"org.freedesktop.UDisks2",
205 UDISKS2_OBJECT_PATH"/org/freedesktop/UDisks2",
206 UDISKS2_INTERFACE_NAME"org.freedesktop.DBus.ObjectManager",
207 NULL((void*)0), &error);
208
209 if (NULL((void*)0) == proxy) {
210
211#ifdef UD2PD
212syslog(LOG_ERR, "dbus conn proxy fail");
213#endif
214 g_debug ("dbus conn proxy fail: %s", error->message);
215 g_clear_error (&error);
216 g_clear_object (&connection)do { _Static_assert (sizeof *((&connection)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&connection
))) _pp = ((&connection)); __typeof__ (*((&connection
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
217 return;
218 }
219
220#ifdef UD2PD
221syslog(LOG_ERR, "dbus conn proxy success");
222#endif
223
224 /* The object paths of the disks are enumerated and placed in an array of object paths
225 * "GetManagedObjects" returns dict of (objectpath, (dict of (string [ie. if. name], dict of(string [ie. property name], variant [ie. prop. value])))) */
226
227 /* g_dbus_proxy_call_sync() returns NULL on error, GVariant * otherwise
228 * need second variable to prevent memory leak */
229 GVariant *managed_objects = NULL((void*)0);
230 GVariant *managed_objects2 = NULL((void*)0);
231
232 managed_objects2 = g_dbus_proxy_call_sync (proxy, "GetManagedObjects",
233 NULL((void*)0), /* parameters */
234 G_DBUS_CALL_FLAGS_NONE, /* flags */
235 -1, /* timeout */
236 NULL((void*)0), /* cancellable */
237 &error);
238
239 if (NULL((void*)0) == managed_objects2) {
240
241#ifdef UD2PD
242syslog(LOG_ERR, "Failed to enumerate disk devices");
243#endif
244
245 g_debug ("Failed to enumerate disk devices: %s", error->message);
246 g_clear_error (&error);
247 g_clear_object (&proxy)do { _Static_assert (sizeof *((&proxy)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&proxy
))) _pp = ((&proxy)); __typeof__ (*((&proxy))) _ptr =
*_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); }
while (0)
;
248 g_clear_object (&connection)do { _Static_assert (sizeof *((&connection)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&connection
))) _pp = ((&connection)); __typeof__ (*((&connection
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
249 return;
250 }
251
252 /* the result dictionary is enclosed in an array, unpack */
253 managed_objects = g_variant_get_child_value (managed_objects2, 0);
254 g_variant_unref (managed_objects2);
255
256#ifdef UD2PD
257//syslog(LOG_ERR, "managed_objects type: %s", g_variant_print(managed_objects, TRUE));
258syslog(LOG_ERR, "success to enumerate disk devices");
259#endif
260
261 /* iterator for the result dictionary
262 * iterator code is based on the g_variant_iter_next() documentation
263 * iter is freed if the GVariant is, when using g_variant_iter_init() */
264 GVariantIter iter;
265 gchar *key = NULL((void*)0); /* object path (like '/org/freedesktop/UDisks2/drives/Samsung_SSD_840_EVO_250GB_*insert drive serial nr.*') */
266 GVariant *value = NULL((void*)0);
267
268#ifdef UD2PD
269/* log collection size */
270syslog(LOG_ERR, "iter init count: %d", (int) g_variant_iter_init (&iter, managed_objects));
271#else
272 g_variant_iter_init (&iter, managed_objects);
273#endif
274
275 /* "{sv}" is a GVariant format string
276 * {} dictionary of, s string, v GVariant
277 * changed to "{oa{sa{sv}}}" on error message 'the GVariant format string '{sv}' has a type of '{sv}' but the given value has a type of 'a{oa{sa{sv}}}''
278 * a is array, o is object path
279 * NOO!! the right format string is "{o@*}", which means get an object path into the 1st variable (key)
280 * and get 'everything else' (as a GVariant) into the 2nd variable (value)
281 * needs the & before the key and value params! */
282 while (g_variant_iter_next (&iter, "{o@*}", &key, &value)) {
283
284#ifdef UD2PD
285syslog(LOG_ERR, "in iter while loop");
286syslog(LOG_ERR, "key value: %s", key);
287//syslog(LOG_ERR, "value type: %s", g_variant_print(value, TRUE));
288#endif
289
290 /* level 2
291 * create a dictionary of value
292 * the two interface names that we are searching for are known and defined
293 * can't use GVariantDict, it only supports '{sv}' but the given value has a type of '{sa{sv}}'
294 * using general lookup */
295
296 GVariant *propdict = NULL((void*)0); /* drive data */
297 GVariant *propdict2 = NULL((void*)0); /* drive smart data */
298
299 /* make two dictionaries that contain the properties of the drive interfaces */
300 propdict = g_variant_lookup_value (value, UDISKS2_DEVICE_INTERFACE_NAME"org.freedesktop.UDisks2.Drive", G_VARIANT_TYPE_DICTIONARY((const GVariantType *) "a{?*}"));
301 propdict2 = g_variant_lookup_value (value, UDISKS2_DEVICE_INTERFACE2_NAME"org.freedesktop.UDisks2.Drive.Ata", G_VARIANT_TYPE_DICTIONARY((const GVariantType *) "a{?*}"));
302
303
304 /* do we have the right ifname keys? */
305 if ((NULL((void*)0) != propdict) && (NULL((void*)0) != propdict2)) {
306
307#ifdef UD2PD
308syslog(LOG_ERR, "propdict type: %s", g_variant_print(propdict, TRUE(!(0))));
309syslog(LOG_ERR, "propdict2 type: %s", g_variant_print(propdict2, TRUE(!(0))));
310#endif
311
312 /* get data */
313 gchar *id = NULL((void*)0);
314 gchar *model = NULL((void*)0);
315
316 gboolean smartenabled;
317 gdouble temp;
318
319 /* NULL, bc we don't care about the length of the string
320 * typecast bc g_variant_get_string() returns const char* */
321 id = (gchar *) g_variant_get_string (g_variant_lookup_value (propdict, "Id", G_VARIANT_TYPE_STRING((const GVariantType *) "s")), NULL((void*)0));
322 model = (gchar *) g_variant_get_string (g_variant_lookup_value (propdict, "Model", G_VARIANT_TYPE_STRING((const GVariantType *) "s")), NULL((void*)0));
323
324 smartenabled = g_variant_get_boolean (g_variant_lookup_value (propdict2, "SmartEnabled", G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b")));
325 temp = g_variant_get_double (g_variant_lookup_value (propdict2, "SmartTemperature", G_VARIANT_TYPE_DOUBLE((const GVariantType *) "d")));
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
326
327#ifdef UD2PD
328syslog(LOG_ERR, "Found udisks2 device id: '%s'\n", id);
329syslog(LOG_ERR, "Found udisks2 device model: '%s'\n", model);
330syslog(LOG_ERR, "Found udisks2 device smartenabled: '%d'\n", smartenabled);
331syslog(LOG_ERR, "Found udisks2 device temp: '%f'\n", temp);
332#endif
333
334 /* only go on if smart is enabled
335 * save data */
336 if (smartenabled) {
337
338 info = g_new0 (DevInfo, 1)((DevInfo *) g_malloc0_n ((1), sizeof (DevInfo)));
339 if (NULL((void*)0) == devices) {
340 devices = g_hash_table_new (g_str_hash, g_str_equal);
341 }
342
343 info->id = g_strdup (id);
344 info->path = g_strdup (key);
345
346 /* temp in K
347 * this could be left at 0.0, 2 seconds later it will be refreshed anyway */
348 info->temp = (gdouble) temp - 273.15;
349 g_hash_table_insert (devices, info->id, info);
350
351 /* Write the sensor data */
352 sensors_applet_plugin_add_sensor (sensors,
353 id,
354 "Disk Temperature",
355 model,
356 TEMP_SENSOR,
357 FALSE(0),
358 HDD_ICON,
359 DEFAULT_GRAPH_COLOR"#ff0000");
360
361 g_debug ("Added %s", id);
362
363#ifdef UD2PD
364syslog(LOG_ERR, "Added %s", id);
365#endif
366
367 } else {
368
369#ifdef UD2PD
370syslog(LOG_ERR, "No temp data for device: %s\n", key);
371#endif
372
373 g_debug ("No temp data for device: %s\n", key);
374 }
375
376#ifdef UD2PD
377syslog(LOG_ERR, "b4 free1");
378#endif
379
380 g_free (id);
381 g_free (model);
382
383 }
384
385#ifdef UD2PD
386syslog(LOG_ERR, "b4 free2");
387#endif
388
389 /* free propdict, propdict2
390 * g_variant_dict_unref() may not work a few times, gives error
391 * this one seems to do fine */
392 if (NULL((void*)0) != propdict) {g_variant_unref (propdict);}
393 if (NULL((void*)0) != propdict2) {g_variant_unref (propdict2);}
394
395#ifdef UD2PD
396syslog(LOG_ERR, "b4 free3");
397#endif
398
399 g_free (key);
400 g_variant_unref (value);
401
402 } /* end of while loop */
403
404
405 g_variant_unref (managed_objects);
406 g_clear_object (&proxy)do { _Static_assert (sizeof *((&proxy)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&proxy
))) _pp = ((&proxy)); __typeof__ (*((&proxy))) _ptr =
*_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); }
while (0)
;
407 if (NULL((void*)0) == devices) {
408 g_clear_object (&connection)do { _Static_assert (sizeof *((&connection)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&connection
))) _pp = ((&connection)); __typeof__ (*((&connection
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
409 }
410}
411
412/* this function is called every refresh cycle */
413static gdouble udisks2_plugin_get_sensor_value (const gchar *path,
414 const gchar *id,
415 SensorType type,
416 GError **error) {
417 DevInfo *info = NULL((void*)0);
418
419 /* get device stuct from data store */
420 info = (DevInfo *) g_hash_table_lookup (devices, path);
421 if (NULL((void*)0) == info) {
422 g_set_error (error, SENSORS_APPLET_PLUGIN_ERROR(sensors_applet_plugin_error_quark()), 0, "Error finding disk with path %s", path);
423 return 0.0;
424 }
425
426 if (info->error) {
427 *error = info->error;
428 info->error = NULL((void*)0);
429 return 0.0;
430 }
431
432 /* refresh device temp */
433 update_device (info);
434 return info->temp;
435}
436
437
438/* API functions */
439const gchar *sensors_applet_plugin_name (void) {
440 return plugin_name;
441}
442
443static GList *udisks2_plugin_init (void) {
444 GList *sensors = NULL((void*)0);
445
446 udisks2_plugin_get_sensors (&sensors);
447
448 return sensors;
449}
450
451GList *sensors_applet_plugin_init (void) {
452 return udisks2_plugin_init ();
453}
454
455gdouble sensors_applet_plugin_get_sensor_value (const gchar *path,
456 const gchar *id,
457 SensorType type,
458 GError **error) {
459
460 return udisks2_plugin_get_sensor_value (path, id, type, error);
461}