android_kernel_google_msm/scripts
David Brown 137d1b2b4c checkpatch: strlen and strcmp should not be banned
Software security is an important issue, in general, but it is
especially important in Linux kernel code.  Buffer overflows can have
wide-reaching ramifications and can often be readily exploited to
compromise the entire system.  It is important for every developer to
be aware of security issues while writing code.

However, I've noticed a few "rules" about coding that are resulting in
code that isn't any more secure, and has the disadvantage of obscuring
what the code is doing.  In most instances, the "corrected" code is
actually wrong: we've traded a perceived lack of safety for incorrect
behavior.  These obfuscations also make this code more distant from
upstream kernel standards.

I'm only going to focus here on strcmp/strncmp and strlen/strnlen.  I
choose these two, because in the context of the kernel, it's not easy
to make a general rule, such as "always use the 'n' variant".  These
function have different behavior, and the 'n' isn't just a blanket fix
that makes them better.  In many instances, the correct call is the
plain variant (strcpy has a strlcpy variant which is usually helpful).

Let's start with strlen/strnlen.

	size_t strlen(const char *);
	size_t strnlen(const char *, size_t);

The strlen() function scans for a NUL byte within a string, and
returns the number of characters that had to be skipped to get there.

The strnlen() call is similar, but will stop after after a maximal
number of characters, and return that result.  This variant was
intended for storing variable length strings in fixed-sized buffers,
where the full-length case did not have a trailing NUL.  This storage
model is very uncommon, as is the use of strnlen().

The question becomes, what is the maximal length you should be giving
to strnlen().  If the string is truly variable length (allocated and
filled), there really isn't a meaningful value to use for this.  The
only time that a max length makes sense is when you have something
like:

	char name[MAX_NAME_LENGTH];

but, in this case, strnlen() is still probably not what you want to be
using.  It would be safe to use, if you check the result, and if it is
MAX_NAME_LENGTH, raise some kind of error case.  If later code assumes
there is a NUL at the end, there will still be a buffer overflow.  In
this case, it is much better to check the length before storing it in
this field, and make sure there is room for the NUL.

If the string is a constant, passing in a length doesn't make sense,
since you would have to know the length of the string to check that.
There is no safety issue with calling strlen() on a constant.

So, the simple rule for strnlen()/strlen() is:

  - If the string doesn't have an obvious bound length, such as an
    allocated string, use strlen().

  - If the string is a constant, use strlen().

  - If there is a fixed buffer, strnlen() might make sense, but it is
    probably better to change the design to avoid these types of
    strings.

The only case where strnlen really makes sense is when you have a
string that is passed in from the user.  In this case, it is very
important to check the result, and if the length is at the maximum,
return an error, and don't try to do any processing on the string.

Moving on to strcmp/strncmp.  These functions are similar, except that
they take two string arguments, which gives a lot more combinations.

	int strcmp(const char *, const char *);
	int strncmp(const char *, const char *, size_t);

These will walk both strings (at the same time), and stop when
reaching the first difference between them.  This means that they will
never go further than the length of the shortest string being
compared.  As in strnlen, the max argument to strncmp sets a limit on
the comparison.  Similar to strnlen, the results are unusual when the
limit is reached, but in a sense, even worse, since it may consider
the strings equal without ever reaching the end of either.

Looking over the 200 some uses of strncmp in the msm code, almost all
of them do something akin to:

	strncmp(value, constant, strlen(constant))

If the call has added 1 to the 'strlen' result, the strncmp would just
become an inefficient, but otherwise identical version of strcmp.
However, without the +1, this compares the prefix of 'value' instead
of the entire string.  Only one instance of strncmp in the code
appears to be intentionally checking for a prefix.  The rest have
changed a simple string compare into an unintentional prefix match.

Because there are two strings, it is a little more complex to
determine which to use, but it is very similar.  It might seem that
strncmp() would be useful for checking an unknown buffer (say from
userspace).  However, since strncmp()'s result doesn't distinguish
between finding the end of the string, or hitting the max, there's no
way to know.  Some guidelines:

  - If one of the strings has a known bound length (such as a
    constant, or another string whose length has already been
    checked), AND this bound length is within the expected buffer of
    the other string, it is safe to use strcmp().

  - Otherwise, you may need to use something like strnlen() to
    determine a maximum length before calling strcmp().

  - strncmp() is useful to test a string for a prefix.  No other uses
    make sense.

To facilitate fixing these, remove strlen(), strcmp(), and
strcasecmp() from the list of calls that are banned.  Problems with
these calls need to be caught at a higher level (such as review), and
replacing them with the 'n' variants doesn't help anything.

