1 /*
2  * Copyright © 2020 Endless OS Foundation, LLC
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author: Philip Withnall <withnall@endlessm.com>
18  */
19 
20 /* This modelling file needs to be uploaded to GLib’s Coverity configuration at
21  * https://scan.coverity.com/projects/glib?tab=analysis_settings
22  * by someone with the appropriate permissions on Coverity. It should be kept in
23  * sync with what’s there.
24  *
25  * Reference: https://scan.coverity.com/tune
26  */
27 
28 /* Disable some esoteric options which Coverity doesn't understand because they
29  * delve into assembly. */
30 #define NVALGRIND 1
31 #undef HAVE_DTRACE
32 
33 #define TRACE(probe)  /* no-op */
34 
35 /* libc definitions */
36 #define NULL ((void*)0)
37 
38 void *malloc (size_t);
39 void *calloc (size_t, size_t);
40 void *realloc (void *, size_t);
41 void free (void *);
42 
43 /* Define some standard GLib types. */
44 typedef size_t gsize;
45 typedef char gchar;
46 typedef unsigned char guchar;
47 typedef int gint;
48 typedef unsigned long gulong;
49 typedef unsigned int guint32;
50 typedef void* gpointer;
51 typedef unsigned int gboolean;
52 
53 typedef enum
54 {
55   /* log flags */
56   G_LOG_FLAG_RECURSION          = 1 << 0,
57   G_LOG_FLAG_FATAL              = 1 << 1,
58 
59   /* GLib log levels */
60   G_LOG_LEVEL_ERROR             = 1 << 2,       /* always fatal */
61   G_LOG_LEVEL_CRITICAL          = 1 << 3,
62   G_LOG_LEVEL_WARNING           = 1 << 4,
63   G_LOG_LEVEL_MESSAGE           = 1 << 5,
64   G_LOG_LEVEL_INFO              = 1 << 6,
65   G_LOG_LEVEL_DEBUG             = 1 << 7,
66 
67   G_LOG_LEVEL_MASK              = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL)
68 } GLogLevelFlags;
69 
70 typedef struct _GList GList;
71 
72 struct _GList
73 {
74   gpointer data;
75   GList *next;
76   GList *prev;
77 };
78 
79 typedef struct _GError GError;
80 
81 struct _GError
82 {
83   /* blah */
84 };
85 
86 /* Dummied from sys/stat.h. */
87 struct stat {};
88 extern int stat (const char *path, struct stat *buf);
89 
90 /* g_stat() can be used to check whether a given path is safe (i.e. exists).
91  * This is not a full solution for sanitising user-provided paths, but goes a
92  * long way, and is the best we can do without more context about how the path
93  * is used. */
94 typedef struct stat GStatBuf;
95 #undef g_stat
96 
97 int
g_stat(const char * filename,GStatBuf * buf)98 g_stat (const char *filename, GStatBuf *buf)
99 {
100   __coverity_tainted_string_sanitize_content__ (filename);
101   return stat (filename, buf);
102 }
103 
104 /* g_path_skip_root() can be used to validate that a @file_name is absolute. It
105  * returns %NULL otherwise. */
106 const char *
g_path_skip_root(const char * file_name)107 g_path_skip_root (const char *file_name)
108 {
109   int is_ok;
110   if (is_ok)
111     {
112       __coverity_tainted_string_sanitize_content__ (file_name);
113       return file_name;
114     }
115   else
116     {
117       return 0;  /* NULL */
118     }
119 }
120 
121 /* Tainted string sanitiser. */
122 int
g_action_name_is_valid(const char * action_name)123 g_action_name_is_valid (const char *action_name)
124 {
125   int is_ok;
126   if (is_ok)
127     {
128       __coverity_tainted_string_sanitize_content__ (action_name);
129       return 1;  /* TRUE */
130     }
131   else
132     {
133       return 0;  /* FALSE */
134     }
135 }
136 
137 /* Treat this like an assert(0). */
138 void
g_return_if_fail_warning(const char * log_domain,const char * pretty_function,const char * expression)139 g_return_if_fail_warning (const char *log_domain,
140                           const char *pretty_function,
141                           const char *expression)
142 {
143   __coverity_panic__();
144 }
145 
146 /* Treat this like an assert(0). */
147 void
g_log(const gchar * log_domain,GLogLevelFlags log_level,const gchar * format,...)148 g_log (const gchar   *log_domain,
149        GLogLevelFlags log_level,
150        const gchar   *format,
151        ...)
152 {
153   if (log_level & G_LOG_LEVEL_CRITICAL)
154     __coverity_panic__ ();
155 }
156 
157 #define g_critical(...) __coverity_panic__ ();
158 
159 /* Treat it as a memory sink to hide one-time allocation leaks. */
160 void
161 (g_once_init_leave) (volatile void *location,
162                      gsize          result)
163 {
164   __coverity_escape__ (result);
165 }
166 
167 /* Coverity cannot model allocation management for linked lists, so just pretend
168  * that it's a pass-through. */
169 GList *
g_list_reverse(GList * list)170 g_list_reverse (GList *list)
171 {
172   return list;
173 }
174 
175 /* g_ascii_isspace() routinely throws data_index taint errors, saying that
176  * tainted data is being used to index g_ascii_table. This is true, but the
177  * table has defined values for all possible 8-bit indexes. */
178 gboolean
g_ascii_isspace(gchar c)179 g_ascii_isspace (gchar c)
180 {
181   int is_space;
182   __coverity_tainted_string_sink_content__ (c);
183   if (is_space)
184     return 1;
185   else
186     return 0;
187 }
188 
189 /* Coverity treats byte-swapping operations as suspicious, and taints all data
190  * which is byte-swapped (because it thinks it therefore probably comes from an
191  * external source, which is reasonable). That is not the case for checksum
192  * calculation, however.
193  *
194  * Since the definitions of these two functions depends on the host byte order,
195  * just model them as no-ops. */
196 void
md5_byte_reverse(guchar * buffer,gulong length)197 md5_byte_reverse (guchar *buffer,
198                   gulong  length)
199 {
200   /* No-op. */
201 }
202 
203 void
sha_byte_reverse(guint32 * buffer,gint length)204 sha_byte_reverse (guint32 *buffer,
205                   gint     length)
206 {
207   /* No-op. */
208 }
209 
210 /* Parse error printing does not care about sanitising the input. */
211 gchar *
g_variant_parse_error_print_context(GError * error,const gchar * source_str)212 g_variant_parse_error_print_context (GError      *error,
213                                      const gchar *source_str)
214 {
215   __coverity_tainted_data_sink__ (source_str);
216   return __coverity_alloc_nosize__ ();
217 }
218 
219 /* Coverity somehow analyses G_LIKELY(x) as sometimes meaning !x, for example
220  * when analysing g_try_realloc(). Ignore that. */
221 #define G_LIKELY(x) x
222 #define G_UNLIKELY(x) x
223 
224 typedef struct {} DIR;
225 typedef struct _GDir GDir;
226 
227 struct _GDir
228 {
229   DIR *dirp;
230 };
231 
232 /* This is a private function to libglib, and Coverity can’t peek inside it when
233  * analysing code in (say) GIO. */
234 GDir *
g_dir_new_from_dirp(gpointer dirp)235 g_dir_new_from_dirp (gpointer dirp)
236 {
237   GDir *dir;
238 
239   if (dirp == 0)
240     __coverity_panic__();
241 
242   dir = malloc (sizeof (GDir));
243   dir->dirp = dirp;
244 
245   return dir;
246 }
247