Commit 9fc205b4 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Daniel Borkmann

libbpf: Add sane strncpy alternative and use it internally

strncpy() has a notoriously error-prone semantics which makes GCC
complain about it a lot (and quite often completely completely falsely
at that). Instead of pleasing GCC all the time (-Wno-stringop-truncation
is unfortunately only supported by GCC, so it's a bit too messy to just
enable it in Makefile), add libbpf-internal libbpf_strlcpy() helper
which follows what FreeBSD's strlcpy() does and what most people would
expect from strncpy(): copies up to N-1 first bytes from source string
into destination string and ensures zero-termination afterwards.

Replace all the relevant uses of strncpy/strncat/memcpy in libbpf with
libbpf_strlcpy().

This also fixes the issue reported by Emmanuel Deloget in xsk.c where
memcpy() could access source string beyond its end.

Fixes: 2f6324a3 (libbpf: Support shared umems between queues and devices)
Reported-by: default avatarEmmanuel Deloget <emmanuel.deloget@eho.link>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20211211004043.2374068-1-andrii@kernel.org
parent 4581e676
...@@ -112,7 +112,7 @@ int bpf_map_create(enum bpf_map_type map_type, ...@@ -112,7 +112,7 @@ int bpf_map_create(enum bpf_map_type map_type,
attr.map_type = map_type; attr.map_type = map_type;
if (map_name) if (map_name)
strncat(attr.map_name, map_name, sizeof(attr.map_name) - 1); libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
attr.key_size = key_size; attr.key_size = key_size;
attr.value_size = value_size; attr.value_size = value_size;
attr.max_entries = max_entries; attr.max_entries = max_entries;
...@@ -271,7 +271,7 @@ int bpf_prog_load_v0_6_0(enum bpf_prog_type prog_type, ...@@ -271,7 +271,7 @@ int bpf_prog_load_v0_6_0(enum bpf_prog_type prog_type,
attr.kern_version = OPTS_GET(opts, kern_version, 0); attr.kern_version = OPTS_GET(opts, kern_version, 0);
if (prog_name) if (prog_name)
strncat(attr.prog_name, prog_name, sizeof(attr.prog_name) - 1); libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
attr.license = ptr_to_u64(license); attr.license = ptr_to_u64(license);
if (insn_cnt > UINT_MAX) if (insn_cnt > UINT_MAX)
......
...@@ -2321,8 +2321,8 @@ int btf_dump__dump_type_data(struct btf_dump *d, __u32 id, ...@@ -2321,8 +2321,8 @@ int btf_dump__dump_type_data(struct btf_dump *d, __u32 id,
if (!opts->indent_str) if (!opts->indent_str)
d->typed_dump->indent_str[0] = '\t'; d->typed_dump->indent_str[0] = '\t';
else else
strncat(d->typed_dump->indent_str, opts->indent_str, libbpf_strlcpy(d->typed_dump->indent_str, opts->indent_str,
sizeof(d->typed_dump->indent_str) - 1); sizeof(d->typed_dump->indent_str));
d->typed_dump->compact = OPTS_GET(opts, compact, false); d->typed_dump->compact = OPTS_GET(opts, compact, false);
d->typed_dump->skip_names = OPTS_GET(opts, skip_names, false); d->typed_dump->skip_names = OPTS_GET(opts, skip_names, false);
......
...@@ -463,8 +463,7 @@ void bpf_gen__map_create(struct bpf_gen *gen, ...@@ -463,8 +463,7 @@ void bpf_gen__map_create(struct bpf_gen *gen,
attr.map_flags = map_attr->map_flags; attr.map_flags = map_attr->map_flags;
attr.map_extra = map_attr->map_extra; attr.map_extra = map_attr->map_extra;
if (map_name) if (map_name)
memcpy(attr.map_name, map_name, libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
min((unsigned)strlen(map_name), BPF_OBJ_NAME_LEN - 1));
attr.numa_node = map_attr->numa_node; attr.numa_node = map_attr->numa_node;
attr.map_ifindex = map_attr->map_ifindex; attr.map_ifindex = map_attr->map_ifindex;
attr.max_entries = max_entries; attr.max_entries = max_entries;
...@@ -970,8 +969,7 @@ void bpf_gen__prog_load(struct bpf_gen *gen, ...@@ -970,8 +969,7 @@ void bpf_gen__prog_load(struct bpf_gen *gen,
core_relos = add_data(gen, gen->core_relos, core_relos = add_data(gen, gen->core_relos,
attr.core_relo_cnt * attr.core_relo_rec_size); attr.core_relo_cnt * attr.core_relo_rec_size);
memcpy(attr.prog_name, prog_name, libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
min((unsigned)strlen(prog_name), BPF_OBJ_NAME_LEN - 1));
prog_load_attr = add_data(gen, &attr, attr_size); prog_load_attr = add_data(gen, &attr, attr_size);
/* populate union bpf_attr with a pointer to license */ /* populate union bpf_attr with a pointer to license */
......
...@@ -1201,12 +1201,10 @@ static struct bpf_object *bpf_object__new(const char *path, ...@@ -1201,12 +1201,10 @@ static struct bpf_object *bpf_object__new(const char *path,
strcpy(obj->path, path); strcpy(obj->path, path);
if (obj_name) { if (obj_name) {
strncpy(obj->name, obj_name, sizeof(obj->name) - 1); libbpf_strlcpy(obj->name, obj_name, sizeof(obj->name));
obj->name[sizeof(obj->name) - 1] = 0;
} else { } else {
/* Using basename() GNU version which doesn't modify arg. */ /* Using basename() GNU version which doesn't modify arg. */
strncpy(obj->name, basename((void *)path), libbpf_strlcpy(obj->name, basename((void *)path), sizeof(obj->name));
sizeof(obj->name) - 1);
end = strchr(obj->name, '.'); end = strchr(obj->name, '.');
if (end) if (end)
*end = 0; *end = 0;
...@@ -1358,7 +1356,7 @@ static int bpf_object__check_endianness(struct bpf_object *obj) ...@@ -1358,7 +1356,7 @@ static int bpf_object__check_endianness(struct bpf_object *obj)
static int static int
bpf_object__init_license(struct bpf_object *obj, void *data, size_t size) bpf_object__init_license(struct bpf_object *obj, void *data, size_t size)
{ {
memcpy(obj->license, data, min(size, sizeof(obj->license) - 1)); libbpf_strlcpy(obj->license, data, sizeof(obj->license));
pr_debug("license of %s is %s\n", obj->path, obj->license); pr_debug("license of %s is %s\n", obj->path, obj->license);
return 0; return 0;
} }
......
...@@ -169,6 +169,25 @@ static inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size) ...@@ -169,6 +169,25 @@ static inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size)
return realloc(ptr, total); return realloc(ptr, total);
} }
/* Copy up to sz - 1 bytes from zero-terminated src string and ensure that dst
* is zero-terminated string no matter what (unless sz == 0, in which case
* it's a no-op). It's conceptually close to FreeBSD's strlcpy(), but differs
* in what is returned. Given this is internal helper, it's trivial to extend
* this, when necessary. Use this instead of strncpy inside libbpf source code.
*/
static inline void libbpf_strlcpy(char *dst, const char *src, size_t sz)
{
size_t i;
if (sz == 0)
return;
sz--;
for (i = 0; i < sz && src[i]; i++)
dst[i] = src[i];
dst[i] = '\0';
}
struct btf; struct btf;
struct btf_type; struct btf_type;
......
...@@ -548,8 +548,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk) ...@@ -548,8 +548,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk)
return -errno; return -errno;
ifr.ifr_data = (void *)&channels; ifr.ifr_data = (void *)&channels;
memcpy(ifr.ifr_name, ctx->ifname, IFNAMSIZ - 1); libbpf_strlcpy(ifr.ifr_name, ctx->ifname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
err = ioctl(fd, SIOCETHTOOL, &ifr); err = ioctl(fd, SIOCETHTOOL, &ifr);
if (err && errno != EOPNOTSUPP) { if (err && errno != EOPNOTSUPP) {
ret = -errno; ret = -errno;
...@@ -768,8 +767,7 @@ static int xsk_create_xsk_struct(int ifindex, struct xsk_socket *xsk) ...@@ -768,8 +767,7 @@ static int xsk_create_xsk_struct(int ifindex, struct xsk_socket *xsk)
} }
ctx->ifindex = ifindex; ctx->ifindex = ifindex;
memcpy(ctx->ifname, ifname, IFNAMSIZ -1); libbpf_strlcpy(ctx->ifname, ifname, IFNAMSIZ);
ctx->ifname[IFNAMSIZ - 1] = 0;
xsk->ctx = ctx; xsk->ctx = ctx;
xsk->ctx->has_bpf_link = xsk_probe_bpf_link(); xsk->ctx->has_bpf_link = xsk_probe_bpf_link();
...@@ -951,8 +949,7 @@ static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk, ...@@ -951,8 +949,7 @@ static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
ctx->refcount = 1; ctx->refcount = 1;
ctx->umem = umem; ctx->umem = umem;
ctx->queue_id = queue_id; ctx->queue_id = queue_id;
memcpy(ctx->ifname, ifname, IFNAMSIZ - 1); libbpf_strlcpy(ctx->ifname, ifname, IFNAMSIZ);
ctx->ifname[IFNAMSIZ - 1] = '\0';
ctx->fill = fill; ctx->fill = fill;
ctx->comp = comp; ctx->comp = comp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment