public inbox for smatch@vger.kernel.org
 help / color / mirror / Atom feed
* alloc_page leaks tracing
@ 2022-03-08 17:28 Oleg Drokin
  2022-03-10  9:42 ` Dan Carpenter
  0 siblings, 1 reply; 5+ messages in thread
From: Oleg Drokin @ 2022-03-08 17:28 UTC (permalink / raw)
  To: smatch

Hello!

   I am wondering why alloc_page and friends are not considering an allocation function?
   Found a bit of code where there was an obvious alloc_page leak that was not caught that is caught if I change alloc_page to kmalloc.

   And while trying to put the support into smatch I suddenly found the structure changed so much from the previous time I looked at it it’s very non-obvious how to add it.

   I tried adding hooks in check_free_strict.c, check_frees_argument.c, check_leaks.c, smatch_constraints_required.c, smatch_fresh_alloc.c, smatch_parse_call_math.c
  and tried to insert it alongside kmalloc in smatch_scripts/gen_allocation_list.sh and I still cannot make
   it work in the actual kernel code even though a modified testcase from validation/sm_memory.c works.


   Any hint?

   Thanks.

Bye,
   Oleg

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: alloc_page leaks tracing
  2022-03-08 17:28 alloc_page leaks tracing Oleg Drokin
@ 2022-03-10  9:42 ` Dan Carpenter
       [not found]   ` <82B7079C-AD17-4E5E-A245-71E9ED53E5A3@linuxhacker.ru>
  0 siblings, 1 reply; 5+ messages in thread
From: Dan Carpenter @ 2022-03-10  9:42 UTC (permalink / raw)
  To: Oleg Drokin; +Cc: smatch

On Tue, Mar 08, 2022 at 12:28:59PM -0500, Oleg Drokin wrote:
> Hello!
> 
>    I am wondering why alloc_page and friends are not considering an allocation function?
>    Found a bit of code where there was an obvious alloc_page leak that was not caught that is caught if I change alloc_page to kmalloc.
> 
>    And while trying to put the support into smatch I suddenly found the structure changed so much from the previous time I looked at it it’s very non-obvious how to add it.
> 
>    I tried adding hooks in check_free_strict.c, check_frees_argument.c, check_leaks.c, smatch_constraints_required.c, smatch_fresh_alloc.c, smatch_parse_call_math.c
>   and tried to insert it alongside kmalloc in smatch_scripts/gen_allocation_list.sh and I still cannot make
>    it work in the actual kernel code even though a modified testcase from validation/sm_memory.c works.
> 
> 
>    Any hint?

The check_leaks.c function is really limitted in the type of leaks it
looks for.  It has basically no false positives, but misses 90% of bugs.

If you're looking for leaks the right place to add it is probably in
check_unwind.c.

regards,
dan carpenter

diff --git a/check_unwind.c b/check_unwind.c
index 569792ad5a57..7ef040d2ca59 100644
--- a/check_unwind.c
+++ b/check_unwind.c
@@ -92,6 +92,10 @@ static struct ref_func_info func_table[] = {
 
 	{ "ieee80211_alloc_hw", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
 	{ "ieee80211_free_hw",  RELEASE, 0, "$" },
+
+	{ "alloc_pages", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "__get_free_pages", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "free_pages", RELEASE, 0, "$" },
 };
 
 static struct smatch_state *unmatched_state(struct sm_state *sm)

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: alloc_page leaks tracing
       [not found]   ` <82B7079C-AD17-4E5E-A245-71E9ED53E5A3@linuxhacker.ru>
@ 2022-03-11 21:12     ` Dan Carpenter
  2022-03-22  8:05       ` Dan Carpenter
  0 siblings, 1 reply; 5+ messages in thread
From: Dan Carpenter @ 2022-03-11 21:12 UTC (permalink / raw)
  To: Oleg Drokin; +Cc: smatch

