From 99f99024851903c02f214b8c745f19b962d730cd Mon Sep 17 00:00:00 2001 From: Victor Nogueira Date: Sat, 16 Jan 2021 15:52:49 -0300 Subject: [PATCH] #267 Load Lua scripts with luaL_loadbufferx --- include/net/xdplua.h | 4 +- net/core/rtnetlink.c | 10 ++--- net/core/xdplua.c | 24 +++++++++-- samples/bpf/xdplua_user.c | 86 +++++++++++++++++++++++++++------------ tools/lib/bpf/bpf.c | 22 +++++----- tools/lib/bpf/libbpf.h | 2 +- 6 files changed, 99 insertions(+), 49 deletions(-) diff --git a/include/net/xdplua.h b/include/net/xdplua.h index f47cfde01e9fed..01509f2ab13821 100644 --- a/include/net/xdplua.h +++ b/include/net/xdplua.h @@ -22,6 +22,7 @@ struct xdp_lua_work { char script[XDP_LUA_MAX_SCRIPT_LEN]; + size_t script_len; struct lua_State *L; struct sk_buff *skb; struct work_struct work; @@ -29,12 +30,13 @@ struct xdp_lua_work { DECLARE_PER_CPU(struct xdp_lua_work, luaworks); + #define XDP_LUA_BPF_FUNC(name) BPF_FUNC_lua_##name #define xdp_lua_get_skb() (this_cpu_ptr(&luaworks)->skb) #define xdp_lua_set_skb(skb) (this_cpu_ptr(&luaworks)->skb = skb) -void generic_xdp_lua_install_prog(const char *script); +int generic_xdp_lua_install_prog(const char *script, size_t script_len); void xdp_lua_init(void); #define __BPF_LUA_MAP_0(l, m, v, ...) l diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 9fa69d93b8c025..eb86749f309a46 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2638,14 +2638,14 @@ static int do_setlink(const struct sk_buff *skb, #ifdef CONFIG_XDP_LUA if (xdp[IFLA_XDP_LUA_PROG]) { const char *script; + int script_len; script = nla_data(xdp[IFLA_XDP_LUA_PROG]); - if (!script) { - err = -EINVAL; - goto errout; - } + script_len = nla_len(xdp[IFLA_XDP_LUA_PROG]); - generic_xdp_lua_install_prog(script); + err = generic_xdp_lua_install_prog(script, script_len); + if (err) + goto errout; } #endif /* CONFIG_XDP_LUA */ } diff --git a/net/core/xdplua.c b/net/core/xdplua.c index 3a3287f7262451..2932945b417fa5 100644 --- a/net/core/xdplua.c +++ b/net/core/xdplua.c @@ -25,23 +25,39 @@ static void per_cpu_xdp_lua_install(struct work_struct *w) lw = container_of(w, struct xdp_lua_work, work); local_bh_disable(); - if (luaL_dostring(lw->L, lw->script)) { - pr_err(KERN_INFO "error: %s\nOn cpu: %d\n", + if (luaL_loadbufferx(lw->L, lw->script, lw->script_len, NULL, "t")) { + pr_err("error loading Lua script: %s\non cpu: %d\n", lua_tostring(lw->L, -1), this_cpu); lua_pop(lw->L, 1); + goto enable; } + + if (lua_pcall(lw->L, 0, LUA_MULTRET, 0)) { + pr_err("error running Lua script: %s\non cpu: %d\n", + lua_tostring(lw->L, -1), this_cpu); + lua_pop(lw->L, 1); + } + +enable: local_bh_enable(); } -void generic_xdp_lua_install_prog(const char *script) +int generic_xdp_lua_install_prog(const char *script, size_t script_len) { int i; + if (!script || script_len == 0) + return -EINVAL; + + if (script_len > XDP_LUA_MAX_SCRIPT_LEN) + return -ENAMETOOLONG; + for_each_possible_cpu(i) { struct xdp_lua_work *lw; lw = per_cpu_ptr(&luaworks, i); - strncpy(lw->script, script, XDP_LUA_MAX_SCRIPT_LEN); + memcpy(lw->script, script, script_len); + lw->script_len = script_len; schedule_work_on(i, &lw->work); } diff --git a/samples/bpf/xdplua_user.c b/samples/bpf/xdplua_user.c index 78b2873fa6fc09..5589d60f9d7e1f 100644 --- a/samples/bpf/xdplua_user.c +++ b/samples/bpf/xdplua_user.c @@ -41,10 +41,22 @@ static void usage(const char *prog) { prog); } -static char *extract_script(const char *path) +static int try_strncpy(char *dest, const char *src, size_t n, const char *fmt) { + int srclen = strnlen(src, n); + + if (srclen == n) { + int err = ENAMETOOLONG; + fprintf(stderr, fmt, strerror(err)); + return -err; + } + + strncpy(dest, src, n); + return srclen; +} + +static char *extract_script(const char *path, size_t *script_len) { FILE *f; - long script_len; size_t read; char *script = NULL; @@ -55,25 +67,33 @@ static char *extract_script(const char *path) } if (fseek(f, 0 , SEEK_END) < 0) { - perror("unable to reach end of script file"); + perror("unable to reach end of file"); goto out; } - script_len = ftell(f); - if (script_len < 0) { - perror("error while attempting to get script length"); + + *script_len = (size_t) ftell(f); + if (*script_len < 0) { + perror("error while attempting to get file length"); goto out; } - rewind(f); - script = (char *) malloc(script_len + 1); + fseek(f, 0, *script_len); + + if (*script_len > XDP_LUA_MAX_SCRIPT_LEN) + fprintf(stderr, "lua file can't have more than %d bytes\n", + XDP_LUA_MAX_SCRIPT_LEN); + + script = (char *) malloc(sizeof(char) * (*script_len)); if (!script) { perror("failed to alloc lua script"); goto out; } - memset(script, 0, script_len + 1); - read = fread(script, 1, script_len, f); - if (read != script_len) { - perror("unable to read lua file"); + + rewind(f); + + read = fread(script, sizeof(char), *script_len, f); + if (read != *script_len) { + fprintf(stderr, "unable to read file %s\n", path); free(script); script = NULL; goto out; @@ -95,11 +115,11 @@ static int do_attach_ebpf(int idx, int fd, const char *name) return err; } -static int do_attach_lua(const char *script) +static int do_attach_lua(const char *script, size_t script_len) { int err; - err = bpf_set_link_xdp_lua_script(script); + err = bpf_set_link_xdp_lua_script(script, script_len); if (err < 0) fprintf(stderr, "ERROR: failed to attach lua script %d\n", err); @@ -138,12 +158,15 @@ static void poll(int map_fd, int interval, int duration) { } } +#define strncpy_err(fmt, err) fprintf(stderr, fmt, strerr(-err)) + int main(int argc, char *argv[]) { struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; char lua_filename[MAXFILENAMELEN]; char filename[MAXFILENAMELEN]; char script[XDP_LUA_MAX_SCRIPT_LEN]; + size_t script_len = 0; char ifname[IFNAMSIZ]; struct bpf_object *obj; int opt, prog_fd; @@ -151,6 +174,7 @@ int main(int argc, char *argv[]) int ifindex = 0; int detach = 0, attach_lua_file = 0, attach_ebpf = 0, monitor = 0, attach_lua_script = 0, interval = 1, duration = 1; + int err = 0; const char *optstr = "f:p:i:dms:I:D:"; struct bpf_prog_load_attr prog_load_attr = { @@ -163,28 +187,36 @@ int main(int argc, char *argv[]) while ((opt = getopt(argc, argv, optstr)) != -1) { switch (opt) { case 'f': - snprintf(lua_filename, sizeof(lua_filename), "%s", optarg); + err = try_strncpy(lua_filename, optarg, MAXFILENAMELEN, "Invalid lua filename\nerr: %s\n"); + if (err < 0) + return 1; attach_lua_file = 1; break; case 'p': - snprintf(filename, sizeof(filename), - "%s", optarg); + err = try_strncpy(filename, optarg, MAXFILENAMELEN, "Invalid bpf prog filename\nerr: %s"); + if (err < 0) + return 1; attach_ebpf = 1; break; case 'd': detach = 1; break; case 'i': - snprintf(ifname, sizeof(ifname), "%s", optarg); + script_len = try_strncpy(ifname, optarg, IFNAMSIZ, "Invalid interface name\nerr: %s"); + if (script_len < 0) + return 1; ifindex = if_nametoindex(optarg); break; case 'm': monitor = 1; break; - case 's': - snprintf(script, sizeof(script), "%s", optarg); + case 's': { + err = try_strncpy(script, optarg, XDP_LUA_MAX_SCRIPT_LEN, "Invalid lua script\nerr: %s"); + if (err < 0) + return 1; attach_lua_script = 1; break; + } case 'I': interval = atoi(optarg); break; @@ -197,7 +229,6 @@ int main(int argc, char *argv[]) } } - if (attach_ebpf || detach) { if (!ifindex) { printf("ERROR: invalid interface name"); @@ -234,20 +265,21 @@ int main(int argc, char *argv[]) } if (attach_lua_file) { - char *extracted_script = extract_script(lua_filename); + int ret = 0; + size_t extracted_script_len; + char *extracted_script = extract_script(lua_filename, &extracted_script_len); if (!extracted_script) return 1; - if (do_attach_lua(extracted_script) < 0) { - free(extracted_script); - return 1; - } + if (do_attach_lua(extracted_script, extracted_script_len) < 0) + ret = 1; free(extracted_script); + return ret; } if (attach_lua_script) - if (do_attach_lua(script) < 0) + if (do_attach_lua(script, script_len) < 0) return 1; if (monitor) { diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index b3f82a1e39edce..a38f8225692ca8 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -621,16 +621,16 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) } /* #ifdef CONFIG_XDPLUA */ -int bpf_set_link_xdp_lua_script(const char *script) +int bpf_set_link_xdp_lua_script(const char *script, size_t script_len) { struct sockaddr_nl sa; int sock, seq = 0, len, ret = -1; char buf[4096]; - struct nlattr *nla, *nla_xdp; + struct nlattr *nla, *nla_xdp_lua; struct { struct nlmsghdr nh; struct ifinfomsg ifinfo; - char attrbuf[XDP_LUA_MAX_SCRIPT_LEN + 64]; + char attrbuf[XDP_LUA_MAX_SCRIPT_LEN]; } req; struct nlmsghdr *nh; struct nlmsgerr *err; @@ -681,24 +681,24 @@ int bpf_set_link_xdp_lua_script(const char *script) nla->nla_type = NLA_F_NESTED | IFLA_XDP; nla->nla_len = NLA_HDRLEN; - /* add XDP LUA PROG */ - nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); - nla_xdp->nla_type = IFLA_XDP_LUA_PROG; + /* add XDP LUA SCRIPT */ + nla_xdp_lua = (struct nlattr *)((char *)nla + nla->nla_len); + nla_xdp_lua->nla_type = IFLA_XDP_LUA_PROG; if (script) { - if (strlen(script) + 1 > XDP_LUA_MAX_SCRIPT_LEN) { + if (script_len > XDP_LUA_MAX_SCRIPT_LEN) { fprintf(stderr, "script length cannot exceed %d bytes\n", XDP_LUA_MAX_SCRIPT_LEN); - ret = -EINVAL; + ret = -ENAMETOOLONG; goto cleanup; } - nla_xdp->nla_len = NLA_HDRLEN + strlen(script) + 1; - memcpy((char *)nla_xdp + NLA_HDRLEN, script, strlen(script) + 1); + nla_xdp_lua->nla_len = NLA_HDRLEN + script_len; + memcpy((char *)nla_xdp_lua + NLA_HDRLEN, script, script_len); } else { ret = -EINVAL; goto cleanup; } - nla->nla_len += nla_xdp->nla_len; + nla->nla_len += nla_xdp_lua->nla_len; req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index bfcb0d0feefe2d..863c390840a55a 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -285,7 +285,7 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type, int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); /* #ifdef CONFIG_XDP_LUA */ -int bpf_set_link_xdp_lua_script(const char *script); +int bpf_set_link_xdp_lua_script(const char *script, size_t script_len); /* #endif CONFIG_XDP_LUA */ enum bpf_perf_event_ret {