diff options
author | Andreas Schneider <asn@samba.org> | 2019-02-15 18:03:51 +0100 |
---|---|---|
committer | Andreas Schneider <asn@samba.org> | 2019-02-28 12:48:37 +0100 |
commit | a0f38b46a20b9d55bb67ce4e8d91eff8bcad0203 (patch) | |
tree | cb1ed53cbf702bb09681a0e1c4f1e410e46ce607 | |
parent | fbb37b1fbc1bab4361aac258142257d353d082d8 (diff) | |
download | nss_wrapper-a0f38b46a20b9d55bb67ce4e8d91eff8bcad0203.tar.gz nss_wrapper-a0f38b46a20b9d55bb67ce4e8d91eff8bcad0203.tar.xz nss_wrapper-a0f38b46a20b9d55bb67ce4e8d91eff8bcad0203.zip |
nwrap: Rewrite nwrap_gr_copy_r() to take memory alignment into account
Found by UndefinedSanitizer
tests/testsuite.c:288:43: runtime error: load of misaligned address
0x7fff50a89199 for type 'char *', which requires 8 byte alignment
0x7fff50a89199: note: pointer points here
79 00 78 00 00 00 00 00 00 00 00 00 fe 00 00 00 00 00 00 0c dc 8e e6 7a 7f 00 00 00 00 00 00 00
^
BUG: https://bugzilla.samba.org/show_bug.cgi?id=10667
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
-rw-r--r-- | src/nss_wrapper.c | 95 |
1 files changed, 62 insertions, 33 deletions
diff --git a/src/nss_wrapper.c b/src/nss_wrapper.c index e7dd818..f8f6ce7 100644 --- a/src/nss_wrapper.c +++ b/src/nss_wrapper.c @@ -2550,55 +2550,84 @@ static void nwrap_gr_unload(struct nwrap_cache *nwrap) static int nwrap_gr_copy_r(const struct group *src, struct group *dst, char *buf, size_t buflen, struct group **dstp) { - char *first; - char **lastm; - char *last = NULL; - off_t ofsb; - off_t ofsm; - off_t ofs; + char *p = NULL; + uintptr_t align = 0; + unsigned int gr_mem_cnt = 0; unsigned i; + size_t total_len; + size_t gr_name_len = strlen(src->gr_name) + 1; + size_t gr_passwd_len = strlen(src->gr_passwd) + 1; union { char *ptr; char **data; - } g; + } g_mem; - first = src->gr_name; - - lastm = src->gr_mem; - while (*lastm) { - last = *lastm; - lastm++; + for (i = 0; src->gr_mem[i] != NULL; i++) { + gr_mem_cnt++; } - if (last == NULL) { - last = src->gr_passwd; + /* Align the memory for storing pointers */ + align = __alignof__(char *) - ((p - (char *)0) % __alignof__(char *)); + total_len = align + + (1 + gr_mem_cnt) * sizeof(char *) + + gr_name_len + gr_passwd_len; + + if (total_len > buflen) { + errno = ERANGE; + return -1; } - while (*last) last++; + buflen -= total_len; - ofsb = PTR_DIFF(last + 1, first); - ofsm = PTR_DIFF(lastm + 1, src->gr_mem); + /* gr_mem */ + p = buf + align; + g_mem.ptr = p; + dst->gr_mem = g_mem.data; - if ((ofsb + ofsm) > (off_t) buflen) { - return ERANGE; - } + /* gr_name */ + p += (1 + gr_mem_cnt) * sizeof(char *); + dst->gr_name = p; - memcpy(buf, first, ofsb); - memcpy(buf + ofsb, src->gr_mem, ofsm); + /* gr_passwd */ + p += gr_name_len; + dst->gr_passwd = p; - ofs = PTR_DIFF(src->gr_name, first); - dst->gr_name = buf + ofs; - ofs = PTR_DIFF(src->gr_passwd, first); - dst->gr_passwd = buf + ofs; + /* gr_mem[x] */ + p += gr_passwd_len; + + /* gr_gid */ dst->gr_gid = src->gr_gid; - g.ptr = (buf + ofsb); - dst->gr_mem = g.data; - for (i=0; src->gr_mem[i]; i++) { - ofs = PTR_DIFF(src->gr_mem[i], first); - dst->gr_mem[i] = buf + ofs; + memcpy(dst->gr_name, src->gr_name, gr_name_len); + + memcpy(dst->gr_passwd, src->gr_passwd, gr_passwd_len); + + /* Set the terminating entry */ + dst->gr_mem[gr_mem_cnt] = NULL; + + /* Now add the group members content */ + total_len = 0; + for (i = 0; i < gr_mem_cnt; i++) { + size_t len = strlen(src->gr_mem[i]) + 1; + + dst->gr_mem[i] = p; + total_len += len; + p += len; } - if (dstp) { + if (total_len > buflen) { + errno = ERANGE; + return -1; + } + + for (i = 0; i < gr_mem_cnt; i++) { + size_t len = strlen(src->gr_mem[i]) + 1; + + memcpy(dst->gr_mem[i], + src->gr_mem[i], + len); + } + + if (dstp != NULL) { *dstp = dst; } |