Skip to content

Commit b44123b

Browse files
zhuyifei1999Alexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: Add cgroup helpers bpf_{get,set}_retval to get/set syscall return value
The helpers continue to use int for retval because all the hooks are int-returning rather than long-returning. The return value of bpf_set_retval is int for future-proofing, in case in the future there may be errors trying to set the retval. After the previous patch, if a program rejects a syscall by returning 0, an -EPERM will be generated no matter if the retval is already set to -err. This patch change it being forced only if retval is not -err. This is because we want to support, for example, invoking bpf_set_retval(-EINVAL) and return 0, and have the syscall return value be -EINVAL not -EPERM. For BPF_PROG_CGROUP_INET_EGRESS_RUN_ARRAY, the prior behavior is that, if the return value is NET_XMIT_DROP, the packet is silently dropped. We preserve this behavior for backward compatibility reasons, so even if an errno is set, the errno does not return to caller. However, setting a non-err to retval cannot propagate so this is not allowed and we return a -EFAULT in that case. Signed-off-by: YiFei Zhu <[email protected]> Reviewed-by: Stanislav Fomichev <[email protected]> Link: https://lore.kernel.org/r/b4013fd5d16bed0b01977c1fafdeae12e1de61fb.1639619851.git.zhuyifei@google.com Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent c4dcfdd commit b44123b

File tree

4 files changed

+79
-5
lines changed

4 files changed

+79
-5
lines changed

