• Kees Cook's avatar
    NFSD: Avoid clashing function prototypes · e78e274e
    Kees Cook authored
    When built with Control Flow Integrity, function prototypes between
    caller and function declaration must match. These mismatches are visible
    at compile time with the new -Wcast-function-type-strict in Clang[1].
    
    There were 97 warnings produced by NFS. For example:
    
    fs/nfsd/nfs4xdr.c:2228:17: warning: cast from '__be32 (*)(struct nfsd4_compoundargs *, struct nfsd4_access *)' (aka 'unsigned int (*)(struct nfsd4_compoundargs *, struct nfsd4_access *)') to 'nfsd4_dec' (aka 'unsigned int (*)(struct nfsd4_compoundargs *, void *)') converts to incompatible function type [-Wcast-function-type-strict]
            [OP_ACCESS]             = (nfsd4_dec)nfsd4_decode_access,
                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    The enc/dec callbacks were defined as passing "void *" as the second
    argument, but were being implicitly cast to a new type. Replace the
    argument with union nfsd4_op_u, and perform explicit member selection
    in the function body. There are no resulting binary differences.
    
    Changes were made mechanically using the following Coccinelle script,
    with minor by-hand fixes for members that didn't already match their
    existing argument name:
    
    @find@
    identifier func;
    type T, opsT;
    identifier ops, N;
    @@
    
     opsT ops[] = {
    	[N] = (T) func,
     };
    
    @already_void@
    identifier find.func;
    identifier name;
    @@
    
     func(...,
    -void
    +union nfsd4_op_u
     *name)
     {
    	...
     }
    
    @proto depends on !already_void@
    identifier find.func;
    type T;
    identifier name;
    position p;
    @@
    
     func@p(...,
     	T name
     ) {
    	...
       }
    
    @script:python get_member@
    type_name << proto.T;
    member;
    @@
    
    coccinelle.member = cocci.make_ident(type_name.split("_", 1)[1].split(' ',1)[0])
    
    @convert@
    identifier find.func;
    type proto.T;
    identifier proto.name;
    position proto.p;
    identifier get_member.member;
    @@
    
     func@p(...,
    -	T name
    +	union nfsd4_op_u *u
     ) {
    +	T name = &u->member;
    	...
       }
    
    @cast@
    identifier find.func;
    type T, opsT;
    identifier ops, N;
    @@
    
     opsT ops[] = {
    	[N] =
    -	(T)
    	func,
     };
    
    Cc: Chuck Lever <chuck.lever@oracle.com>
    Cc: Jeff Layton <jlayton@kernel.org>
    Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
    Cc: linux-nfs@vger.kernel.org
    Signed-off-by: default avatarKees Cook <keescook@chromium.org>
    Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
    e78e274e
nfs4xdr.c 141 KB