]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
analyzer: use std::unique_ptr for known functions
[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"
accece8c 45#include "make-unique.h"
c81b60b8
DM
46
47int plugin_is_GPL_compatible;
48
49#if ENABLE_ANALYZER
50
51namespace ana {
52
53/* Implementation of "copy_from_user" and "copy_to_user". */
54
55class copy_across_boundary_fn : public known_function
56{
57 public:
58 virtual bool untrusted_source_p () const = 0;
59 virtual bool untrusted_destination_p () const = 0;
60
61 void impl_call_pre (const call_details &cd) const final override
62 {
63 region_model_manager *mgr = cd.get_manager ();
64 region_model *model = cd.get_model ();
65 region_model_context *ctxt = cd.get_ctxt ();
66
67 const svalue *dest_sval = cd.get_arg_svalue (0);
68 const svalue *src_sval = cd.get_arg_svalue (1);
69 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
70
71 const region *dest_reg = model->deref_rvalue (dest_sval,
72 cd.get_arg_tree (0),
73 ctxt);
74 const region *src_reg = model->deref_rvalue (src_sval,
75 cd.get_arg_tree (1),
76 ctxt);
77 if (const svalue *bounded_sval
78 = model->maybe_get_copy_bounds (src_reg, num_bytes_sval))
79 num_bytes_sval = bounded_sval;
80
81 if (tree cst = num_bytes_sval->maybe_get_constant ())
82 if (zerop (cst))
83 /* No-op. */
84 return;
85
86 const region *sized_src_reg = mgr->get_sized_region (src_reg,
87 NULL_TREE,
88 num_bytes_sval);
89
90 const svalue *copied_sval
91 = model->get_store_value (sized_src_reg, ctxt);
92 const region *sized_dest_reg = mgr->get_sized_region (dest_reg,
93 NULL_TREE,
94 num_bytes_sval);
95
96 if (ctxt)
97 {
98 /* Bifurcate state, creating a "failure" out-edge. */
accece8c 99 ctxt->bifurcate (make_unique<copy_failure> (cd));
c81b60b8
DM
100
101 /* The "unbifurcated" state is the "success" case. */
102 copy_success success (cd,
103 sized_dest_reg,
104 copied_sval,
105 sized_src_reg,
106 untrusted_source_p (),
107 untrusted_destination_p ());
108 success.update_model (model, NULL, ctxt);
109 }
110 }
111
112 private:
113 class copy_success : public success_call_info
114 {
115 public:
116 copy_success (const call_details &cd,
117 const region *sized_dest_reg,
118 const svalue *copied_sval,
119 const region *sized_src_reg,
120 bool untrusted_source,
121 bool untrusted_destination)
122 : success_call_info (cd),
123 m_sized_dest_reg (sized_dest_reg),
124 m_copied_sval (copied_sval),
125 m_sized_src_reg (sized_src_reg),
126 m_untrusted_source (untrusted_source),
127 m_untrusted_destination (untrusted_destination)
128 {}
129
130 bool update_model (region_model *model,
131 const exploded_edge *,
132 region_model_context *ctxt) const final override
133 {
134 call_details cd (get_call_details (model, ctxt));
135 model->update_for_zero_return (cd, true);
136 model->set_value (m_sized_dest_reg, m_copied_sval, ctxt);
137 if (ctxt && m_untrusted_source)
138 model->mark_as_tainted (m_copied_sval, ctxt);
139 if (m_untrusted_destination)
140 model->maybe_complain_about_infoleak (m_sized_dest_reg,
141 m_copied_sval,
142 m_sized_src_reg,
143 ctxt);
144 return true;
145 }
146
147 const region *m_sized_dest_reg;
148 const svalue *m_copied_sval;
149 const region *m_sized_src_reg;
150 bool m_untrusted_source;
151 bool m_untrusted_destination;
152 };
153
154 class copy_failure : public failed_call_info
155 {
156 public:
157 copy_failure (const call_details &cd)
158 : failed_call_info (cd)
159 {}
160
161 bool update_model (region_model *model,
162 const exploded_edge *,
163 region_model_context *ctxt) const final override
164 {
165 call_details cd (get_call_details (model, ctxt));
166 model->update_for_nonzero_return (cd);
167 /* Leave the destination region untouched. */
168 return true;
169 }
170 };
171};
172
173/* "copy_from_user". */
174
175class known_function_copy_from_user : public copy_across_boundary_fn
176{
177public:
178 bool untrusted_source_p () const final override
179 {
180 return true;
181 }
182 bool untrusted_destination_p () const final override
183 {
184 return false;
185 }
186};
187
188/* "copy_to_user". */
189
190class known_function_copy_to_user : public copy_across_boundary_fn
191{
192public:
193 bool untrusted_source_p () const final override
194 {
195 return false;
196 }
197 bool untrusted_destination_p () const final override
198 {
199 return true;
200 }
201};
202
203/* Callback handler for the PLUGIN_ANALYZER_INIT event. */
204
205static void
206kernel_analyzer_init_cb (void *gcc_data, void */*user_data*/)
207{
208 ana::plugin_analyzer_init_iface *iface
209 = (ana::plugin_analyzer_init_iface *)gcc_data;
210 LOG_SCOPE (iface->get_logger ());
211 if (0)
212 inform (input_location, "got here: kernel_analyzer_init_cb");
76dd2c4f
DM
213 iface->register_known_function
214 ("copy_from_user",
215 make_unique<known_function_copy_from_user> ());
c81b60b8 216 iface->register_known_function ("copy_to_user",
76dd2c4f 217 make_unique<known_function_copy_to_user> ());
c81b60b8
DM
218}
219
220} // namespace ana
221
222#endif /* #if ENABLE_ANALYZER */
223
224int
225plugin_init (struct plugin_name_args *plugin_info,
226 struct plugin_gcc_version *version)
227{
228#if ENABLE_ANALYZER
229 const char *plugin_name = plugin_info->base_name;
230 if (0)
231 inform (input_location, "got here; %qs", plugin_name);
232 register_callback (plugin_info->base_name,
233 PLUGIN_ANALYZER_INIT,
234 ana::kernel_analyzer_init_cb,
235 NULL); /* void *user_data */
236#else
237 sorry_no_analyzer ();
238#endif
239 return 0;
240}