include/linux/bpf.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ BPF_PROG_RUN_ARRAY_CG_FLAGS(const struct bpf_prog_array __rcu *array_rcu,
12991299
while ((prog = READ_ONCE(item->prog))) {
13001300
run_ctx.prog_item = item;
13011301
func_ret = run_prog(prog, ctx);
1302-
if (!(func_ret & 1))
1302+
if (!(func_ret & 1) && !IS_ERR_VALUE((long)run_ctx.retval))
13031303
run_ctx.retval = -EPERM;
13041304
*(ret_flags) |= (func_ret >> 1);
13051305
item++;
@@ -1329,7 +1329,7 @@ BPF_PROG_RUN_ARRAY_CG(const struct bpf_prog_array __rcu *array_rcu,
13291329
old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
13301330
while ((prog = READ_ONCE(item->prog))) {
13311331
run_ctx.prog_item = item;
1332-
if (!run_prog(prog, ctx))
1332+
if (!run_prog(prog, ctx) && !IS_ERR_VALUE((long)run_ctx.retval))
13331333
run_ctx.retval = -EPERM;
13341334
item++;
13351335
}
@@ -1389,7 +1389,7 @@ BPF_PROG_RUN_ARRAY(const struct bpf_prog_array __rcu *array_rcu,
13891389
* 0: NET_XMIT_SUCCESS skb should be transmitted
13901390
* 1: NET_XMIT_DROP skb should be dropped and cn
13911391
* 2: NET_XMIT_CN skb should be transmitted and cn
1392-
* 3: -EPERM skb should be dropped
1392+
* 3: -err skb should be dropped
13931393
*/
13941394
#define BPF_PROG_CGROUP_INET_EGRESS_RUN_ARRAY(array, ctx, func) \
13951395
({ \
@@ -1398,10 +1398,12 @@ BPF_PROG_RUN_ARRAY(const struct bpf_prog_array __rcu *array_rcu,
13981398
u32 _ret; \
13991399
_ret = BPF_PROG_RUN_ARRAY_CG_FLAGS(array, ctx, func, 0, &_flags); \
14001400
_cn = _flags & BPF_RET_SET_CN; \
1401+
if (_ret && !IS_ERR_VALUE((long)_ret)) \
1402+
_ret = -EFAULT; \
14011403
if (!_ret) \
14021404
_ret = (_cn ? NET_XMIT_CN : NET_XMIT_SUCCESS); \
14031405
else \
1404-
_ret = (_cn ? NET_XMIT_DROP : -EPERM); \
1406+
_ret = (_cn ? NET_XMIT_DROP : _ret); \
14051407
_ret; \
14061408
})
14071409

include/uapi/linux/bpf.h

+18
Original file line numberDiff line numberDiff line change
@@ -5033,6 +5033,22 @@ union bpf_attr {
50335033
*
50345034
* Return
50355035
* The number of arguments of the traced function.
5036+
*
5037+
* int bpf_get_retval(void)
5038+
* Description
5039+
* Get the syscall's return value that will be returned to userspace.
5040+
*
5041+
* This helper is currently supported by cgroup programs only.
5042+
* Return
5043+
* The syscall's return value.
5044+
*
5045+
* int bpf_set_retval(int retval)
5046+
* Description
5047+
* Set the syscall's return value that will be returned to userspace.
5048+
*
5049+
* This helper is currently supported by cgroup programs only.
5050+
* Return
5051+
* 0 on success, or a negative error in case of failure.
50365052
*/
50375053
#define __BPF_FUNC_MAPPER(FN) \
50385054
FN(unspec), \
@@ -5221,6 +5237,8 @@ union bpf_attr {
52215237
FN(get_func_arg), \
52225238
FN(get_func_ret), \
52235239
FN(get_func_arg_cnt), \
5240+
FN(get_retval), \
5241+
FN(set_retval), \
52245242
/* */
52255243

52265244
/* integer value in 'imm' field of BPF_CALL instruction selects which helper

kernel/bpf/cgroup.c

+37-1
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ int cgroup_bpf_prog_query(const union bpf_attr *attr,
10441044
* NET_XMIT_DROP (1) - drop packet and notify TCP to call cwr
10451045
* NET_XMIT_CN (2) - continue with packet output and notify TCP
10461046
* to call cwr
1047-
* -EPERM - drop packet
1047+
* -err - drop packet
10481048
*
10491049
* For ingress packets, this function will return -EPERM if any
10501050
* attached program was found and if it returned != 1 during execution.
@@ -1080,6 +1080,8 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk,
10801080
} else {
10811081
ret = BPF_PROG_RUN_ARRAY_CG(cgrp->bpf.effective[atype], skb,
10821082
__bpf_prog_run_save_cb, 0);
1083+
if (ret && !IS_ERR_VALUE((long)ret))
1084+
ret = -EFAULT;
10831085
}
10841086
bpf_restore_data_end(skb, saved_data_end);
10851087
__skb_pull(skb, offset);
@@ -1205,6 +1207,36 @@ int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor,
12051207
return ret;
12061208
}
12071209

1210+
BPF_CALL_0(bpf_get_retval)
1211+
{
1212+
struct bpf_cg_run_ctx *ctx =
1213+
container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
1214+
1215+
return ctx->retval;
1216+
}
1217+
1218+
static const struct bpf_func_proto bpf_get_retval_proto = {
1219+
.func = bpf_get_retval,
1220+
.gpl_only = false,
1221+
.ret_type = RET_INTEGER,
1222+
};
1223+
1224+
BPF_CALL_1(bpf_set_retval, int, retval)
1225+
{
1226+
struct bpf_cg_run_ctx *ctx =
1227+
container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
1228+
1229+
ctx->retval = retval;
1230+
return 0;
1231+
}
1232+
1233+
static const struct bpf_func_proto bpf_set_retval_proto = {
1234+
.func = bpf_set_retval,
1235+
.gpl_only = false,
1236+
.ret_type = RET_INTEGER,
1237+
.arg1_type = ARG_ANYTHING,
1238+
};
1239+
12081240
static const struct bpf_func_proto *
12091241
cgroup_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
12101242
{
@@ -1217,6 +1249,10 @@ cgroup_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
12171249
return &bpf_get_current_cgroup_id_proto;
12181250
case BPF_FUNC_perf_event_output:
12191251
return &bpf_event_output_data_proto;
1252+
case BPF_FUNC_get_retval:
1253+
return &bpf_get_retval_proto;
1254+
case BPF_FUNC_set_retval:
1255+
return &bpf_set_retval_proto;
12201256
default:
12211257
return bpf_base_func_proto(func_id);
12221258
}

tools/include/uapi/linux/bpf.h

+18
Original file line numberDiff line numberDiff line change
@@ -5033,6 +5033,22 @@ union bpf_attr {
50335033
*
50345034
* Return
50355035
* The number of arguments of the traced function.
5036+
*
5037+
* int bpf_get_retval(void)
5038+
* Description
5039+
* Get the syscall's return value that will be returned to userspace.
5040+
*
5041+
* This helper is currently supported by cgroup programs only.
5042+
* Return
5043+
* The syscall's return value.
5044+
*
5045+
* int bpf_set_retval(int retval)
5046+
* Description
5047+
* Set the syscall's return value that will be returned to userspace.
5048+
*
5049+
* This helper is currently supported by cgroup programs only.
5050+
* Return
5051+
* 0 on success, or a negative error in case of failure.
50365052
*/
50375053
#define __BPF_FUNC_MAPPER(FN) \
50385054
FN(unspec), \
@@ -5221,6 +5237,8 @@ union bpf_attr {
52215237
FN(get_func_arg), \
52225238
FN(get_func_ret), \
52235239
FN(get_func_arg_cnt), \
5240+
FN(get_retval), \
5241+
FN(set_retval), \
52245242
/* */
52255243

52265244
/* integer value in 'imm' field of BPF_CALL instruction selects which helper

0 commit comments

Comments
 (0)