]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
analyzer: use std::unique_ptr for pending_diagnostic/note
[thirdparty/gcc.git] / gcc / testsuite / gcc.dg / plugin / analyzer_kernel_plugin.c
CommitLineData
c81b60b8
DM
1/* Proof-of-concept of a -fanalyzer plugin for the Linux kernel. */
2/* { dg-options "-g" } */
3
6341f14e 4#define INCLUDE_MEMORY
c81b60b8
DM
5#include "gcc-plugin.h"
6#include "config.h"
7#include "system.h"
8#include "coretypes.h"
9#include "tree.h"
10#include "function.h"
11#include "basic-block.h"
12#include "gimple.h"
13#include "gimple-iterator.h"
14#include "diagnostic-core.h"
15#include "graphviz.h"
16#include "options.h"
17#include "cgraph.h"
18#include "tree-dfa.h"
19#include "stringpool.h"
20#include "convert.h"
21#include "target.h"
22#include "fold-const.h"
23#include "tree-pretty-print.h"
24#include "diagnostic-color.h"
25#include "diagnostic-metadata.h"
26#include "tristate.h"
27#include "bitmap.h"
28#include "selftest.h"
29#include "function.h"
30#include "json.h"
31#include "analyzer/analyzer.h"
32#include "analyzer/analyzer-logging.h"
33#include "ordered-hash-map.h"
34#include "options.h"
35#include "cgraph.h"
36#include "cfg.h"
37#include "digraph.h"
38#include "analyzer/supergraph.h"
39#include "sbitmap.h"
40#include "analyzer/call-string.h"
41#include "analyzer/program-point.h"
42#include "analyzer/store.h"
43#include "analyzer/region-model.h"
44#include "analyzer/call-info.h"
45
46int plugin_is_GPL_compatible;
47
48#if ENABLE_ANALYZER
49
50namespace ana {
51
52/* Implementation of "copy_from_user" and "copy_to_user". */
53
54class copy_across_boundary_fn : public known_function
55{
56 public:
57 virtual bool untrusted_source_p () const = 0;
58 virtual bool untrusted_destination_p () const = 0;
59
60 void impl_call_pre (const call_details &cd) const final override
61 {
62 region_model_manager *mgr = cd.get_manager ();
63 region_model *model = cd.get_model ();
64 region_model_context *ctxt = cd.get_ctxt ();
65
66 const svalue *dest_sval = cd.get_arg_svalue (0);
67 const svalue *src_sval = cd.get_arg_svalue (1);
68 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
69
70 const region *dest_reg = model->deref_rvalue (dest_sval,
71 cd.get_arg_tree (0),
72 ctxt);
73 const region *src_reg = model->deref_rvalue (src_sval,
74 cd.get_arg_tree (1),
75 ctxt);
76 if (const svalue *bounded_sval
77 = model->maybe_get_copy_bounds (src_reg, num_bytes_sval))
78 num_bytes_sval = bounded_sval;
79
80 if (tree cst = num_bytes_sval->maybe_get_constant ())
81 if (zerop (cst))
82 /* No-op. */
83 return;
84
85 const region *sized_src_reg = mgr->get_sized_region (src_reg,
86 NULL_TREE,
87 num_bytes_sval);
88
89 const svalue *copied_sval
90 = model->get_store_value (sized_src_reg, ctxt);
91 const region *sized_dest_reg = mgr->get_sized_region (dest_reg,
92 NULL_TREE,
93 num_bytes_sval);
94
95 if (ctxt)
96 {
97 /* Bifurcate state, creating a "failure" out-edge. */
98 ctxt->bifurcate (new copy_failure (cd));
99
100 /* The "unbifurcated" state is the "success" case. */
101 copy_success success (cd,
102 sized_dest_reg,
103 copied_sval,
104 sized_src_reg,
105 untrusted_source_p (),
106 untrusted_destination_p ());
107 success.update_model (model, NULL, ctxt);
108 }
109 }
110
111 private:
112 class copy_success : public success_call_info
113 {
114 public:
115 copy_success (const call_details &cd,
116 const region *sized_dest_reg,
117 const svalue *copied_sval,
118 const region *sized_src_reg,
119 bool untrusted_source,
120 bool untrusted_destination)
121 : success_call_info (cd),
122 m_sized_dest_reg (sized_dest_reg),
123 m_copied_sval (copied_sval),
124 m_sized_src_reg (sized_src_reg),
125 m_untrusted_source (untrusted_source),
126 m_untrusted_destination (untrusted_destination)
127 {}
128
129 bool update_model (region_model *model,
130 const exploded_edge *,
131 region_model_context *ctxt) const final override
132 {
133 call_details cd (get_call_details (model, ctxt));
134 model->update_for_zero_return (cd, true);
135 model->set_value (m_sized_dest_reg, m_copied_sval, ctxt);
136 if (ctxt && m_untrusted_source)
137 model->mark_as_tainted (m_copied_sval, ctxt);
138 if (m_untrusted_destination)
139 model->maybe_complain_about_infoleak (m_sized_dest_reg,
140 m_copied_sval,
141 m_sized_src_reg,
142 ctxt);
143 return true;
144 }
145
146 const region *m_sized_dest_reg;
147 const svalue *m_copied_sval;
148 const region *m_sized_src_reg;
149 bool m_untrusted_source;
150 bool m_untrusted_destination;
151 };
152
153 class copy_failure : public failed_call_info
154 {
155 public:
156 copy_failure (const call_details &cd)
157 : failed_call_info (cd)
158 {}
159
160 bool update_model (region_model *model,
161 const exploded_edge *,
162 region_model_context *ctxt) const final override
163 {
164 call_details cd (get_call_details (model, ctxt));
165 model->update_for_nonzero_return (cd);
166 /* Leave the destination region untouched. */
167 return true;
168 }
169 };
170};
171
172/* "copy_from_user". */
173
174class known_function_copy_from_user : public copy_across_boundary_fn
175{
176public:
177 bool untrusted_source_p () const final override
178 {
179 return true;
180 }
181 bool untrusted_destination_p () const final override
182 {
183 return false;
184 }
185};
186
187/* "copy_to_user". */
188
189class known_function_copy_to_user : public copy_across_boundary_fn
190{
191public:
192 bool untrusted_source_p () const final override
193 {
194 return false;
195 }
196 bool untrusted_destination_p () const final override
197 {
198 return true;
199 }
200};
201
202/* Callback handler for the PLUGIN_ANALYZER_INIT event. */
203
204static void
205kernel_analyzer_init_cb (void *gcc_data, void */*user_data*/)
206{
207 ana::plugin_analyzer_init_iface *iface
208 = (ana::plugin_analyzer_init_iface *)gcc_data;
209 LOG_SCOPE (iface->get_logger ());
210 if (0)
211 inform (input_location, "got here: kernel_analyzer_init_cb");
212 iface->register_known_function ("copy_from_user",
213 new known_function_copy_from_user ());
214 iface->register_known_function ("copy_to_user",
215 new known_function_copy_to_user ());
216}
217
218} // namespace ana
219
220#endif /* #if ENABLE_ANALYZER */
221
222int
223plugin_init (struct plugin_name_args *plugin_info,
224 struct plugin_gcc_version *version)
225{
226#if ENABLE_ANALYZER
227 const char *plugin_name = plugin_info->base_name;
228 if (0)
229 inform (input_location, "got here; %qs", plugin_name);
230 register_callback (plugin_info->base_name,
231 PLUGIN_ANALYZER_INIT,
232 ana::kernel_analyzer_init_cb,
233 NULL); /* void *user_data */
234#else
235 sorry_no_analyzer ();
236#endif
237 return 0;
238}