bpf: Don't EFAULT for getsockopt with optval=NULL
authorStanislav Fomichev <sdf@google.com>
Tue, 18 Apr 2023 22:53:38 +0000 (15:53 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 21 Apr 2023 15:09:53 +0000 (17:09 +0200)
Some socket options do getsockopt with optval=NULL to estimate the size
of the final buffer (which is returned via optlen). This breaks BPF
getsockopt assumptions about permitted optval buffer size. Let's enforce
these assumptions only when non-NULL optval is provided.

Fixes: 0d01da6afc54 ("bpf: implement getsockopt and setsockopt hooks")
Reported-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/ZD7Js4fj5YyI2oLd@google.com/T/#mb68daf700f87a9244a15d01d00c3f0e5b08f49f7
Link: https://lore.kernel.org/bpf/20230418225343.553806-2-sdf@google.com
kernel/bpf/cgroup.c

index 53edb8ad247178c91c98545654b67ad39aa45ce3..a06e118a9be582c1314ec624706010fb3a4000c0 100644 (file)
@@ -1921,14 +1921,17 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
        if (ret < 0)
                goto out;
 
-       if (ctx.optlen > max_optlen || ctx.optlen < 0) {
+       if (optval && (ctx.optlen > max_optlen || ctx.optlen < 0)) {
                ret = -EFAULT;
                goto out;
        }
 
        if (ctx.optlen != 0) {
-               if (copy_to_user(optval, ctx.optval, ctx.optlen) ||
-                   put_user(ctx.optlen, optlen)) {
+               if (optval && copy_to_user(optval, ctx.optval, ctx.optlen)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (put_user(ctx.optlen, optlen)) {
                        ret = -EFAULT;
                        goto out;
                }