[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [XEN RFC] x86/uaccess: remove __{put,get}_user_bad()



On Fri, 5 Jan 2024, Federico Serafini wrote:
> Hello everyone,
> 
> On 21/12/23 13:41, Jan Beulich wrote:
> > On 21.12.2023 13:01, Nicola Vetrini wrote:
> > > Hi Andrew,
> > > 
> > > On 2023-12-21 12:03, Andrew Cooper wrote:
> > > > On 21/12/2023 10:58 am, Jan Beulich wrote:
> > > > > On 21.12.2023 11:53, Federico Serafini wrote:
> > > > > > Remove declarations of __put_user_bad() and __get_user_bad()
> > > > > > since they have no definition.
> > > > > > Replace their uses with a break statement to address violations of
> > > > > > MISRA C:2012 Rule 16.3 ("An unconditional `break' statement shall
> > > > > > terminate every switch-clause").
> > > > > > No functional change.
> > > > > > 
> > > > > > Signed-off-by: Federico Serafini <federico.serafini@xxxxxxxxxxx>
> > > > > > ---
> > > > > > Several violations of Rule 16.3 come from uses of macros
> > > > > > get_unsafe_size() and put_unsafe_size().
> > > > > > Looking at the macro definitions I found __get_user_bad() and
> > > > > > __put_user_bad().
> > > > > > I was wondering if instead of just adding the break statement I can
> > > > > > also remove
> > > > > > such functions which seem to not have a definition.
> > > > > No, you can't. Try introducing a caller which "accidentally" uses the
> > > > > wrong size. Without your change you'll observe the build failing (in
> > > > > a somewhat obscure way, but still), while with your change bad code
> > > > > will silently be generated.
> > > > 
> > > > The construct here is deliberate.  It's a build time assertion that bad
> > > > sizes aren't used.
> > > > 
> > > > __bitop_bad_size() and __xsm_action_mismatch_detected() are the same
> > > > pattern in other areas of code too, with the latter being more explicit
> > > > because of how it's wrapped by LINKER_BUG_ON().
> > > > 
> > > > 
> > > > It is slightly horrible, and not the most obvious construct for
> > > > newcomers.  If there's an alternative way to get a build assertion, we
> > > > could consider switching to a new pattern.
> > > 
> > > would you be in favour of a solution with a BUILD_BUG_ON in the default
> > > branch followed by a break?
> > > 
> > > default:
> > >       BUILD_BUG_ON(!size || size >=8 || (size & (size - 1)));
> > >       break;
> > 
> > I don't think this would compile - BUILD_BUG_ON() wants a compile-time
> > constant passed.
> 
> What do you think about adding the following macro to compiler.h:
> 
> #define static_assert_unreachable(identifier) \
>     asm("unreachable " #identifier " reached")
> 
> It expands to an invalid assembly instruction that will lead to a
> customizable error message generated by the assembler instead of the
> linker (anticipating the error detection).
> 
> The use of this macro will indicate a program point considered
> unreachable (and as such removed) by the static analysis performed by the
> compiler, even at an optimization level -O0.
> 
> An example of use is in the default case of put_unsafe_size():
> 
> default: static_assert_unreachable(default);
> 
> In case a wrong size will be used, the following message will be
> generated:
> 
> ./arch/x86/include/asm/uaccess.h: Assembler messages:
> ./arch/x86/include/asm/uaccess.h:257: Error: no such instruction: `unreachable
> default reached'
> 
> 
> Note that adopting the macro and discussing its definition are two
> separate things:
> I think we can all agree on the fact that the use of such macro improves
> readability, so I would suggest its adoption.
> Whereas for its definition, if you don't like the invalid asm
> instruction, we could discuss for a different solution, for example,
> the following is something similar to what you are doing now:
> 
> #define static_assert_unreachable(identifier) \
>     extern void identifier(void);             \
>     identifier()
> 
> 
> Note also that the problem of the missing break statement (that violates
> Rule 16.3) is still present, it could be addressed by adding the break
> or deviating for such special cases, do you have any preferences?

So overall for clarity you are suggesting:


diff --git a/xen/arch/x86/include/asm/uaccess.h 
b/xen/arch/x86/include/asm/uaccess.h
index 7443519d5b..7e7ef77e49 100644
--- a/xen/arch/x86/include/asm/uaccess.h
+++ b/xen/arch/x86/include/asm/uaccess.h
@@ -208,7 +205,9 @@ do {                                                        
               \
     case 8:                                                                \
         put_unsafe_asm(x, ptr, grd, retval, "q",  "", "ir", errret);       \
         break;                                                             \
-    default: __put_user_bad();                                             \
+    default:                                                               \
+        static_assert_unreachable(default);                                \
+        break;                                                             \
     }                                                                      \
     clac();                                                                \
 } while ( false )


I prefer static_assert_unreachable(default) over __put_user_bad()
because it is even clearer about its intent and still generates a
build-time error.

Regarding the addition of the break, I think that's OK for me. But I am
guessing that Jan will prefer to add static_assert_unreachable to
docs/misra/deviations.rst like we did for BUG() so that we don't need to
add the break.

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.