Skip to contentSkip to conversation

bpf: link: refuse non-O_RDWR flags in BPF_OBJ_GET

PATCH Applied Lorenz Bauer 4 participants 9 messages Mar 26, 2021 – Apr 1, 2021

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH v2 1/2 bpf: link: refuse non-O_RDWR flags in BPF_OBJ_GET

Invoking BPF_OBJ_GET on a pinned bpf_link checks the path access permissions based on file_flags, but the returned fd ignores flags. This means that any user can acquire a "read-write" fd for a pinned link with mode 0664 by invoking BPF_OBJ_GET with BPF_F_RDONLY in file_flags. The fd can be used to invoke BPF_LINK_DETACH, etc.

Fix this by refusing non-O_RDWR flags in BPF_OBJ_GET. This works because OBJ_GET by default returns a read write mapping and libbpf doesn't expose a way to override this behaviour for programs and links.

Fixes 70ed506c3bbc ("bpf: Introduce pinnable bpf_link abstraction")
---
 kernel/bpf/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/inode.c +1 -1
index 1576ff331ee4..dc56237d6960 100644
@@ -547,7 +547,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
 	else if (type == BPF_TYPE_MAP)
 		ret = bpf_map_new_fd(raw, f_flags);
 	else if (type == BPF_TYPE_LINK)
-		ret = bpf_link_new_fd(raw);
+		ret = (f_flags != O_RDWR) ? -EINVAL : bpf_link_new_fd(raw);
 	else
 		return -ENOENT;
 
Signature · 1 line
2.27.0
#1 lore raw

PATCH v2 2/2 bpf: program: refuse non-O_RDWR flags in BPF_OBJ_GET

As for bpf_link, refuse creating a non-O_RDWR fd. Since program fds currently don't allow modifications this is a precaution, not a straight up bug fix.

---
 kernel/bpf/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/inode.c +1 -1
index dc56237d6960..d2de2abec35b 100644
@@ -543,7 +543,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
 		return PTR_ERR(raw);
 
 	if (type == BPF_TYPE_PROG)
-		ret = bpf_prog_new_fd(raw);
+		ret = (f_flags != O_RDWR) ? -EINVAL : bpf_prog_new_fd(raw);
 	else if (type == BPF_TYPE_MAP)
 		ret = bpf_map_new_fd(raw, f_flags);
 	else if (type == BPF_TYPE_LINK)
Signature · 1 line
2.27.0
reviewer
#2 lore raw

Re: [PATCH bpf v2 2/2] bpf: program: refuse non-O_RDWR flags in BPF_OBJ_GET

Quoted 15 lines · Lorenz Bauer

As for bpf_link, refuse creating a non-O_RDWR fd. Since program fds currently don't allow modifications this is a precaution, not a straight up bug fix.

---
 kernel/bpf/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/inode.c +0 -0
index dc56237d6960..d2de2abec35b 100644

kernel/bpf/inode.c int bpf_obj_get_user(const char __user *pathname, int flags) · line 543

Quoted 1 line
kernel/bpf/inode.c +0 -0
@@ -543,7 +543,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
                return PTR_ERR(raw);

For both patches, shall we do the check before bpf_obj_do_get(), which is a few lines above?

Thanks,
Song

Quoted 10 lines
kernel/bpf/inode.c +1 -2
        if (type == BPF_TYPE_PROG)
-               ret = bpf_prog_new_fd(raw);
+               ret = (f_flags != O_RDWR) ? -EINVAL : bpf_prog_new_fd(raw);
        else if (type == BPF_TYPE_MAP)
                ret = bpf_map_new_fd(raw, f_flags);
        else if (type == BPF_TYPE_LINK)
--

2.27.0

#3 lore raw

Re: [PATCH bpf v2 2/2] bpf: program: refuse non-O_RDWR flags in BPF_OBJ_GET

Quoted 12 lines · Song Liu
Quoted 10 lines · Lorenz Bauer

As for bpf_link, refuse creating a non-O_RDWR fd. Since program fds currently don't allow modifications this is a precaution, not a straight up bug fix.

---
 kernel/bpf/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 9 lines

kernel/bpf/inode.c int bpf_obj_get_user(const char __user *pathname, int flags) · line 543

Quoted 6 lines
kernel/bpf/inode.c +0 -0
index dc56237d6960..d2de2abec35b 100644
@@ -543,7 +543,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
                return PTR_ERR(raw);

For both patches, shall we do the check before bpf_obj_do_get(), which is a few lines above?

Map does use f_flags, so we need to let them through. Or did you mean to do a (type != BPF_TYPE_MAP && f_flags != O_RDWR) check?

Either way is fine with me, so:

Quoted 14 lines

Thanks,
Song

Quoted 10 lines
kernel/bpf/inode.c +1 -2
        if (type == BPF_TYPE_PROG)
-               ret = bpf_prog_new_fd(raw);
+               ret = (f_flags != O_RDWR) ? -EINVAL : bpf_prog_new_fd(raw);
        else if (type == BPF_TYPE_MAP)
                ret = bpf_map_new_fd(raw, f_flags);
        else if (type == BPF_TYPE_LINK)
--

2.27.0

#4 lore raw

Re: [PATCH bpf v2 2/2] bpf: program: refuse non-O_RDWR flags in BPF_OBJ_GET

In reply to Song Liu
Quoted 12 lines · Song Liu
Quoted 10 lines · Lorenz Bauer

As for bpf_link, refuse creating a non-O_RDWR fd. Since program fds currently don't allow modifications this is a precaution, not a straight up bug fix.

