1 /* Modeling API uses and misuses via state machines.
2    Copyright (C) 2019-2021 Free Software Foundation, Inc.
3    Contributed by David Malcolm <dmalcolm@redhat.com>.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #ifndef GCC_ANALYZER_SM_H
22 #define GCC_ANALYZER_SM_H
23 
24 /* Utility functions for use by state machines.  */
25 
26 namespace ana {
27 
28 class state_machine;
29 class sm_context;
30 class pending_diagnostic;
31 
32 extern bool any_pointer_p (tree expr);
33 extern bool any_pointer_p (const svalue *sval);
34 
35 /* An abstract base class for a state machine describing an API.
36    Manages a set of state objects, and has various virtual functions
37    for pattern-matching on statements.  */
38 
39 class state_machine : public log_user
40 {
41 public:
42   /* States are represented by immutable objects, owned by the state
43      machine.  */
44   class state
45   {
46   public:
state(const char * name,unsigned id)47     state (const char *name, unsigned id) : m_name (name), m_id (id) {}
~state()48     virtual ~state () {}
49 
get_name()50     const char *get_name () const { return m_name; }
51     virtual void dump_to_pp (pretty_printer *pp) const;
52     virtual json::value *to_json () const;
53 
get_id()54     unsigned get_id () const { return m_id; }
55 
56   private:
57     const char *m_name;
58     unsigned m_id;
59   };
60   typedef const state_machine::state *state_t;
61 
62   state_machine (const char *name, logger *logger);
~state_machine()63   virtual ~state_machine () {}
64 
65   /* Should states be inherited from a parent region to a child region,
66      when first accessing a child region?
67      For example we should inherit the taintedness of a subregion,
68      but we should not inherit the "malloc:non-null" state of a field
69      within a heap-allocated struct.  */
70   virtual bool inherited_state_p () const = 0;
71 
72   /* A vfunc for more general handling of inheritance.  */
73   virtual state_t
alt_get_inherited_state(const sm_state_map &,const svalue *,const extrinsic_state &)74   alt_get_inherited_state (const sm_state_map &,
75 			   const svalue *,
76 			   const extrinsic_state &) const
77   {
78     return NULL;
79   }
80 
get_default_state(const svalue *)81   virtual state_machine::state_t get_default_state (const svalue *) const
82   {
83     return m_start;
84   }
85 
get_name()86   const char *get_name () const { return m_name; }
87 
88   state_t get_state_by_name (const char *name) const;
89 
90   /* Return true if STMT is a function call recognized by this sm.  */
91   virtual bool on_stmt (sm_context *sm_ctxt,
92 			const supernode *node,
93 			const gimple *stmt) const = 0;
94 
on_phi(sm_context * sm_ctxt ATTRIBUTE_UNUSED,const supernode * node ATTRIBUTE_UNUSED,const gphi * phi ATTRIBUTE_UNUSED,tree rhs ATTRIBUTE_UNUSED)95   virtual void on_phi (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
96 		       const supernode *node ATTRIBUTE_UNUSED,
97 		       const gphi *phi ATTRIBUTE_UNUSED,
98 		       tree rhs ATTRIBUTE_UNUSED) const
99   {
100   }
101 
on_condition(sm_context * sm_ctxt ATTRIBUTE_UNUSED,const supernode * node ATTRIBUTE_UNUSED,const gimple * stmt ATTRIBUTE_UNUSED,const svalue * lhs ATTRIBUTE_UNUSED,enum tree_code op ATTRIBUTE_UNUSED,const svalue * rhs ATTRIBUTE_UNUSED)102   virtual void on_condition (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
103 			     const supernode *node ATTRIBUTE_UNUSED,
104 			     const gimple *stmt ATTRIBUTE_UNUSED,
105 			     const svalue *lhs ATTRIBUTE_UNUSED,
106 			     enum tree_code op ATTRIBUTE_UNUSED,
107 			     const svalue *rhs ATTRIBUTE_UNUSED) const
108   {
109   }
110 
111   /* Return true if it safe to discard the given state (to help
112      when simplifying state objects).
113      States that need leak detection should return false.  */
114   virtual bool can_purge_p (state_t s) const = 0;
115 
116   /* Called when VAR leaks (and !can_purge_p).  */
on_leak(tree var ATTRIBUTE_UNUSED)117   virtual pending_diagnostic *on_leak (tree var ATTRIBUTE_UNUSED) const
118   {
119     return NULL;
120   }
121 
122   /* Return true if S should be reset to "start" for values passed (or reachable
123      from) calls to unknown functions.  IS_MUTABLE is true for pointers as
124      non-const, false if only passed as const-pointers.
125 
126      For example, in sm-malloc.cc, an on-stack ptr doesn't stop being
127      stack-allocated when passed to an unknown fn, but a malloc-ed pointer
128      could be freed when passed to an unknown fn (unless passed as "const").  */
reset_when_passed_to_unknown_fn_p(state_t s ATTRIBUTE_UNUSED,bool is_mutable)129   virtual bool reset_when_passed_to_unknown_fn_p (state_t s ATTRIBUTE_UNUSED,
130 						  bool is_mutable) const
131   {
132     return is_mutable;
133   }
134 
135   void validate (state_t s) const;
136 
137   void dump_to_pp (pretty_printer *pp) const;
138 
139   json::object *to_json () const;
140 
get_start_state()141   state_t get_start_state () const { return m_start; }
142 
143 protected:
144   state_t add_state (const char *name);
add_custom_state(state * s)145   state_t add_custom_state (state *s)
146   {
147     m_states.safe_push (s);
148     return s;
149   }
150 
alloc_state_id()151   unsigned alloc_state_id () { return m_next_state_id++; }
152 
153 private:
154   DISABLE_COPY_AND_ASSIGN (state_machine);
155 
156   const char *m_name;
157 
158   /* States are owned by the state_machine.  */
159   auto_delete_vec<state> m_states;
160 
161   unsigned m_next_state_id;
162 
163 protected:
164   /* Must be inited after m_next_state_id.  */
165   state_t m_start;
166 };
167 
168 /* Abstract base class for state machines to pass to
169    sm_context::on_custom_transition for handling non-standard transitions
170    (e.g. adding a node and edge to simulate registering a callback and having
171    the callback be called later).  */
172 
173 class custom_transition
174 {
175 public:
~custom_transition()176   virtual ~custom_transition () {}
177   virtual void impl_transition (exploded_graph *eg,
178 				exploded_node *src_enode,
179 				int sm_idx) = 0;
180 };
181 
182 /* Abstract base class giving an interface for the state machine to call
183    the checker engine, at a particular stmt.  */
184 
185 class sm_context
186 {
187 public:
~sm_context()188   virtual ~sm_context () {}
189 
190   /* Get the fndecl used at call, or NULL_TREE.
191      Use in preference to gimple_call_fndecl (and gimple_call_addr_fndecl),
192      since it can look through function pointer assignments and
193      other callback handling.  */
194   virtual tree get_fndecl_for_call (const gcall *call) = 0;
195 
196   /* Get the old state of VAR at STMT.  */
197   virtual state_machine::state_t get_state (const gimple *stmt,
198 					    tree var) = 0;
199   virtual state_machine::state_t get_state (const gimple *stmt,
200 					    const svalue *) = 0;
201   /* Set the next state of VAR to be TO, recording the "origin" of the
202      state as ORIGIN.
203      Use STMT for location information.  */
204   virtual void set_next_state (const gimple *stmt,
205 			       tree var,
206 			       state_machine::state_t to,
207 			       tree origin = NULL_TREE) = 0;
208   virtual void set_next_state (const gimple *stmt,
209 			       const svalue *var,
210 			       state_machine::state_t to,
211 			       tree origin = NULL_TREE) = 0;
212 
213   /* Called by state_machine in response to pattern matches:
214      if VAR is in state FROM, transition it to state TO, potentially
215      recording the "origin" of the state as ORIGIN.
216      Use NODE and STMT for location information.  */
217   void on_transition (const supernode *node ATTRIBUTE_UNUSED,
218 		      const gimple *stmt,
219 		      tree var,
220 		      state_machine::state_t from,
221 		      state_machine::state_t to,
222 		      tree origin = NULL_TREE)
223   {
224     state_machine::state_t current = get_state (stmt, var);
225     if (current == from)
226       set_next_state (stmt, var, to, origin);
227   }
228 
229   void on_transition (const supernode *node ATTRIBUTE_UNUSED,
230 		      const gimple *stmt,
231 		      const svalue *var,
232 		      state_machine::state_t from,
233 		      state_machine::state_t to,
234 		      tree origin = NULL_TREE)
235   {
236     state_machine::state_t current = get_state (stmt, var);
237     if (current == from)
238       set_next_state (stmt, var, to, origin);
239   }
240 
241   /* Called by state_machine in response to pattern matches:
242      issue a diagnostic D using NODE and STMT for location information.  */
243   virtual void warn (const supernode *node, const gimple *stmt,
244 		     tree var, pending_diagnostic *d) = 0;
245 
246   /* For use when generating trees when creating pending_diagnostics, so that
247      rather than e.g.
248        "double-free of '<unknown>'"
249      we can print:
250        "double-free of 'inbuf.data'".  */
get_diagnostic_tree(tree expr)251   virtual tree get_diagnostic_tree (tree expr)
252   {
253     return expr;
254   }
255   virtual tree get_diagnostic_tree (const svalue *) = 0;
256 
257   virtual state_machine::state_t get_global_state () const = 0;
258   virtual void set_global_state (state_machine::state_t) = 0;
259 
260   /* A vfunc for handling custom transitions, such as when registering
261      a signal handler.  */
262   virtual void on_custom_transition (custom_transition *transition) = 0;
263 
264   /* If STMT is an assignment known to assign zero to its LHS, return
265      the LHS.
266      Otherwise return NULL_TREE.  */
267   virtual tree is_zero_assignment (const gimple *stmt) = 0;
268 
get_path_context()269   virtual path_context *get_path_context () const
270   {
271     return NULL;
272   }
273 
274 protected:
sm_context(int sm_idx,const state_machine & sm)275   sm_context (int sm_idx, const state_machine &sm)
276   : m_sm_idx (sm_idx), m_sm (sm) {}
277 
278   int m_sm_idx;
279   const state_machine &m_sm;
280 };
281 
282 
283 /* The various state_machine subclasses are hidden in their respective
284    implementation files.  */
285 
286 extern void make_checkers (auto_delete_vec <state_machine> &out,
287 			   logger *logger);
288 
289 extern state_machine *make_malloc_state_machine (logger *logger);
290 extern state_machine *make_fileptr_state_machine (logger *logger);
291 extern state_machine *make_taint_state_machine (logger *logger);
292 extern state_machine *make_sensitive_state_machine (logger *logger);
293 extern state_machine *make_signal_state_machine (logger *logger);
294 extern state_machine *make_pattern_test_state_machine (logger *logger);
295 
296 } // namespace ana
297 
298 #endif /* GCC_ANALYZER_SM_H */
299