Bug Summary

File:lapiz/bacon-message-connection.c
Warning:line 170, column 30
Out of bound memory access (access exceeds upper limit of memory block)

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 bacon-message-connection.c -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/lapiz -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -I .. -I . -I ./smclient -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/local/include/ctksourceview-4 -I /usr/local/include/libbean-1.0 -I /usr/include/gobject-introspection-1.0 -I /usr/include/gobject-introspection-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D DATADIR="/usr/share" -D LAPIZ_DATADIR="/usr/share/lapiz" -D LIBDIR="/usr/lib" -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../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/lapiz -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/2024-08-26-222817-32832-1 -x c bacon-message-connection.c
1/*
2 * Copyright (C) 2003 Bastien Nocera <hadess@hadess.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <sys/un.h>
29#include <errno(*__errno_location ()).h>
30
31#include "bacon-message-connection.h"
32
33#ifndef UNIX_PATH_MAX108
34#define UNIX_PATH_MAX108 108
35#endif
36
37struct BaconMessageConnection {
38 /* A server accepts connections */
39 gboolean is_server;
40
41 /* The socket path itself */
42 char *path;
43
44 /* File descriptor of the socket */
45 int fd;
46 /* Channel to watch */
47 GIOChannel *chan;
48 /* Event id returned by g_io_add_watch() */
49 int conn_id;
50
51 /* Connections accepted by this connection */
52 GSList *accepted_connections;
53
54 /* callback */
55 void (*func) (const char *message, gpointer user_data);
56 gpointer data;
57};
58
59static gboolean
60test_is_socket (const char *path)
61{
62 struct stat s;
63
64 if (stat (path, &s) == -1)
65 return FALSE(0);
66
67 if (S_ISSOCK (s.st_mode)((((s.st_mode)) & 0170000) == (0140000)))
68 return TRUE(!(0));
69
70 return FALSE(0);
71}
72
73static gboolean
74is_owned_by_user_and_socket (const char *path)
75{
76 struct stat s;
77
78 if (stat (path, &s) == -1)
79 return FALSE(0);
80
81 if (s.st_uid != geteuid ())
82 return FALSE(0);
83
84 if ((s.st_mode & S_IFSOCK0140000) != S_IFSOCK0140000)
85 return FALSE(0);
86
87 return TRUE(!(0));
88}
89
90static gboolean server_cb (GIOChannel *source,
91 GIOCondition condition, gpointer data);
92
93static gboolean
94setup_connection (BaconMessageConnection *conn)
95{
96 g_return_val_if_fail (conn->chan == NULL, FALSE)do { if ((conn->chan == ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn->chan == NULL"
); return ((0)); } } while (0)
;
97
98 conn->chan = g_io_channel_unix_new (conn->fd);
99 if (!conn->chan) {
100 return FALSE(0);
101 }
102 g_io_channel_set_line_term (conn->chan, "\n", 1);
103 conn->conn_id = g_io_add_watch (conn->chan, G_IO_IN, server_cb, conn);
104
105 return TRUE(!(0));
106}
107
108static void
109accept_new_connection (BaconMessageConnection *server_conn)
110{
111 BaconMessageConnection *conn;
112 int alen;
113
114 g_return_if_fail (server_conn->is_server)do { if ((server_conn->is_server)) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "server_conn->is_server"
); return; } } while (0)
;
115
116 conn = g_new0 (BaconMessageConnection, 1)((BaconMessageConnection *) g_malloc0_n ((1), sizeof (BaconMessageConnection
)))
;
117 conn->is_server = FALSE(0);
118 conn->func = server_conn->func;
119 conn->data = server_conn->data;
120
121 conn->fd = accept (server_conn->fd, NULL((void*)0), (guint *)&alen);
122
123 server_conn->accepted_connections =
124 g_slist_prepend (server_conn->accepted_connections, conn);
125
126 setup_connection (conn);
127}
128
129static gboolean
130server_cb (GIOChannel *source,
131 GIOCondition condition G_GNUC_UNUSED__attribute__ ((__unused__)),
132 gpointer data)
133{
134 BaconMessageConnection *conn = (BaconMessageConnection *)data;
135 char *message, *subs, buf;
136 int cd, rc, offset;
137 gboolean finished;
138
139 offset = 0;
140 if (conn->is_server && conn->fd == g_io_channel_unix_get_fd (source)) {
1
Assuming field 'is_server' is 0
141 accept_new_connection (conn);
142 return TRUE(!(0));
143 }
144 message = g_malloc (1);
145 cd = conn->fd;
146 rc = read (cd, &buf, 1);
147 while (rc > 0 && buf != '\n')
2
Assuming 'rc' is > 0
3
Assuming the condition is true
4
Loop condition is true. Entering loop body
5
Assuming 'rc' is > 0
6
Assuming the condition is true
7
Loop condition is true. Entering loop body
8
Assuming 'rc' is > 0
9
Assuming the condition is false
10
Loop condition is false. Execution continues on line 154
148 {
149 message = g_realloc (message, rc + offset + 1);
150 message[offset] = buf;
151 offset = offset + rc;
152 rc = read (cd, &buf, 1);
153 }
154 if (rc
10.1
'rc' is > 0
<= 0) {
11
Taking false branch
155 g_io_channel_shutdown (conn->chan, FALSE(0), NULL((void*)0));
156 g_io_channel_unref (conn->chan);
157 conn->chan = NULL((void*)0);
158 close (conn->fd);
159 conn->fd = -1;
160 g_free (message);
161 conn->conn_id = 0;
162
163 return FALSE(0);
164 }
165 message[offset] = '\0';
166
167 subs = message;
168 finished = FALSE(0);
169
170 while (finished
11.1
'finished' is equal to FALSE
16.1
'finished' is equal to FALSE
20.1
'finished' is equal to FALSE
== FALSE(0) && *subs != '\0')
12
Loop condition is true. Entering loop body
16
Taking false branch
17
Loop condition is true. Entering loop body
20
Taking false branch
21
Out of bound memory access (access exceeds upper limit of memory block)
171 {
172 if (conn->func
17.1
Field 'func' is equal to NULL
!= NULL((void*)0)
)
13
Assuming field 'func' is equal to NULL
14
Taking false branch
18
Taking false branch
173 (*conn->func) (subs, conn->data);
174
175 subs += strlen (subs) + 1;
176 if (subs - message >= offset)
15
Assuming the condition is false
19
Assuming the condition is false
177 finished = TRUE(!(0));
178 }
179
180 g_free (message);
181
182 return TRUE(!(0));
183}
184
185static char *
186find_file_with_pattern (const char *dir, const char *pattern)
187{
188 GDir *filedir;
189 char *found_filename;
190 const char *filename;
191 GPatternSpec *pat;
192
193 filedir = g_dir_open (dir, 0, NULL((void*)0));
194 if (filedir == NULL((void*)0))
195 return NULL((void*)0);
196
197 pat = g_pattern_spec_new (pattern);
198 if (pat == NULL((void*)0))
199 {
200 g_dir_close (filedir);
201 return NULL((void*)0);
202 }
203
204 found_filename = NULL((void*)0);
205
206 while ((filename = g_dir_read_name (filedir)))
207 {
208 if (g_pattern_match_string (pat, filename))
209 {
210 char *tmp = g_build_filename (dir, filename, NULL((void*)0));
211 if (is_owned_by_user_and_socket (tmp))
212 found_filename = g_strdup (filename)g_strdup_inline (filename);
213 g_free (tmp);
214 }
215
216 if (found_filename != NULL((void*)0))
217 break;
218 }
219
220 g_pattern_spec_free (pat);
221 g_dir_close (filedir);
222
223 return found_filename;
224}
225
226static char *
227socket_filename (const char *prefix)
228{
229 char *pattern, *path, *filename;
230 const char *tmpdir;
231
232 pattern = g_strdup_printf ("%s.%s.*", prefix, g_get_user_name ());
233 tmpdir = g_get_tmp_dir ();
234 filename = find_file_with_pattern (tmpdir, pattern);
235 if (filename == NULL((void*)0))
236 {
237 char *newfile;
238
239 newfile = g_strdup_printf ("%s.%s.%u", prefix,
240 g_get_user_name (), g_random_int ());
241 path = g_build_filename (tmpdir, newfile, NULL((void*)0));
242 g_free (newfile);
243 } else {
244 path = g_build_filename (tmpdir, filename, NULL((void*)0));
245 g_free (filename);
246 }
247
248 g_free (pattern);
249 return path;
250}
251
252static gboolean
253try_server (BaconMessageConnection *conn)
254{
255 struct sockaddr_un uaddr;
256
257 uaddr.sun_family = AF_UNIX1;
258 strncpy (uaddr.sun_path, conn->path,
259 MIN (strlen(conn->path)+1, UNIX_PATH_MAX)(((strlen(conn->path)+1) < (108)) ? (strlen(conn->path
)+1) : (108))
);
260 conn->fd = socket (PF_UNIX1, SOCK_STREAMSOCK_STREAM, 0);
261 if (bind (conn->fd, (struct sockaddr *) &uaddr, sizeof (uaddr)) == -1)
262 {
263 conn->fd = -1;
264 return FALSE(0);
265 }
266 listen (conn->fd, 5);
267
268 if (!setup_connection (conn))
269 return FALSE(0);
270 return TRUE(!(0));
271}
272
273static gboolean
274try_client (BaconMessageConnection *conn)
275{
276 struct sockaddr_un uaddr;
277
278 uaddr.sun_family = AF_UNIX1;
279 strncpy (uaddr.sun_path, conn->path,
280 MIN(strlen(conn->path)+1, UNIX_PATH_MAX)(((strlen(conn->path)+1) < (108)) ? (strlen(conn->path
)+1) : (108))
);
281 conn->fd = socket (PF_UNIX1, SOCK_STREAMSOCK_STREAM, 0);
282 if (connect (conn->fd, (struct sockaddr *) &uaddr,
283 sizeof (uaddr)) == -1)
284 {
285 conn->fd = -1;
286 return FALSE(0);
287 }
288
289 return setup_connection (conn);
290}
291
292BaconMessageConnection *
293bacon_message_connection_new (const char *prefix)
294{
295 BaconMessageConnection *conn;
296
297 g_return_val_if_fail (prefix != NULL, NULL)do { if ((prefix != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "prefix != NULL")
; return (((void*)0)); } } while (0)
;
298
299 conn = g_new0 (BaconMessageConnection, 1)((BaconMessageConnection *) g_malloc0_n ((1), sizeof (BaconMessageConnection
)))
;
300 conn->path = socket_filename (prefix);
301
302 if (test_is_socket (conn->path) == FALSE(0))
303 {
304 if (!try_server (conn))
305 {
306 bacon_message_connection_free (conn);
307 return NULL((void*)0);
308 }
309
310 conn->is_server = TRUE(!(0));
311 return conn;
312 }
313
314 if (try_client (conn) == FALSE(0))
315 {
316 unlink (conn->path);
317 try_server (conn);
318 if (conn->fd == -1)
319 {
320 bacon_message_connection_free (conn);
321 return NULL((void*)0);
322 }
323
324 conn->is_server = TRUE(!(0));
325 return conn;
326 }
327
328 conn->is_server = FALSE(0);
329 return conn;
330}
331
332void
333bacon_message_connection_free (BaconMessageConnection *conn)
334{
335 GSList *child_conn;
336
337 g_return_if_fail (conn != NULL)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
; } } while (0)
;
338 /* Only servers can accept other connections */
339 g_return_if_fail (conn->is_server != FALSE ||do { if ((conn->is_server != (0) || conn->accepted_connections
== ((void*)0))) { } else { g_return_if_fail_warning (((gchar
*) 0), ((const char*) (__func__)), "conn->is_server != FALSE || conn->accepted_connections == NULL"
); return; } } while (0)
340 conn->accepted_connections == NULL)do { if ((conn->is_server != (0) || conn->accepted_connections
== ((void*)0))) { } else { g_return_if_fail_warning (((gchar
*) 0), ((const char*) (__func__)), "conn->is_server != FALSE || conn->accepted_connections == NULL"
); return; } } while (0)
;
341
342 child_conn = conn->accepted_connections;
343 while (child_conn != NULL((void*)0)) {
344 bacon_message_connection_free (child_conn->data);
345 child_conn = g_slist_next (child_conn)((child_conn) ? (((GSList *)(child_conn))->next) : ((void*
)0))
;
346 }
347 g_slist_free (conn->accepted_connections);
348
349 if (conn->conn_id) {
350 g_source_remove (conn->conn_id);
351 conn->conn_id = 0;
352 }
353 if (conn->chan) {
354 g_io_channel_shutdown (conn->chan, FALSE(0), NULL((void*)0));
355 g_io_channel_unref (conn->chan);
356 }
357
358 if (conn->is_server != FALSE(0)) {
359 unlink (conn->path);
360 }
361 if (conn->fd != -1) {
362 close (conn->fd);
363 }
364
365 g_free (conn->path);
366 g_free (conn);
367}
368
369void
370bacon_message_connection_set_callback (BaconMessageConnection *conn,
371 BaconMessageReceivedFunc func,
372 gpointer user_data)
373{
374 g_return_if_fail (conn != NULL)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
; } } while (0)
;
375
376 conn->func = func;
377 conn->data = user_data;
378}
379
380void
381bacon_message_connection_send (BaconMessageConnection *conn,
382 const char *message)
383{
384 g_return_if_fail (conn != NULL)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
; } } while (0)
;
385 g_return_if_fail (message != NULL)do { if ((message != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "message != NULL"
); return; } } while (0)
;
386
387 g_io_channel_write_chars (conn->chan, message, strlen (message),
388 NULL((void*)0), NULL((void*)0));
389 g_io_channel_write_chars (conn->chan, "\n", 1, NULL((void*)0), NULL((void*)0));
390 g_io_channel_flush (conn->chan, NULL((void*)0));
391}
392
393gboolean
394bacon_message_connection_get_is_server (BaconMessageConnection *conn)
395{
396 g_return_val_if_fail (conn != NULL, FALSE)do { if ((conn != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "conn != NULL"); return
((0)); } } while (0)
;
397
398 return conn->is_server;
399}
400