---
 kernel/bpf/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Quoted 9 lines

kernel/bpf/inode.c int bpf_obj_get_user(const char __user *pathname, int flags) · line 543

Quoted 6 lines
kernel/bpf/inode.c +0 -0
index dc56237d6960..d2de2abec35b 100644
@@ -543,7 +543,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
                return PTR_ERR(raw);

For both patches, shall we do the check before bpf_obj_do_get(), which is a few lines above?

type is filled in by bpf_obj_do_get, so we can't avoid calling it. As Andrii mentions we need to allow flags for map.

Quoted 14 lines

Thanks,
Song

Quoted 10 lines
kernel/bpf/inode.c +1 -2
        if (type == BPF_TYPE_PROG)
-               ret = bpf_prog_new_fd(raw);
+               ret = (f_flags != O_RDWR) ? -EINVAL : bpf_prog_new_fd(raw);
        else if (type == BPF_TYPE_MAP)
                ret = bpf_map_new_fd(raw, f_flags);
        else if (type == BPF_TYPE_LINK)
--

2.27.0

Signature · 4 lines
Lorenz Bauer  |  Systems Engineer
6th Floor, County Hall/The Riverside Building, SE1 7PB, UK

www.cloudflare.com
Acked-by on v2 1/2
#5 lore raw
In reply to Lorenz Bauer
Quoted 7 lines · Lorenz Bauer

Invoking BPF_OBJ_GET on a pinned bpf_link checks the path access permissions based on file_flags, but the returned fd ignores flags. This means that any user can acquire a "read-write" fd for a pinned link with mode 0664 by invoking BPF_OBJ_GET with BPF_F_RDONLY in file_flags. The fd can be used to invoke BPF_LINK_DETACH, etc.

Quoted 8 lines

Fix this by refusing non-O_RDWR flags in BPF_OBJ_GET. This works because OBJ_GET by default returns a read write mapping and libbpf doesn't expose a way to override this behaviour for programs and links.

Fixes 70ed506c3bbc ("bpf: Introduce pinnable bpf_link abstraction")

---

LGTM.

Quoted 19 lines
 kernel/bpf/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/inode.c +1 -2
index 1576ff331ee4..dc56237d6960 100644
@@ -547,7 +547,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
        else if (type == BPF_TYPE_MAP)
                ret = bpf_map_new_fd(raw, f_flags);
        else if (type == BPF_TYPE_LINK)
-               ret = bpf_link_new_fd(raw);
+               ret = (f_flags != O_RDWR) ? -EINVAL : bpf_link_new_fd(raw);
        else
                return -ENOENT;
 
--

2.27.0

#6 lore raw
In reply to Lorenz Bauer
Quoted 11 lines · Lorenz Bauer

Invoking BPF_OBJ_GET on a pinned bpf_link checks the path access permissions based on file_flags, but the returned fd ignores flags. This means that any user can acquire a "read-write" fd for a pinned link with mode 0664 by invoking BPF_OBJ_GET with BPF_F_RDONLY in file_flags. The fd can be used to invoke BPF_LINK_DETACH, etc.

Fix this by refusing non-O_RDWR flags in BPF_OBJ_GET. This works because OBJ_GET by default returns a read write mapping and libbpf doesn't expose a way to override this behaviour for programs and links.

Hi Alexei and Daniel,

I think these two patches might have fallen through the cracks, could you take a look? I'm not sure what the etiquette is around bumping a set, so please let me know if you'd prefer me to send the patches with acks included or something like that.

Best

Signature · 4 lines
Lorenz Bauer  |  Systems Engineer
6th Floor, County Hall/The Riverside Building, SE1 7PB, UK

www.cloudflare.com
#7 lore raw
Quoted 14 lines · Lorenz Bauer
Quoted 11 lines · Lorenz Bauer

Invoking BPF_OBJ_GET on a pinned bpf_link checks the path access permissions based on file_flags, but the returned fd ignores flags. This means that any user can acquire a "read-write" fd for a pinned link with mode 0664 by invoking BPF_OBJ_GET with BPF_F_RDONLY in file_flags. The fd can be used to invoke BPF_LINK_DETACH, etc.

Fix this by refusing non-O_RDWR flags in BPF_OBJ_GET. This works because OBJ_GET by default returns a read write mapping and libbpf doesn't expose a way to override this behaviour for programs and links.

Quoted 6 lines

Hi Alexei and Daniel,

I think these two patches might have fallen through the cracks, could you take a look? I'm not sure what the etiquette is around bumping a set, so please let me know if you'd prefer me to send the patches with acks included or something like that.

It is still in patchworks. I didn't have time to think it through. Sorry for delay.

#8 lore raw
In reply to Lorenz Bauer
Quoted 14 lines · Lorenz Bauer
Quoted 11 lines · Lorenz Bauer

Invoking BPF_OBJ_GET on a pinned bpf_link checks the path access permissions based on file_flags, but the returned fd ignores flags. This means that any user can acquire a "read-write" fd for a pinned link with mode 0664 by invoking BPF_OBJ_GET with BPF_F_RDONLY in file_flags. The fd can be used to invoke BPF_LINK_DETACH, etc.

Fix this by refusing non-O_RDWR flags in BPF_OBJ_GET. This works because OBJ_GET by default returns a read write mapping and libbpf doesn't expose a way to override this behaviour for programs and links.

Quoted 6 lines

Hi Alexei and Daniel,

I think these two patches might have fallen through the cracks, could you take a look? I'm not sure what the etiquette is around bumping a set, so please let me know if you'd prefer me to send the patches with acks included or something like that.

Applied both. Thanks