On Thu, Mar 10, 2022 at 04:30:42PM -0500, Oleg Drokin wrote:
> 
> Thanks, I added this and there’s still no detection.
> Example code:
> 
>         __page = alloc_page(GFP_KERNEL);
>         if (__page == NULL)
>                 return -ENOMEM;
> 
>         req = cfs_crypto_hash_init(cfs_alg, NULL, 0);
>         if (IS_ERR(req)) {
>                 CERROR("%s: unable to initialize checksum hash %s\n",
>                        tgt_name(tgt), cfs_crypto_hash_name(cfs_alg));
>                 return PTR_ERR(req);
>         }
> 
>         buffer = kmap(__page);
> 
> 
> diff --git a/check_unwind.c b/check_unwind.c
> index 569792ad..7611f377 100644
> --- a/check_unwind.c
> +++ b/check_unwind.c
> @@ -92,6 +92,11 @@ static struct ref_func_info func_table[] = {
>  
>         { "ieee80211_alloc_hw", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
>         { "ieee80211_free_hw",  RELEASE, 0, "$" },
> +       { "alloc_pages", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
> +       { "alloc_page", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
> +       { "__get_free_pages", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
> +       { "free_pages", RELEASE, 0, "$" },
> +       { "__free_page", RELEASE, 0, "$" },
>  };

Hey Oleg,

Sorry, I should have tested this better...

There are two issues.  The easy issue is that apparently I didn't stop
to consider error pointers as a failure return.

The more complicated problem is that the allocation hook will only
trigger for cases where Smatch knows what the return is.  Right now
Smatch knows that alloc_pages either returns NULL, or non-NULL (but
potentially error pointers).  This is return_implies_param_key_exact()
vs return_implies_param_key().

Of course, I changed it to _exact() deliberately to silence false
positives.  I don't remember the details so I'll retest tonight and look
again on Monday.

An easy "fix" would be to add "alloc_pages 1-u64max 4096-ptr_max" so it
gets hardcoded on the next db rebuild, but that's kind of a hack as
well.

diff --git a/check_unwind.c b/check_unwind.c
index 569792ad5a57..c3015cca3374 100644
--- a/check_unwind.c
+++ b/check_unwind.c
@@ -92,6 +92,10 @@ static struct ref_func_info func_table[] = {
 
 	{ "ieee80211_alloc_hw", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
 	{ "ieee80211_free_hw",  RELEASE, 0, "$" },
+
+	{ "alloc_pages", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "__get_free_pages", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "free_pages", RELEASE, 0, "$" },
 };
 
 static struct smatch_state *unmatched_state(struct sm_state *sm)
@@ -237,11 +241,14 @@ enum {
 static int success_fail_positive(struct range_list *rl)
 {
 	if (!rl)
-		return UNKNOWN;
+		return SUCCESS;
 
 	if (sval_is_negative(rl_min(rl)) && sval_is_negative(rl_max(rl)))
 		return FAIL;
 
+	if (type_is_ptr(rl_type(rl)) && is_err_or_null(rl))
+		return FAIL;
+
 	if (rl_min(rl).value == 0)
 		return SUCCESS;
 
@@ -334,7 +341,7 @@ void check_unwind(int id)
 		if (info->call_back) {
 			add_function_hook(info->name, info->call_back, info);
 		} else if (info->implies_start && info->type == ALLOC) {
-			return_implies_param_key_exact(info->name,
+			return_implies_param_key(info->name,
 					*info->implies_start,
 					*info->implies_end,
 					&return_param_alloc,

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: alloc_page leaks tracing
  2022-03-11 21:12     ` Dan Carpenter
@ 2022-03-22  8:05       ` Dan Carpenter
  2022-03-25  6:48         ` Dan Carpenter
  0 siblings, 1 reply; 5+ messages in thread
From: Dan Carpenter @ 2022-03-22  8:05 UTC (permalink / raw)
  To: Oleg Drokin; +Cc: smatch

I've pushed some changes to the check_unwind.c script so now the results
say which function allocated it.

I still haven't added the alloc_pages() and related functions to the
function table.  I need to do that.  I'm also still thinking about the
correct solution to the return_implies_param_key_exact() problem.  I
guess on my system, I just hardcoded the return values.  There is no
harm in pushing that so let me do that.

There are bunch of common false positives like:
1) put_device() frees the page.  I've been sort of working towards
   making put_device() handled in the correct way where we figure out
   what function it calls and parse the container_of() correctly and
   then it's all handled transparently by the check_kernel.c.  But for
   now probably the right thing is to add a special case to
   check_unwind.c.
2) Arrays.  Again, probably add a special case in check_unwind.c
3) Direct calls to a function which frees pointers from container_of().
   Eventually this will work correctly.  Another option for this would
   be to do what check_locking does and just record whenever a function
   frees something and then in the caller try to guess which resource
   it was based on the name.

So there is quite a bit of work which can be done still.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: alloc_page leaks tracing
  2022-03-22  8:05       ` Dan Carpenter
@ 2022-03-25  6:48         ` Dan Carpenter
  0 siblings, 0 replies; 5+ messages in thread
From: Dan Carpenter @ 2022-03-25  6:48 UTC (permalink / raw)
  To: Oleg Drokin; +Cc: smatch

Another option to free the page is put_page() right?

To me it looks like r5l_recovery_verify_data_checksum_for_mb() should
use free_page() but put_page() also works I think.  My understanding is
that you could swap all the free_page() calls for put_page() but not the
other way round.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-03-25  6:50 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-03-08 17:28 alloc_page leaks tracing Oleg Drokin
2022-03-10  9:42 ` Dan Carpenter
     [not found]   ` <82B7079C-AD17-4E5E-A245-71E9ED53E5A3@linuxhacker.ru>
2022-03-11 21:12     ` Dan Carpenter
2022-03-22  8:05       ` Dan Carpenter
2022-03-25  6:48         ` Dan Carpenter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox