mirror of
https://github.com/SELinuxProject/selinux
synced 2025-04-01 23:08:09 +00:00
libselinux: enable usage with pedantic UB sanitizers
Clang's undefined behavior sanitizer supports checking for unsigned integer overflow and underflow, and implicit conversions. While those operations are well-defined by the C language they can signal logic mistakes or processing of unchecked user input. Annotate functions deliberately making use of integer overflow and adopt the remaining code sites. Example reports: stringrep.c:348:7: runtime error: left shift of 2147483648 by 1 places cannot be represented in type 'access_vector_t' (aka 'unsigned int') seusers.c:98:14: runtime error: implicit conversion from type 'int' of value -1 (32-bit, signed) to type 'gid_t' (aka 'unsigned int') changed the value to 4294967295 (32-bit, unsigned) Signed-off-by: Christian Göttsche <cgzones@googlemail.com> Acked-by: James Carter <jwcart2@gmail.com>
This commit is contained in:
parent
a1fa1c8ad7
commit
454a9f248b
@ -229,13 +229,15 @@ int avc_open(struct selinux_opt *opts, unsigned nopts)
|
||||
{
|
||||
avc_setenforce = 0;
|
||||
|
||||
while (nopts--)
|
||||
while (nopts) {
|
||||
nopts--;
|
||||
switch(opts[nopts].type) {
|
||||
case AVC_OPT_SETENFORCE:
|
||||
avc_setenforce = 1;
|
||||
avc_enforcing = !!opts[nopts].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return avc_init_internal("avc", NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "avc_sidtab.h"
|
||||
#include "avc_internal.h"
|
||||
|
||||
ignore_unsigned_overflow_
|
||||
static inline unsigned sidtab_hash(const char * key)
|
||||
{
|
||||
unsigned int hash = 5381;
|
||||
|
@ -60,7 +60,8 @@ static inline struct selabel_digest *selabel_is_digest_set
|
||||
{
|
||||
struct selabel_digest *digest = NULL;
|
||||
|
||||
while (n--) {
|
||||
while (n) {
|
||||
n--;
|
||||
if (opts[n].type == SELABEL_OPT_DIGEST &&
|
||||
!!opts[n].value) {
|
||||
digest = calloc(1, sizeof(*digest));
|
||||
@ -112,9 +113,11 @@ static void selabel_digest_fini(struct selabel_digest *ptr)
|
||||
static inline int selabel_is_validate_set(const struct selinux_opt *opts,
|
||||
unsigned n)
|
||||
{
|
||||
while (n--)
|
||||
while (n) {
|
||||
n--;
|
||||
if (opts[n].type == SELABEL_OPT_VALIDATE)
|
||||
return !!opts[n].value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -152,7 +152,8 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
struct stat sb;
|
||||
|
||||
/* Process arguments */
|
||||
while (n--)
|
||||
while (n) {
|
||||
n--;
|
||||
switch (opts[n].type) {
|
||||
case SELABEL_OPT_PATH:
|
||||
path = opts[n].value;
|
||||
@ -165,6 +166,7 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path)
|
||||
return -1;
|
||||
|
@ -263,7 +263,8 @@ db_init(const struct selinux_opt *opts, unsigned nopts,
|
||||
* the default one. If RDBMS is not SE-PostgreSQL, it may need to
|
||||
* specify an explicit specfile for database objects.
|
||||
*/
|
||||
while (nopts--) {
|
||||
while (nopts) {
|
||||
nopts--;
|
||||
switch (opts[nopts].type) {
|
||||
case SELABEL_OPT_PATH:
|
||||
path = opts[nopts].value;
|
||||
|
@ -68,7 +68,7 @@ static int find_stem_from_file(struct saved_data *data, const char *key)
|
||||
/*
|
||||
* hash calculation and key comparison of hash table
|
||||
*/
|
||||
|
||||
ignore_unsigned_overflow_
|
||||
static unsigned int symhash(hashtab_t h, const_hashtab_key_t key)
|
||||
{
|
||||
const struct chkdups_key *k = (const struct chkdups_key *)key;
|
||||
@ -801,7 +801,8 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
int status = -1, baseonly = 0;
|
||||
|
||||
/* Process arguments */
|
||||
while (n--)
|
||||
while (n) {
|
||||
n--;
|
||||
switch(opts[n].type) {
|
||||
case SELABEL_OPT_PATH:
|
||||
path = opts[n].value;
|
||||
@ -820,6 +821,7 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BUILD_HOST) && !defined(ANDROID)
|
||||
char subs_file[PATH_MAX + 1];
|
||||
|
@ -80,7 +80,8 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
struct stat sb;
|
||||
|
||||
/* Process arguments */
|
||||
while (n--)
|
||||
while (n) {
|
||||
n--;
|
||||
switch(opts[n].type) {
|
||||
case SELABEL_OPT_PATH:
|
||||
path = opts[n].value;
|
||||
@ -93,6 +94,7 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the specification file. */
|
||||
if (!path)
|
||||
|
@ -107,7 +107,8 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
struct stat sb;
|
||||
|
||||
/* Process arguments */
|
||||
while (n--)
|
||||
while (n) {
|
||||
n--;
|
||||
switch(opts[n].type) {
|
||||
case SELABEL_OPT_PATH:
|
||||
path = opts[n].value;
|
||||
@ -120,6 +121,7 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the specification file. */
|
||||
if (!path)
|
||||
|
@ -102,4 +102,15 @@ size_t strlcpy(char *dest, const char *src, size_t size);
|
||||
void *reallocarray(void *ptr, size_t nmemb, size_t size);
|
||||
#endif
|
||||
|
||||
/* Use to ignore intentional unsigned under- and overflows while running under UBSAN. */
|
||||
#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ >= 4)
|
||||
#if (__clang_major__ >= 12)
|
||||
#define ignore_unsigned_overflow_ __attribute__((no_sanitize("unsigned-integer-overflow", "unsigned-shift-base")))
|
||||
#else
|
||||
#define ignore_unsigned_overflow_ __attribute__((no_sanitize("unsigned-integer-overflow")))
|
||||
#endif
|
||||
#else
|
||||
#define ignore_unsigned_overflow_
|
||||
#endif
|
||||
|
||||
#endif /* SELINUX_INTERNAL_H_ */
|
||||
|
@ -99,7 +99,7 @@ int require_seusers = 0;
|
||||
|
||||
static gid_t get_default_gid(const char *name) {
|
||||
struct passwd pwstorage, *pwent = NULL;
|
||||
gid_t gid = -1;
|
||||
gid_t gid = (gid_t)-1;
|
||||
/* Allocate space for the getpwnam_r buffer */
|
||||
char *rbuf = NULL;
|
||||
long rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "sha1.h"
|
||||
#include <memory.h>
|
||||
|
||||
#include "selinux_internal.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TYPES
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -62,6 +64,7 @@ typedef union
|
||||
//
|
||||
// Hash a single 512-bit block. This is the core of the algorithm
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ignore_unsigned_overflow_
|
||||
static
|
||||
void
|
||||
TransformFunction
|
||||
|
@ -337,13 +337,15 @@ void print_access_vector(security_class_t tclass, access_vector_t av)
|
||||
|
||||
printf(" {");
|
||||
|
||||
while (av) {
|
||||
for (;;) {
|
||||
if (av & bit) {
|
||||
permstr = security_av_perm_to_string(tclass, bit);
|
||||
if (!permstr)
|
||||
break;
|
||||
printf(" %s", permstr);
|
||||
av &= ~bit;
|
||||
if (!av)
|
||||
break;
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user