This will be followed by some patches that fixup the incorrect code
introduced by this "ban".

Change-Id: I77dfe1f2f58e8c951e4b38b23f4ec79f8209b1dc
Signed-off-by: David Brown <davidb@codeaurora.org>
2013-02-27 18:19:30 -08:00
..
basic
coccinelle Merge branch 'akpm' (Andrew's patch-bomb) 2012-04-05 15:30:34 -07:00
dtc scripts: dtc: fix compile warnings 2012-03-24 23:07:35 +01:00
genksyms scripts/genksyms: clean lex/yacc generated files 2012-01-08 14:48:15 +01:00
kconfig kconfig: delete last traces of __enabled_ from autoconf.h 2012-04-12 18:35:58 -07:00
ksymoops
mod modpost: Make verbose mismatches errors 2013-02-20 02:49:31 -08:00
package kbuild: Fix out-of-tree build for 'make deb-pkg' 2012-02-25 00:01:28 +01:00
rt-tester
selinux
tracing
.gitignore
bin2c.c
bloat-o-meter
bootgraph.pl
build-all.py scripts: Include copper pattern in build targets 2013-02-20 02:49:45 -08:00
checkincludes.pl
checkkconfigsymbols.sh
checkpatch.pl checkpatch: strlen and strcmp should not be banned 2013-02-27 18:19:30 -08:00
checkstack.pl
checksyscalls.sh checksyscalls: Use arch/x86/syscalls/syscall_32.tbl as source 2011-11-17 13:35:37 -08:00
checkversion.pl
cleanfile
cleanpatch
coccicheck coccicheck: change handling of C={1,2} when M= is set 2012-02-24 23:50:19 +01:00
config
conmakehash.c
decodecode
depmod.sh kbuild: do not check for ancient modutils tools 2012-01-23 15:12:19 +01:00
diffconfig
docproc.c
export_report.pl
extract-ikconfig
extract-vmlinux
gcc-goto.sh ARM: 7333/2: jump label: detect %c support for ARM 2012-03-24 09:38:56 +00:00
gcc-version.sh
gcc-wrapper.py scripts: gcc-wrapper: Add an allowed warning for alignment.c 2013-02-20 02:49:38 -08:00
gcc-x86_32-has-stack-protector.sh
gcc-x86_64-has-stack-protector.sh
gen_initramfs_list.sh
get_maintainer.pl get_maintainer.pl: add support for moderated lists 2012-03-23 16:58:32 -07:00
gfp-translate
headerdep.pl
headers.sh kbuild, headers.sh: Don't make archheaders explicitly 2011-11-22 14:47:50 -08:00
headers_check.pl headers_check: recursively search for linux/types.h inclusion 2012-03-26 14:54:27 +02:00
headers_install.pl
kallsyms.c
Kbuild.include scripts/Kbuild.include: Fix portability problem of "echo -e" 2012-03-24 23:32:05 +01:00
kernel-doc scripts/kernel-doc: fix fatal error caused by cfg80211.h 2012-01-23 08:44:53 -08:00
Lindent
Makefile x86, realmode: 16-bit real-mode code support for relocs tool 2012-05-18 19:49:40 -07:00
Makefile.asm-generic
Makefile.build kbuild: disable -Wmissing-field-initializers for W=1 2012-01-26 11:07:26 +01:00
Makefile.clean
Makefile.fwinst
Makefile.headersinst kbuild: Add support for installing generated asm headers 2011-11-17 13:14:36 -08:00
Makefile.help
Makefile.host
Makefile.lib Kbuild: centralize MKIMAGE and cmd_uimage definitions 2012-03-26 15:49:20 +02:00
Makefile.modbuiltin
Makefile.modinst
Makefile.modpost modpost: Make section mismatches an error 2013-02-20 02:49:31 -08:00
makelst
markup_oops.pl
mkcompile_h
mkmakefile
mksysmap
mkuboot.sh
mkversion
module-common.lds
namespace.pl
patch-kernel scripts/patch-kernel: digest kernel.org hosted .xz patches 2012-03-30 15:23:36 +02:00
pnmtologo.c
profile2linkerlist.pl
recordmcount.c
recordmcount.h recordmcount: Fix handling of elf64 big-endian objects. 2012-01-06 17:06:42 -05:00
recordmcount.pl
setlocalversion setlocalversion: Fix version when built/synced on a tag 2013-02-20 02:49:33 -08:00
show_delta
tags.sh Subject: [PATCH] tags.sh: Add missing quotes 2012-04-02 11:28:17 +02:00
unifdef.c
ver_linux
xz_wrap.sh xz: Enable BCJ filters on SPARC and 32-bit x86 2012-04-18 13:13:18 -07:00