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