* Re: [PATCH 00/17] spelling.txt: /decriptors/descriptors/
From: Martin K. Petersen @ 2020-06-16 3:59 UTC (permalink / raw)
To: Kieran Bingham, Kieran Bingham
Cc: Martin K . Petersen, netdev, linux-input, linux-renesas-soc,
linux-mm, linux-rdma, linuxppc-dev, linux-scsi, virtualization,
linux-pm, linux-arm-kernel, linux-kernel, linux-mtd,
linux-wireless, dri-devel, linux-usb, linux-gpio, ath10k
In-Reply-To: <20200609124610.3445662-1-kieran.bingham+renesas@ideasonboard.com>
On Tue, 9 Jun 2020 13:45:53 +0100, Kieran Bingham wrote:
> I wouldn't normally go through spelling fixes, but I caught sight of
> this typo twice, and then foolishly grepped the tree for it, and saw how
> pervasive it was.
>
> so here I am ... fixing a typo globally... but with an addition in
> scripts/spelling.txt so it shouldn't re-appear ;-)
>
> [...]
Applied to 5.9/scsi-queue, thanks!
[06/17] scsi: Fix trivial spelling
https://git.kernel.org/mkp/scsi/c/0a19a725c0ed
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply
* Re: [PATCH bpf 1/2] flow_dissector: reject invalid attach_flags
From: Alexei Starovoitov @ 2020-06-16 3:55 UTC (permalink / raw)
To: Lorenz Bauer
Cc: Alexei Starovoitov, Daniel Borkmann, Jakub Sitnicki, kernel-team,
Network Development, bpf, LKML
In-Reply-To: <CACAyw9-Jy+r2t5Yy83EEZ8GDnxEsGOPdrqr2JSfVqcC2E6dYmQ@mail.gmail.com>
On Mon, Jun 15, 2020 at 7:43 AM Lorenz Bauer <lmb@cloudflare.com> wrote:
>
> On Fri, 12 Jun 2020 at 23:36, Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Fri, Jun 12, 2020 at 9:02 AM Lorenz Bauer <lmb@cloudflare.com> wrote:
> > >
> > > Using BPF_PROG_ATTACH on a flow dissector program supports neither flags
> > > nor target_fd but accepts any value. Return EINVAL if either are non-zero.
> > >
> > > Signed-off-by: Lorenz Bauer <lmb@cloudflare.com>
> > > Fixes: b27f7bb590ba ("flow_dissector: Move out netns_bpf prog callbacks")
> > > ---
> > > kernel/bpf/net_namespace.c | 3 +++
> > > 1 file changed, 3 insertions(+)
> > >
> > > diff --git a/kernel/bpf/net_namespace.c b/kernel/bpf/net_namespace.c
> > > index 78cf061f8179..56133e78ae4f 100644
> > > --- a/kernel/bpf/net_namespace.c
> > > +++ b/kernel/bpf/net_namespace.c
> > > @@ -192,6 +192,9 @@ int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
> > > struct net *net;
> > > int ret;
> > >
> > > + if (attr->attach_flags || attr->target_fd)
> > > + return -EINVAL;
> > > +
> >
> > In theory it makes sense, but how did you test it?
>
> Not properly it seems, sorry!
>
> > test_progs -t flow
> > fails 5 tests.
>
> I spent today digging through this, and the issue is actually more annoying than
> I thought. BPF_PROG_DETACH for sockmap and flow_dissector ignores
> attach_bpf_fd. The cgroup and lirc2 attach point use this to make sure that the
> program being detached is actually what user space expects. We actually have
> tests that set attach_bpf_fd for these to attach points, which tells
> me that this is
> an easy mistake to make.
>
> Unfortunately I can't come up with a good fix that seems backportable:
> - Making sockmap and flow_dissector have the same semantics as cgroup
> and lirc2 requires a bunch of changes (probably a new function for sockmap)
making flow dissector pass prog_fd as cg and lirc is certainly my preference.
Especially since tests are passing fd user code is likely doing the same,
so breakage is unlikely. Also it wasn't done that long ago, so
we can backport far enough.
It will remove cap_net_admin ugly check in bpf_prog_detach()
which is the only exception now in cap model.
^ permalink raw reply
* Re: linux-next: build failures after merge of the vfs tree
From: Al Viro @ 2020-06-16 3:38 UTC (permalink / raw)
To: Herbert Xu
Cc: Stephen Rothwell, Linux Next Mailing List,
Linux Kernel Mailing List, netdev
In-Reply-To: <20200616010502.GA28834@gondor.apana.org.au>
On Tue, Jun 16, 2020 at 11:05:02AM +1000, Herbert Xu wrote:
> On Tue, Jun 16, 2020 at 10:34:40AM +1000, Stephen Rothwell wrote:
> > [Just adding Herbert to cc]
> >
> > On Tue, 16 Jun 2020 10:33:30 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> > >
> > > Hi all,
> > >
> > > After merging the vfs tree, today's linux-next build (x86_64 allmodconfig)
> > > failed like this:
>
> Thanks Stephen, here is an incremental patch to fix these up.
Folded and pushed
^ permalink raw reply
* [PATCH net] tcp: grow window for OOO packets only for SACK flows
From: Eric Dumazet @ 2020-06-16 3:37 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Neal Cardwell, Yuchung Cheng,
Venkat Venkatsubra
Back in 2013, we made a change that broke fast retransmit
for non SACK flows.
Indeed, for these flows, a sender needs to receive three duplicate
ACK before starting fast retransmit. Sending ACK with different
receive window do not count.
Even if enabling SACK is strongly recommended these days,
there still are some cases where it has to be disabled.
Not increasing the window seems better than having to
rely on RTO.
After the fix, following packetdrill test gives :
// Initialize connection
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
+0 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 8>
+0 < . 1:1(0) ack 1 win 514
+0 accept(3, ..., ...) = 4
+0 < . 1:1001(1000) ack 1 win 514
// Quick ack
+0 > . 1:1(0) ack 1001 win 264
+0 < . 2001:3001(1000) ack 1 win 514
// DUPACK : Normally we should not change the window
+0 > . 1:1(0) ack 1001 win 264
+0 < . 3001:4001(1000) ack 1 win 514
// DUPACK : Normally we should not change the window
+0 > . 1:1(0) ack 1001 win 264
+0 < . 4001:5001(1000) ack 1 win 514
// DUPACK : Normally we should not change the window
+0 > . 1:1(0) ack 1001 win 264
+0 < . 1001:2001(1000) ack 1 win 514
// Hole is repaired.
+0 > . 1:1(0) ack 5001 win 272
Fixes: 4e4f1fc22681 ("tcp: properly increase rcv_ssthresh for ofo packets")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
---
net/ipv4/tcp_input.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 83330a6cb24209cf6ac60d634245b7bc151ee6ac..12fda8f27b08bdf5c9f3bad422734f6b1965cef9 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4605,7 +4605,11 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
if (tcp_ooo_try_coalesce(sk, tp->ooo_last_skb,
skb, &fragstolen)) {
coalesce_done:
- tcp_grow_window(sk, skb);
+ /* For non sack flows, do not grow window to force DUPACK
+ * and trigger fast retransmit.
+ */
+ if (tcp_is_sack(tp))
+ tcp_grow_window(sk, skb);
kfree_skb_partial(skb, fragstolen);
skb = NULL;
goto add_sack;
@@ -4689,7 +4693,11 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
tcp_sack_new_ofo_skb(sk, seq, end_seq);
end:
if (skb) {
- tcp_grow_window(sk, skb);
+ /* For non sack flows, do not grow window to force DUPACK
+ * and trigger fast retransmit.
+ */
+ if (tcp_is_sack(tp))
+ tcp_grow_window(sk, skb);
skb_condense(skb);
skb_set_owner_r(skb, sk);
}
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply related
* [PATCH net v3 3/4] net/sched: cls_api: fix nooffloaddevcnt warning dmesg log
From: wenxu @ 2020-06-16 3:19 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu
In-Reply-To: <1592277580-5524-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
When a indr device add in offload success. The block->nooffloaddevcnt
should be 0. After the representor go away. When the dir device go away
the flow_block UNBIND operation with -EOPNOTSUPP which lead the warning
dmesg log.
The block->nooffloaddevcnt should always count for indr block.
even the indr block offload successful. The representor maybe
gone away and the ingress qdisc can work in software mode.
block->nooffloaddevcnt warning with following dmesg log:
[ 760.667058] #####################################################
[ 760.668186] ## TEST test-ecmp-add-vxlan-encap-disable-sriov.sh ##
[ 760.669179] #####################################################
[ 761.780655] :test: Fedora 30 (Thirty)
[ 761.783794] :test: Linux reg-r-vrt-018-180 5.7.0+
[ 761.822890] :test: NIC ens1f0 FW 16.26.6000 PCI 0000:81:00.0 DEVICE 0x1019 ConnectX-5 Ex
[ 761.860244] mlx5_core 0000:81:00.0 ens1f0: Link up
[ 761.880693] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f0: link becomes ready
[ 762.059732] mlx5_core 0000:81:00.1 ens1f1: Link up
[ 762.234341] :test: unbind vfs of ens1f0
[ 762.257825] :test: Change ens1f0 eswitch (0000:81:00.0) mode to switchdev
[ 762.291363] :test: unbind vfs of ens1f1
[ 762.306914] :test: Change ens1f1 eswitch (0000:81:00.1) mode to switchdev
[ 762.309237] mlx5_core 0000:81:00.1: E-Switch: Disable: mode(LEGACY), nvfs(2), active vports(3)
[ 763.282598] mlx5_core 0000:81:00.1: E-Switch: Supported tc offload range - chains: 4294967294, prios: 4294967295
[ 763.362825] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 763.444465] mlx5_core 0000:81:00.1 ens1f1: renamed from eth0
[ 763.460088] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 763.502586] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 763.552429] ens1f1_0: renamed from eth0
[ 763.569569] mlx5_core 0000:81:00.1: E-Switch: Enable: mode(OFFLOADS), nvfs(2), active vports(3)
[ 763.629694] ens1f1_1: renamed from eth1
[ 764.631552] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f1_0: link becomes ready
[ 764.670841] :test: unbind vfs of ens1f0
[ 764.681966] :test: unbind vfs of ens1f1
[ 764.726762] mlx5_core 0000:81:00.0 ens1f0: Link up
[ 764.766511] mlx5_core 0000:81:00.1 ens1f1: Link up
[ 764.797325] :test: Add multipath vxlan encap rule and disable sriov
[ 764.798544] :test: config multipath route
[ 764.812732] mlx5_core 0000:81:00.0: lag map port 1:2 port 2:2
[ 764.874556] mlx5_core 0000:81:00.0: modify lag map port 1:1 port 2:2
[ 765.603681] :test: OK
[ 765.659048] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f1_1: link becomes ready
[ 765.675085] :test: verify rule in hw
[ 765.694237] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f0: link becomes ready
[ 765.711892] IPv6: ADDRCONF(NETDEV_CHANGE): ens1f1: link becomes ready
[ 766.979230] :test: OK
[ 768.125419] :test: OK
[ 768.127519] :test: - disable sriov ens1f1
[ 768.131160] pci 0000:81:02.2: Removing from iommu group 75
[ 768.132646] pci 0000:81:02.3: Removing from iommu group 76
[ 769.179749] mlx5_core 0000:81:00.1: E-Switch: Disable: mode(OFFLOADS), nvfs(2), active vports(3)
[ 769.455627] mlx5_core 0000:81:00.0: modify lag map port 1:1 port 2:1
[ 769.703990] mlx5_core 0000:81:00.1: MLX5E: StrdRq(1) RqSz(8) StrdSz(2048) RxCqeCmprss(0)
[ 769.988637] mlx5_core 0000:81:00.1 ens1f1: renamed from eth0
[ 769.990022] :test: - disable sriov ens1f0
[ 769.994922] pci 0000:81:00.2: Removing from iommu group 73
[ 769.997048] pci 0000:81:00.3: Removing from iommu group 74
[ 771.035813] mlx5_core 0000:81:00.0: E-Switch: Disable: mode(OFFLOADS), nvfs(2), active vports(3)
[ 771.339091] ------------[ cut here ]------------
[ 771.340812] WARNING: CPU: 6 PID: 3448 at net/sched/cls_api.c:749 tcf_block_offload_unbind.isra.0+0x5c/0x60
[ 771.341728] Modules linked in: act_mirred act_tunnel_key cls_flower dummy vxlan ip6_udp_tunnel udp_tunnel sch_ingress nfsv3 nfs_acl nfs lockd grace fscache tun bridge stp llc sunrpc rdma_ucm rdma_cm iw_cm ib_cm mlx5_ib ib_uverbs ib_core mlx5_core intel_rapl_msr intel_rapl_common sb_edac x86_pkg_temp_thermal intel_powerclamp coretemp mlxfw act_ct nf_flow_table kvm_intel nf_nat kvm nf_conntrack irqbypass crct10dif_pclmul igb crc32_pclmul nf_defrag_ipv6 libcrc32c nf_defrag_ipv4 crc32c_intel ghash_clmulni_intel ptp ipmi_ssif intel_cstate pps_c
ore ses intel_uncore mei_me iTCO_wdt joydev ipmi_si iTCO_vendor_support i2c_i801 enclosure mei ioatdma dca lpc_ich wmi ipmi_devintf pcspkr acpi_power_meter ipmi_msghandler acpi_pad ast i2c_algo_bit drm_vram_helper drm_kms_helper drm_ttm_helper ttm drm mpt3sas raid_class scsi_transport_sas
[ 771.347818] CPU: 6 PID: 3448 Comm: test-ecmp-add-v Not tainted 5.7.0+ #1146
[ 771.348727] Hardware name: Supermicro SYS-2028TP-DECR/X10DRT-P, BIOS 2.0b 03/30/2017
[ 771.349646] RIP: 0010:tcf_block_offload_unbind.isra.0+0x5c/0x60
[ 771.350553] Code: 4a fd ff ff 83 f8 a1 74 0e 5b 4c 89 e7 5d 41 5c 41 5d e9 07 93 89 ff 8b 83 a0 00 00 00 8d 50 ff 89 93 a0 00 00 00 85 c0 75 df <0f> 0b eb db 0f 1f 44 00 00 41 57 41 56 41 55 41 89 cd 41 54 49 89
[ 771.352420] RSP: 0018:ffffb33144cd3b00 EFLAGS: 00010246
[ 771.353353] RAX: 0000000000000000 RBX: ffff8b37cf4b2800 RCX: 0000000000000000
[ 771.354294] RDX: 00000000ffffffff RSI: ffff8b3b9aad0000 RDI: ffffffff8d5c6e20
[ 771.355245] RBP: ffff8b37eb546948 R08: ffffffffc0b7a348 R09: ffff8b3b9aad0000
[ 771.356189] R10: 0000000000000001 R11: ffff8b3ba7a0a1c0 R12: ffff8b37cf4b2850
[ 771.357123] R13: ffff8b3b9aad0000 R14: ffff8b37cf4b2820 R15: ffff8b37cf4b2820
[ 771.358039] FS: 00007f8a19b6e740(0000) GS:ffff8b3befa00000(0000) knlGS:0000000000000000
[ 771.358965] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 771.359885] CR2: 00007f3afb91c1a0 CR3: 000000045133c004 CR4: 00000000001606e0
[ 771.360825] Call Trace:
[ 771.361764] __tcf_block_put+0x84/0x150
[ 771.362712] ingress_destroy+0x1b/0x20 [sch_ingress]
[ 771.363658] qdisc_destroy+0x3e/0xc0
[ 771.364594] dev_shutdown+0x7a/0xa5
[ 771.365522] rollback_registered_many+0x20d/0x530
[ 771.366458] ? netdev_upper_dev_unlink+0x15d/0x1c0
[ 771.367387] unregister_netdevice_many.part.0+0xf/0x70
[ 771.368310] vxlan_netdevice_event+0xa4/0x110 [vxlan]
[ 771.369454] notifier_call_chain+0x4c/0x70
[ 771.370579] rollback_registered_many+0x2f5/0x530
[ 771.371719] rollback_registered+0x56/0x90
[ 771.372843] unregister_netdevice_queue+0x73/0xb0
[ 771.373982] unregister_netdev+0x18/0x20
[ 771.375168] mlx5e_vport_rep_unload+0x56/0xc0 [mlx5_core]
[ 771.376327] esw_offloads_disable+0x81/0x90 [mlx5_core]
[ 771.377512] mlx5_eswitch_disable_locked.cold+0xcb/0x1af [mlx5_core]
[ 771.378679] mlx5_eswitch_disable+0x44/0x60 [mlx5_core]
[ 771.379822] mlx5_device_disable_sriov+0xad/0xb0 [mlx5_core]
[ 771.380968] mlx5_core_sriov_configure+0xc1/0xe0 [mlx5_core]
[ 771.382087] sriov_numvfs_store+0xfc/0x130
[ 771.383195] kernfs_fop_write+0xce/0x1b0
[ 771.384302] vfs_write+0xb6/0x1a0
[ 771.385410] ksys_write+0x5f/0xe0
[ 771.386500] do_syscall_64+0x5b/0x1d0
[ 771.387569] entry_SYSCALL_64_after_hwframe+0x44/0xa9
Fixes: 0fdcf78d5973 ("net: use flow_indr_dev_setup_offload()")
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
net/sched/cls_api.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index a00a203..86c3937 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -671,25 +671,29 @@ static int tcf_block_offload_cmd(struct tcf_block *block,
struct netlink_ext_ack *extack)
{
struct flow_block_offload bo = {};
- int err;
tcf_block_offload_init(&bo, dev, command, ei->binder_type,
&block->flow_block, tcf_block_shared(block),
extack);
- if (dev->netdev_ops->ndo_setup_tc)
+ if (dev->netdev_ops->ndo_setup_tc) {
+ int err;
+
err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
- else
- err = flow_indr_dev_setup_offload(dev, TC_SETUP_BLOCK, block,
- &bo, tc_block_indr_cleanup);
+ if (err < 0) {
+ if (err != -EOPNOTSUPP)
+ NL_SET_ERR_MSG(extack, "Driver ndo_setup_tc failed");
+ return err;
+ }
- if (err < 0) {
- if (err != -EOPNOTSUPP)
- NL_SET_ERR_MSG(extack, "Driver ndo_setup_tc failed");
- return err;
+ return tcf_block_setup(block, &bo);
}
- return tcf_block_setup(block, &bo);
+ flow_indr_dev_setup_offload(dev, TC_SETUP_BLOCK, block, &bo,
+ tc_block_indr_cleanup);
+ tcf_block_setup(block, &bo);
+
+ return -EOPNOTSUPP;
}
static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
--
1.8.3.1
^ permalink raw reply related
* [PATCH net v3 1/4] flow_offload: fix incorrect cleanup for flowtable indirect flow_blocks
From: wenxu @ 2020-06-16 3:19 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu
In-Reply-To: <1592277580-5524-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
The cleanup operation based on the setup callback. But in the mlx5e
driver there are tc and flowtable indrict setup callback and shared
the same release callbacks. So when the representor is removed,
then identify the indirect flow_blocks that need to be removed by
the release callback.
Fixes: 1fac52da5942 ("net: flow_offload: consolidate indirect flow_block infrastructure")
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c | 2 +-
drivers/net/ethernet/netronome/nfp/flower/main.c | 2 +-
drivers/net/ethernet/netronome/nfp/flower/main.h | 3 +--
drivers/net/ethernet/netronome/nfp/flower/offload.c | 6 +++---
include/net/flow_offload.h | 2 +-
net/core/flow_offload.c | 9 +++++----
7 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 0eef4f5..ef7f6bc 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -2074,7 +2074,7 @@ void bnxt_shutdown_tc(struct bnxt *bp)
return;
flow_indr_dev_unregister(bnxt_tc_setup_indr_cb, bp,
- bnxt_tc_setup_indr_block_cb);
+ bnxt_tc_setup_indr_rel);
rhashtable_destroy(&tc_info->flow_table);
rhashtable_destroy(&tc_info->l2_table);
rhashtable_destroy(&tc_info->decap_l2_table);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index 80713123..a62bcf0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -496,7 +496,7 @@ int mlx5e_rep_tc_netdevice_event_register(struct mlx5e_rep_priv *rpriv)
void mlx5e_rep_tc_netdevice_event_unregister(struct mlx5e_rep_priv *rpriv)
{
flow_indr_dev_unregister(mlx5e_rep_indr_setup_cb, rpriv,
- mlx5e_rep_indr_setup_tc_cb);
+ mlx5e_rep_indr_block_unbind);
}
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c
index c393276..bb448c8 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.c
@@ -861,7 +861,7 @@ static void nfp_flower_clean(struct nfp_app *app)
flush_work(&app_priv->cmsg_work);
flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app,
- nfp_flower_setup_indr_block_cb);
+ nfp_flower_setup_indr_tc_release);
if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)
nfp_flower_qos_cleanup(app);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 6c3dc3b..c983337 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -460,8 +460,7 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
void nfp_flower_stats_rlim_reply(struct nfp_app *app, struct sk_buff *skb);
int nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
enum tc_setup_type type, void *type_data);
-int nfp_flower_setup_indr_block_cb(enum tc_setup_type type, void *type_data,
- void *cb_priv);
+void nfp_flower_setup_indr_tc_release(void *cb_priv);
void
__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 695d24b9..28de905 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1619,8 +1619,8 @@ struct nfp_flower_indr_block_cb_priv {
return NULL;
}
-int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
- void *type_data, void *cb_priv)
+static int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
+ void *type_data, void *cb_priv)
{
struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
struct flow_cls_offload *flower = type_data;
@@ -1637,7 +1637,7 @@ int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
}
}
-static void nfp_flower_setup_indr_tc_release(void *cb_priv)
+void nfp_flower_setup_indr_tc_release(void *cb_priv)
{
struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index f2c8311..3a2d6b4 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -536,7 +536,7 @@ typedef int flow_indr_block_bind_cb_t(struct net_device *dev, void *cb_priv,
int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv);
void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
- flow_setup_cb_t *setup_cb);
+ void (*release)(void *cb_priv));
int flow_indr_dev_setup_offload(struct net_device *dev,
enum tc_setup_type type, void *data,
struct flow_block_offload *bo,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 0cfc35e..b288d2f 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -372,13 +372,14 @@ int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
}
EXPORT_SYMBOL(flow_indr_dev_register);
-static void __flow_block_indr_cleanup(flow_setup_cb_t *setup_cb, void *cb_priv,
+static void __flow_block_indr_cleanup(void (*release)(void *cb_priv),
+ void *cb_priv,
struct list_head *cleanup_list)
{
struct flow_block_cb *this, *next;
list_for_each_entry_safe(this, next, &flow_block_indr_list, indr.list) {
- if (this->cb == setup_cb &&
+ if (this->release == release &&
this->cb_priv == cb_priv) {
list_move(&this->indr.list, cleanup_list);
return;
@@ -397,7 +398,7 @@ static void flow_block_indr_notify(struct list_head *cleanup_list)
}
void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
- flow_setup_cb_t *setup_cb)
+ void (*release)(void *cb_priv))
{
struct flow_indr_dev *this, *next, *indr_dev = NULL;
LIST_HEAD(cleanup_list);
@@ -418,7 +419,7 @@ void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
return;
}
- __flow_block_indr_cleanup(setup_cb, cb_priv, &cleanup_list);
+ __flow_block_indr_cleanup(release, cb_priv, &cleanup_list);
mutex_unlock(&flow_indr_block_lock);
flow_block_indr_notify(&cleanup_list);
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH v4 1/3] mm/slab: Use memzero_explicit() in kzfree()
From: Eric Biggers @ 2020-06-16 3:30 UTC (permalink / raw)
To: Waiman Long
Cc: Andrew Morton, David Howells, Jarkko Sakkinen, James Morris,
Serge E. Hallyn, Linus Torvalds, Joe Perches, Matthew Wilcox,
David Rientjes, Michal Hocko, Johannes Weiner, Dan Carpenter,
David Sterba, Jason A . Donenfeld, linux-mm, keyrings,
linux-kernel, linux-crypto, linux-pm, linux-stm32, linux-amlogic,
linux-mediatek, linuxppc-dev, virtualization, netdev, linux-ppp,
wireguard, linux-wireless, devel, linux-scsi, target-devel,
linux-btrfs, linux-cifs, linux-fscrypt, ecryptfs, kasan-dev,
linux-bluetooth, linux-wpan, linux-sctp, linux-nfs,
tipc-discussion, linux-security-module, linux-integrity, stable
In-Reply-To: <20200616015718.7812-2-longman@redhat.com>
On Mon, Jun 15, 2020 at 09:57:16PM -0400, Waiman Long wrote:
> The kzfree() function is normally used to clear some sensitive
> information, like encryption keys, in the buffer before freeing it back
> to the pool. Memset() is currently used for the buffer clearing. However,
> it is entirely possible that the compiler may choose to optimize away the
> memory clearing especially if LTO is being used. To make sure that this
> optimization will not happen, memzero_explicit(), which is introduced
> in v3.18, is now used in kzfree() to do the clearing.
>
> Fixes: 3ef0e5ba4673 ("slab: introduce kzfree()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> mm/slab_common.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/mm/slab_common.c b/mm/slab_common.c
> index 9e72ba224175..37d48a56431d 100644
> --- a/mm/slab_common.c
> +++ b/mm/slab_common.c
> @@ -1726,7 +1726,7 @@ void kzfree(const void *p)
> if (unlikely(ZERO_OR_NULL_PTR(mem)))
> return;
> ks = ksize(mem);
> - memset(mem, 0, ks);
> + memzero_explicit(mem, ks);
> kfree(mem);
> }
> EXPORT_SYMBOL(kzfree);
This is a good change, but the commit message isn't really accurate. AFAIK, no
one has found any case where this memset() gets optimized out. And even with
LTO, it would be virtually impossible due to all the synchronization and global
data structures that kfree() uses. (Remember that this isn't the C standard
function "free()", so the compiler can't assign it any special meaning.)
Not to mention that LTO support isn't actually upstream yet.
I still agree with the change, but it might be helpful if the commit message
were honest that this is really a hardening measure and about properly conveying
the intent. As-is this sounds like a critical fix, which might confuse people.
- Eric
^ permalink raw reply
* [PATCH v4 03/11] fs: Add fd_install_received() wrapper for __fd_install_received()
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
For both pidfd and seccomp, the __user pointer is not used. Update
__fd_install_received() to make writing to ufd optional. (ufd
itself cannot checked for NULL because this changes the SCM_RIGHTS
interface behavior.) In these cases, the new fd needs to be returned
on success. Update the existing callers to handle it. Add new wrapper
fd_install_received() for pidfd and seccomp that does not use the ufd
argument.
Signed-off-by: Kees Cook <keescook@chromium.org>
---
fs/file.c | 26 +++++++++++++++++---------
include/linux/file.h | 10 +++++++---
net/compat.c | 2 +-
net/core/scm.c | 2 +-
4 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/fs/file.c b/fs/file.c
index fcfddae0d252..14a8ef74efb2 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -944,11 +944,14 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
* @o_flags: the O_* flags to apply to the new fd entry
*
* Installs a received file into the file descriptor table, with appropriate
- * checks and count updates. Optionally writes the fd number to userspace.
+ * checks and count updates. Optionally writes the fd number to userspace, if
+ * @ufd_required is true (@ufd cannot just be tested for NULL because NULL may
+ * actually get passed into SCM_RIGHTS).
*
- * Returns -ve on error.
+ * Returns newly install fd or -ve on error.
*/
-int __fd_install_received(struct file *file, int __user *ufd, unsigned int o_flags)
+int __fd_install_received(struct file *file, bool ufd_required, int __user *ufd,
+ unsigned int o_flags)
{
struct socket *sock;
int new_fd;
@@ -962,20 +965,25 @@ int __fd_install_received(struct file *file, int __user *ufd, unsigned int o_fla
if (new_fd < 0)
return new_fd;
- error = put_user(new_fd, ufd);
- if (error) {
- put_unused_fd(new_fd);
- return error;
+ if (ufd_required) {
+ error = put_user(new_fd, ufd);
+ if (error) {
+ put_unused_fd(new_fd);
+ return error;
+ }
}
- /* Bump the usage count and install the file. */
+ /* Bump the usage count and install the file. The resulting value of
+ * "error" is ignored here since we only need to take action when
+ * the file is a socket and testing "sock" for NULL is sufficient.
+ */
sock = sock_from_file(file, &error);
if (sock) {
sock_update_netprioidx(&sock->sk->sk_cgrp_data);
sock_update_classid(&sock->sk->sk_cgrp_data);
}
fd_install(new_fd, get_file(file));
- return 0;
+ return new_fd;
}
static int ksys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
diff --git a/include/linux/file.h b/include/linux/file.h
index fe18a1a0d555..999a2c56db07 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -91,12 +91,16 @@ extern void put_unused_fd(unsigned int fd);
extern void fd_install(unsigned int fd, struct file *file);
-extern int __fd_install_received(struct file *file, int __user *ufd,
- unsigned int o_flags);
+extern int __fd_install_received(struct file *file, bool ufd_required,
+ int __user *ufd, unsigned int o_flags);
static inline int fd_install_received_user(struct file *file, int __user *ufd,
unsigned int o_flags)
{
- return __fd_install_received(file, ufd, o_flags);
+ return __fd_install_received(file, true, ufd, o_flags);
+}
+static inline int fd_install_received(struct file *file, unsigned int o_flags)
+{
+ return __fd_install_received(file, false, NULL, o_flags);
}
extern void flush_delayed_fput(void);
diff --git a/net/compat.c b/net/compat.c
index 94f288e8dac5..71494337cca7 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -299,7 +299,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
for (i = 0; i < fdmax; i++) {
err = fd_install_received_user(scm->fp->fp[i], cmsg_data + i, o_flags);
- if (err)
+ if (err < 0)
break;
}
diff --git a/net/core/scm.c b/net/core/scm.c
index df190f1fdd28..b9a0442ebd26 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -307,7 +307,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
for (i = 0; i < fdmax; i++) {
err = fd_install_received_user(scm->fp->fp[i], cmsg_data + i, o_flags);
- if (err)
+ if (err < 0)
break;
}
--
2.25.1
^ permalink raw reply related
* [PATCH v4 02/11] fs: Move __scm_install_fd() to __fd_install_received()
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
In preparation for users of the "install a received file" logic outside
of net/ (pidfd and seccomp), relocate and rename __scm_install_fd() from
net/core/scm.c to __fd_install_received() in fs/file.c, and provide a
wrapper named fd_install_received_user(), as future patches will change
the interface to __fd_install_received().
Signed-off-by: Kees Cook <keescook@chromium.org>
---
fs/file.c | 47 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/file.h | 8 ++++++++
include/net/scm.h | 1 -
net/compat.c | 2 +-
net/core/scm.c | 32 +-----------------------------
5 files changed, 57 insertions(+), 33 deletions(-)
diff --git a/fs/file.c b/fs/file.c
index abb8b7081d7a..fcfddae0d252 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -11,6 +11,7 @@
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/net.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/file.h>
@@ -18,6 +19,8 @@
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
+#include <net/cls_cgroup.h>
+#include <net/netprio_cgroup.h>
unsigned int sysctl_nr_open __read_mostly = 1024*1024;
unsigned int sysctl_nr_open_min = BITS_PER_LONG;
@@ -931,6 +934,50 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
return err;
}
+/**
+ * __fd_install_received() - Install received file into file descriptor table
+ *
+ * @fd: fd to install into (if negative, a new fd will be allocated)
+ * @file: struct file that was received from another process
+ * @ufd_required: true to use @ufd for writing fd number to userspace
+ * @ufd: __user pointer to write new fd number to
+ * @o_flags: the O_* flags to apply to the new fd entry
+ *
+ * Installs a received file into the file descriptor table, with appropriate
+ * checks and count updates. Optionally writes the fd number to userspace.
+ *
+ * Returns -ve on error.
+ */
+int __fd_install_received(struct file *file, int __user *ufd, unsigned int o_flags)
+{
+ struct socket *sock;
+ int new_fd;
+ int error;
+
+ error = security_file_receive(file);
+ if (error)
+ return error;
+
+ new_fd = get_unused_fd_flags(o_flags);
+ if (new_fd < 0)
+ return new_fd;
+
+ error = put_user(new_fd, ufd);
+ if (error) {
+ put_unused_fd(new_fd);
+ return error;
+ }
+
+ /* Bump the usage count and install the file. */
+ sock = sock_from_file(file, &error);
+ if (sock) {
+ sock_update_netprioidx(&sock->sk->sk_cgrp_data);
+ sock_update_classid(&sock->sk->sk_cgrp_data);
+ }
+ fd_install(new_fd, get_file(file));
+ return 0;
+}
+
static int ksys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
{
int err = -EBADF;
diff --git a/include/linux/file.h b/include/linux/file.h
index 122f80084a3e..fe18a1a0d555 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -91,6 +91,14 @@ extern void put_unused_fd(unsigned int fd);
extern void fd_install(unsigned int fd, struct file *file);
+extern int __fd_install_received(struct file *file, int __user *ufd,
+ unsigned int o_flags);
+static inline int fd_install_received_user(struct file *file, int __user *ufd,
+ unsigned int o_flags)
+{
+ return __fd_install_received(file, ufd, o_flags);
+}
+
extern void flush_delayed_fput(void);
extern void __fput_sync(struct file *);
diff --git a/include/net/scm.h b/include/net/scm.h
index 581a94d6c613..1ce365f4c256 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -37,7 +37,6 @@ struct scm_cookie {
#endif
};
-int __scm_install_fd(struct file *file, int __user *ufd, unsigned int o_flags);
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
diff --git a/net/compat.c b/net/compat.c
index 27d477fdcaa0..94f288e8dac5 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -298,7 +298,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
int err = 0, i;
for (i = 0; i < fdmax; i++) {
- err = __scm_install_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
+ err = fd_install_received_user(scm->fp->fp[i], cmsg_data + i, o_flags);
if (err)
break;
}
diff --git a/net/core/scm.c b/net/core/scm.c
index 6151678c73ed..df190f1fdd28 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -280,36 +280,6 @@ void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_inter
}
EXPORT_SYMBOL(put_cmsg_scm_timestamping);
-int __scm_install_fd(struct file *file, int __user *ufd, unsigned int o_flags)
-{
- struct socket *sock;
- int new_fd;
- int error;
-
- error = security_file_receive(file);
- if (error)
- return error;
-
- new_fd = get_unused_fd_flags(o_flags);
- if (new_fd < 0)
- return new_fd;
-
- error = put_user(new_fd, ufd);
- if (error) {
- put_unused_fd(new_fd);
- return error;
- }
-
- /* Bump the usage count and install the file. */
- sock = sock_from_file(file, &error);
- if (sock) {
- sock_update_netprioidx(&sock->sk->sk_cgrp_data);
- sock_update_classid(&sock->sk->sk_cgrp_data);
- }
- fd_install(new_fd, get_file(file));
- return 0;
-}
-
static int scm_max_fds(struct msghdr *msg)
{
if (msg->msg_controllen <= sizeof(struct cmsghdr))
@@ -336,7 +306,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
}
for (i = 0; i < fdmax; i++) {
- err = __scm_install_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
+ err = fd_install_received_user(scm->fp->fp[i], cmsg_data + i, o_flags);
if (err)
break;
}
--
2.25.1
^ permalink raw reply related
* [PATCH v4 00/11] Add seccomp notifier ioctl that enables adding fds
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
Hello!
This is a bit of thread-merge between [1] and [2]. tl;dr: add a way for
a seccomp user_notif process manager to inject files into the managed
process in order to handle emulation of various fd-returning syscalls
across security boundaries. Containers folks and Chrome are in need
of the feature, and investigating this solution uncovered (and fixed)
implementation issues with existing file sending routines.
I intend to carry this in the seccomp tree, unless someone has objections.
:) Please review and test!
-Kees
[1] https://lore.kernel.org/lkml/20200603011044.7972-1-sargun@sargun.me/
[2] https://lore.kernel.org/lkml/20200610045214.1175600-1-keescook@chromium.org/
Kees Cook (9):
net/scm: Regularize compat handling of scm_detach_fds()
fs: Move __scm_install_fd() to __fd_install_received()
fs: Add fd_install_received() wrapper for __fd_install_received()
pidfd: Replace open-coded partial fd_install_received()
fs: Expand __fd_install_received() to accept fd
selftests/seccomp: Make kcmp() less required
selftests/seccomp: Rename user_trap_syscall() to user_notif_syscall()
seccomp: Switch addfd to Extensible Argument ioctl
seccomp: Fix ioctl number for SECCOMP_IOCTL_NOTIF_ID_VALID
Sargun Dhillon (2):
seccomp: Introduce addfd ioctl to seccomp user notifier
selftests/seccomp: Test SECCOMP_IOCTL_NOTIF_ADDFD
fs/file.c | 65 ++++
include/linux/file.h | 16 +
include/uapi/linux/seccomp.h | 25 +-
kernel/pid.c | 11 +-
kernel/seccomp.c | 181 ++++++++-
net/compat.c | 55 ++-
net/core/scm.c | 50 +--
tools/testing/selftests/seccomp/seccomp_bpf.c | 350 +++++++++++++++---
8 files changed, 618 insertions(+), 135 deletions(-)
--
2.25.1
^ permalink raw reply
* [PATCH v4 05/11] fs: Expand __fd_install_received() to accept fd
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
Expand __fd_install_received() with support for replace_fd() for the
coming seccomp "addfd" ioctl(). Add new wrapper fd_replace_received()
for the new mode and update existing wrappers to retain old mode.
Signed-off-by: Kees Cook <keescook@chromium.org>
---
fs/file.c | 22 ++++++++++++++++------
include/linux/file.h | 10 +++++++---
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/fs/file.c b/fs/file.c
index 14a8ef74efb2..b583e7c60571 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -950,8 +950,8 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
*
* Returns newly install fd or -ve on error.
*/
-int __fd_install_received(struct file *file, bool ufd_required, int __user *ufd,
- unsigned int o_flags)
+int __fd_install_received(int fd, struct file *file, bool ufd_required,
+ int __user *ufd, unsigned int o_flags)
{
struct socket *sock;
int new_fd;
@@ -961,9 +961,11 @@ int __fd_install_received(struct file *file, bool ufd_required, int __user *ufd,
if (error)
return error;
- new_fd = get_unused_fd_flags(o_flags);
- if (new_fd < 0)
- return new_fd;
+ if (fd < 0) {
+ new_fd = get_unused_fd_flags(o_flags);
+ if (new_fd < 0)
+ return new_fd;
+ }
if (ufd_required) {
error = put_user(new_fd, ufd);
@@ -973,6 +975,15 @@ int __fd_install_received(struct file *file, bool ufd_required, int __user *ufd,
}
}
+ if (fd < 0)
+ fd_install(new_fd, get_file(file));
+ else {
+ new_fd = fd;
+ error = replace_fd(new_fd, file, o_flags);
+ if (error)
+ return error;
+ }
+
/* Bump the usage count and install the file. The resulting value of
* "error" is ignored here since we only need to take action when
* the file is a socket and testing "sock" for NULL is sufficient.
@@ -982,7 +993,6 @@ int __fd_install_received(struct file *file, bool ufd_required, int __user *ufd,
sock_update_netprioidx(&sock->sk->sk_cgrp_data);
sock_update_classid(&sock->sk->sk_cgrp_data);
}
- fd_install(new_fd, get_file(file));
return new_fd;
}
diff --git a/include/linux/file.h b/include/linux/file.h
index 999a2c56db07..f1d16e24a12e 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -91,16 +91,20 @@ extern void put_unused_fd(unsigned int fd);
extern void fd_install(unsigned int fd, struct file *file);
-extern int __fd_install_received(struct file *file, bool ufd_required,
+extern int __fd_install_received(int fd, struct file *file, bool ufd_required,
int __user *ufd, unsigned int o_flags);
static inline int fd_install_received_user(struct file *file, int __user *ufd,
unsigned int o_flags)
{
- return __fd_install_received(file, true, ufd, o_flags);
+ return __fd_install_received(-1, file, true, ufd, o_flags);
}
static inline int fd_install_received(struct file *file, unsigned int o_flags)
{
- return __fd_install_received(file, false, NULL, o_flags);
+ return __fd_install_received(-1, file, false, NULL, o_flags);
+}
+static inline int fd_replace_received(int fd, struct file *file, unsigned int o_flags)
+{
+ return __fd_install_received(fd, file, false, NULL, o_flags);
}
extern void flush_delayed_fput(void);
--
2.25.1
^ permalink raw reply related
* [PATCH v4 07/11] selftests/seccomp: Test SECCOMP_IOCTL_NOTIF_ADDFD
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
From: Sargun Dhillon <sargun@sargun.me>
Test whether we can add file descriptors in response to notifications.
This injects the file descriptors via notifications, and then uses
kcmp to determine whether or not it has been successful.
It also includes some basic sanity checking for arguments.
Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Link: https://lore.kernel.org/r/20200603011044.7972-5-sargun@sargun.me
Signed-off-by: Kees Cook <keescook@chromium.org>
---
tools/testing/selftests/seccomp/seccomp_bpf.c | 188 ++++++++++++++++++
1 file changed, 188 insertions(+)
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index 402ccb3a4e52..c4e264b37c30 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -45,6 +45,7 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/kcmp.h>
+#include <sys/resource.h>
#include <unistd.h>
#include <sys/syscall.h>
@@ -168,7 +169,9 @@ struct seccomp_metadata {
#ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER
#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3)
+#endif
+#ifndef SECCOMP_RET_USER_NOTIF
#define SECCOMP_RET_USER_NOTIF 0x7fc00000U
#define SECCOMP_IOC_MAGIC '!'
@@ -204,6 +207,24 @@ struct seccomp_notif_sizes {
};
#endif
+#ifndef SECCOMP_IOCTL_NOTIF_ADDFD
+/* On success, the return value is the remote process's added fd number */
+#define SECCOMP_IOCTL_NOTIF_ADDFD SECCOMP_IOW(3, \
+ struct seccomp_notif_addfd)
+
+/* valid flags for seccomp_notif_addfd */
+#define SECCOMP_ADDFD_FLAG_SETFD (1UL << 0) /* Specify remote fd */
+
+struct seccomp_notif_addfd {
+ __u64 size;
+ __u64 id;
+ __u32 flags;
+ __u32 srcfd;
+ __u32 newfd;
+ __u32 newfd_flags;
+};
+#endif
+
#ifndef PTRACE_EVENTMSG_SYSCALL_ENTRY
#define PTRACE_EVENTMSG_SYSCALL_ENTRY 1
#define PTRACE_EVENTMSG_SYSCALL_EXIT 2
@@ -3822,6 +3843,173 @@ TEST(user_notification_filter_empty_threaded)
EXPECT_GT((pollfd.revents & POLLHUP) ?: 0, 0);
}
+TEST(user_notification_sendfd)
+{
+ pid_t pid;
+ long ret;
+ int status, listener, memfd;
+ struct seccomp_notif_addfd addfd = {};
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+ /* 100 ms */
+ struct timespec delay = { .tv_nsec = 100000000 };
+
+ memfd = memfd_create("test", 0);
+ ASSERT_GE(memfd, 0);
+
+ ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ ASSERT_EQ(0, ret) {
+ TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
+ }
+
+ /* Check that the basic notification machinery works */
+ listener = user_trap_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ ASSERT_GE(listener, 0);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ if (syscall(__NR_getppid) != USER_NOTIF_MAGIC)
+ exit(1);
+ exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
+ }
+
+ ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+
+ addfd.size = sizeof(addfd);
+ addfd.srcfd = memfd;
+ addfd.newfd_flags = O_CLOEXEC;
+ addfd.newfd = 0;
+ addfd.id = req.id;
+ addfd.flags = 0xff;
+
+ /* Verify bad flags cannot be set */
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ /* Verify that remote_fd cannot be set without setting flags */
+ addfd.flags = 0;
+ addfd.newfd = 1;
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ /* Verify we can set an arbitrary remote fd */
+ addfd.newfd = 0;
+
+ ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
+ EXPECT_GE(ret, 0);
+ EXPECT_EQ(filecmp(getpid(), pid, memfd, ret), 0);
+
+ /* Verify we can set a specific remote fd */
+ addfd.newfd = 42;
+ addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), 42);
+ EXPECT_EQ(filecmp(getpid(), pid, memfd, 42), 0);
+
+ resp.id = req.id;
+ resp.error = 0;
+ resp.val = USER_NOTIF_MAGIC;
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+
+ /*
+ * This sets the ID of the ADD FD to the last request plus 1. The
+ * notification ID increments 1 per notification.
+ */
+ addfd.id = req.id + 1;
+
+ /* This spins until the underlying notification is generated */
+ while (ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd) != -1 &&
+ errno != -EINPROGRESS)
+ nanosleep(&delay, NULL);
+
+ memset(&req, 0, sizeof(req));
+ ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+ ASSERT_EQ(addfd.id, req.id);
+
+ resp.id = req.id;
+ resp.error = 0;
+ resp.val = USER_NOTIF_MAGIC;
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+
+ close(memfd);
+}
+
+TEST(user_notification_sendfd_rlimit)
+{
+ pid_t pid;
+ long ret;
+ int status, listener, memfd;
+ struct seccomp_notif_addfd addfd = {};
+ struct seccomp_notif req = {};
+ struct seccomp_notif_resp resp = {};
+ const struct rlimit lim = {
+ .rlim_cur = 0,
+ .rlim_max = 0,
+ };
+
+ memfd = memfd_create("test", 0);
+ ASSERT_GE(memfd, 0);
+
+ ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ ASSERT_EQ(0, ret) {
+ TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
+ }
+
+ /* Check that the basic notification machinery works */
+ listener = user_trap_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ ASSERT_GE(listener, 0);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0)
+ exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
+
+
+ ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+
+ ASSERT_EQ(prlimit(pid, RLIMIT_NOFILE, &lim, NULL), 0);
+
+ addfd.size = sizeof(addfd);
+ addfd.srcfd = memfd;
+ addfd.newfd_flags = O_CLOEXEC;
+ addfd.newfd = 0;
+ addfd.id = req.id;
+ addfd.flags = 0;
+
+ /* Should probably spot check /proc/sys/fs/file-nr */
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
+ EXPECT_EQ(errno, EMFILE);
+
+ addfd.newfd = 100;
+ addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
+ EXPECT_EQ(errno, EBADF);
+
+ resp.id = req.id;
+ resp.error = 0;
+ resp.val = USER_NOTIF_MAGIC;
+
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+
+ close(memfd);
+}
+
/*
* TODO:
* - expand NNP testing
--
2.25.1
^ permalink raw reply related
* [PATCH v4 09/11] selftests/seccomp: Rename user_trap_syscall() to user_notif_syscall()
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
The user_trap_syscall() helper creates a filter with
SECCOMP_RET_USER_NOTIF. To avoid confusion with SECCOMP_RET_TRAP, rename
the helper to user_notif_syscall().
Additionally fix a redundant "return" after XFAIL.
Signed-off-by: Kees Cook <keescook@chromium.org>
---
tools/testing/selftests/seccomp/seccomp_bpf.c | 60 +++++++++----------
1 file changed, 29 insertions(+), 31 deletions(-)
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index 40ed846744e4..95b134933831 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -3110,10 +3110,8 @@ TEST(get_metadata)
long ret;
/* Only real root can get metadata. */
- if (geteuid()) {
- XFAIL(return, "get_metadata requires real root");
- return;
- }
+ if (geteuid())
+ XFAIL(return, "get_metadata test requires real root");
ASSERT_EQ(0, pipe(pipefd));
@@ -3170,7 +3168,7 @@ TEST(get_metadata)
ASSERT_EQ(0, kill(pid, SIGKILL));
}
-static int user_trap_syscall(int nr, unsigned int flags)
+static int user_notif_syscall(int nr, unsigned int flags)
{
struct sock_filter filter[] = {
BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
@@ -3216,7 +3214,7 @@ TEST(user_notification_basic)
/* Check that we get -ENOSYS with no listener attached */
if (pid == 0) {
- if (user_trap_syscall(__NR_getppid, 0) < 0)
+ if (user_notif_syscall(__NR_getppid, 0) < 0)
exit(1);
ret = syscall(__NR_getppid);
exit(ret >= 0 || errno != ENOSYS);
@@ -3233,13 +3231,13 @@ TEST(user_notification_basic)
EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
/* Check that the basic notification machinery works */
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
/* Installing a second listener in the chain should EBUSY */
- EXPECT_EQ(user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER),
+ EXPECT_EQ(user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER),
-1);
EXPECT_EQ(errno, EBUSY);
@@ -3303,12 +3301,12 @@ TEST(user_notification_with_tsync)
/* these were exclusive */
flags = SECCOMP_FILTER_FLAG_NEW_LISTENER |
SECCOMP_FILTER_FLAG_TSYNC;
- ASSERT_EQ(-1, user_trap_syscall(__NR_getppid, flags));
+ ASSERT_EQ(-1, user_notif_syscall(__NR_getppid, flags));
ASSERT_EQ(EINVAL, errno);
/* but now they're not */
flags |= SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
- ret = user_trap_syscall(__NR_getppid, flags);
+ ret = user_notif_syscall(__NR_getppid, flags);
close(ret);
ASSERT_LE(0, ret);
}
@@ -3326,8 +3324,8 @@ TEST(user_notification_kill_in_middle)
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
}
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
/*
@@ -3380,8 +3378,8 @@ TEST(user_notification_signal)
ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
- listener = user_trap_syscall(__NR_gettid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_gettid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
pid = fork();
@@ -3450,8 +3448,8 @@ TEST(user_notification_closed_listener)
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
}
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
/*
@@ -3484,8 +3482,8 @@ TEST(user_notification_child_pid_ns)
ASSERT_EQ(unshare(CLONE_NEWUSER | CLONE_NEWPID), 0);
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
pid = fork();
@@ -3524,8 +3522,8 @@ TEST(user_notification_sibling_pid_ns)
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
}
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
pid = fork();
@@ -3589,8 +3587,8 @@ TEST(user_notification_fault_recv)
ASSERT_EQ(unshare(CLONE_NEWUSER), 0);
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
pid = fork();
@@ -3641,7 +3639,7 @@ TEST(user_notification_continue)
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
}
- listener = user_trap_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
pid = fork();
@@ -3736,7 +3734,7 @@ TEST(user_notification_filter_empty)
if (pid == 0) {
int listener;
- listener = user_trap_syscall(__NR_mknod, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_mknod, SECCOMP_FILTER_FLAG_NEW_LISTENER);
if (listener < 0)
_exit(EXIT_FAILURE);
@@ -3792,7 +3790,7 @@ TEST(user_notification_filter_empty_threaded)
int listener, status;
pthread_t thread;
- listener = user_trap_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
if (listener < 0)
_exit(EXIT_FAILURE);
@@ -3869,8 +3867,8 @@ TEST(user_notification_sendfd)
}
/* Check that the basic notification machinery works */
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
pid = fork();
@@ -3993,8 +3991,8 @@ TEST(user_notification_sendfd_rlimit)
}
/* Check that the basic notification machinery works */
- listener = user_trap_syscall(__NR_getppid,
- SECCOMP_FILTER_FLAG_NEW_LISTENER);
+ listener = user_notif_syscall(__NR_getppid,
+ SECCOMP_FILTER_FLAG_NEW_LISTENER);
ASSERT_GE(listener, 0);
pid = fork();
--
2.25.1
^ permalink raw reply related
* [PATCH v4 06/11] seccomp: Introduce addfd ioctl to seccomp user notifier
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Matt Denton, Christian Brauner,
David S. Miller, Christoph Hellwig, Tycho Andersen,
Jakub Kicinski, Alexander Viro, Aleksa Sarai, Jann Horn,
Chris Palmer, Robert Sesek, Giuseppe Scrivano, Greg Kroah-Hartman,
Andy Lutomirski, Will Drewry, Shuah Khan, netdev, containers,
linux-api, linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
From: Sargun Dhillon <sargun@sargun.me>
This adds a seccomp notifier ioctl which allows for the listener to
"add" file descriptors to a process which originated a seccomp user
notification. This allows calls like mount, and mknod to be "implemented",
as the return value, and the arguments are data in memory. On the other
hand, calls like connect can be "implemented" using pidfd_getfd.
Unfortunately, there are calls which return file descriptors, like
open, which are vulnerable to ToCToU attacks, and require that the more
privileged supervisor can inspect the argument, and perform the syscall
on behalf of the process generating the notification. This allows the
file descriptor generated from that open call to be returned to the
calling process.
In addition, there is functionality to allow for replacement of specific
file descriptors, following dup2-like semantics.
As a note, the seccomp_notif_addfd structure is laid out based on 8-byte
alignment without requiring packing as there have been packing issues
with uapi highlighted before[1][2]. Although we could overload the
newfd field and use -1 to indicate that it is not to be used, doing
so requires changing the size of the fd field, and introduces struct
packing complexity.
[1]: https://lore.kernel.org/lkml/87o8w9bcaf.fsf@mid.deneb.enyo.de/
[2]: https://lore.kernel.org/lkml/a328b91d-fd8f-4f27-b3c2-91a9c45f18c0@rasmusvillemoes.dk/
Suggested-by: Matt Denton <mpdenton@google.com>
Link: https://lore.kernel.org/r/20200603011044.7972-4-sargun@sargun.me
Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Signed-off-by: Kees Cook <keescook@chromium.org>
---
include/uapi/linux/seccomp.h | 25 ++++++
kernel/seccomp.c | 165 ++++++++++++++++++++++++++++++++++-
2 files changed, 189 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index c1735455bc53..c347160378e5 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -113,6 +113,27 @@ struct seccomp_notif_resp {
__u32 flags;
};
+/* valid flags for seccomp_notif_addfd */
+#define SECCOMP_ADDFD_FLAG_SETFD (1UL << 0) /* Specify remote fd */
+
+/**
+ * struct seccomp_notif_addfd
+ * @size: The size of the seccomp_notif_addfd structure
+ * @id: The ID of the seccomp notification
+ * @flags: SECCOMP_ADDFD_FLAG_*
+ * @srcfd: The local fd number
+ * @newfd: Optional remote FD number if SETFD option is set, otherwise 0.
+ * @newfd_flags: The O_* flags the remote FD should have applied
+ */
+struct seccomp_notif_addfd {
+ __u64 size;
+ __u64 id;
+ __u32 flags;
+ __u32 srcfd;
+ __u32 newfd;
+ __u32 newfd_flags;
+};
+
#define SECCOMP_IOC_MAGIC '!'
#define SECCOMP_IO(nr) _IO(SECCOMP_IOC_MAGIC, nr)
#define SECCOMP_IOR(nr, type) _IOR(SECCOMP_IOC_MAGIC, nr, type)
@@ -124,4 +145,8 @@ struct seccomp_notif_resp {
#define SECCOMP_IOCTL_NOTIF_SEND SECCOMP_IOWR(1, \
struct seccomp_notif_resp)
#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOR(2, __u64)
+/* On success, the return value is the remote process's added fd number */
+#define SECCOMP_IOCTL_NOTIF_ADDFD SECCOMP_IOW(3, \
+ struct seccomp_notif_addfd)
+
#endif /* _UAPI_LINUX_SECCOMP_H */
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 0016cad0e605..3c913f3b8451 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -78,10 +78,42 @@ struct seccomp_knotif {
long val;
u32 flags;
- /* Signals when this has entered SECCOMP_NOTIFY_REPLIED */
+ /*
+ * Signals when this has changed states, such as the listener
+ * dying, a new seccomp addfd message, or changing to REPLIED
+ */
struct completion ready;
struct list_head list;
+
+ /* outstanding addfd requests */
+ struct list_head addfd;
+};
+
+/**
+ * struct seccomp_kaddfd - container for seccomp_addfd ioctl messages
+ *
+ * @file: A reference to the file to install in the other task
+ * @fd: The fd number to install it at. If the fd number is -1, it means the
+ * installing process should allocate the fd as normal.
+ * @flags: The flags for the new file descriptor. At the moment, only O_CLOEXEC
+ * is allowed.
+ * @ret: The return value of the installing process. It is set to the fd num
+ * upon success (>= 0).
+ * @completion: Indicates that the installing process has completed fd
+ * installation, or gone away (either due to successful
+ * reply, or signal)
+ *
+ */
+struct seccomp_kaddfd {
+ struct file *file;
+ int fd;
+ unsigned int flags;
+
+ /* To only be set on reply */
+ int ret;
+ struct completion completion;
+ struct list_head list;
};
/**
@@ -784,6 +816,17 @@ static u64 seccomp_next_notify_id(struct seccomp_filter *filter)
return filter->notif->next_id++;
}
+static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd)
+{
+ /*
+ * Remove the notification, and reset the list pointers, indicating
+ * that it has been handled.
+ */
+ list_del_init(&addfd->list);
+ addfd->ret = fd_replace_received(addfd->fd, addfd->file, addfd->flags);
+ complete(&addfd->completion);
+}
+
static int seccomp_do_user_notification(int this_syscall,
struct seccomp_filter *match,
const struct seccomp_data *sd)
@@ -792,6 +835,7 @@ static int seccomp_do_user_notification(int this_syscall,
u32 flags = 0;
long ret = 0;
struct seccomp_knotif n = {};
+ struct seccomp_kaddfd *addfd, *tmp;
mutex_lock(&match->notify_lock);
err = -ENOSYS;
@@ -804,6 +848,7 @@ static int seccomp_do_user_notification(int this_syscall,
n.id = seccomp_next_notify_id(match);
init_completion(&n.ready);
list_add(&n.list, &match->notif->notifications);
+ INIT_LIST_HEAD(&n.addfd);
up(&match->notif->request);
wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM);
@@ -812,14 +857,31 @@ static int seccomp_do_user_notification(int this_syscall,
/*
* This is where we wait for a reply from userspace.
*/
+wait:
err = wait_for_completion_interruptible(&n.ready);
mutex_lock(&match->notify_lock);
if (err == 0) {
+ /* Check if we were woken up by a addfd message */
+ addfd = list_first_entry_or_null(&n.addfd,
+ struct seccomp_kaddfd, list);
+ if (addfd && n.state != SECCOMP_NOTIFY_REPLIED) {
+ seccomp_handle_addfd(addfd);
+ mutex_unlock(&match->notify_lock);
+ goto wait;
+ }
ret = n.val;
err = n.error;
flags = n.flags;
}
+ /* If there were any pending addfd calls, clear them out */
+ list_for_each_entry_safe(addfd, tmp, &n.addfd, list) {
+ /* The process went away before we got a chance to handle it */
+ addfd->ret = -ESRCH;
+ list_del_init(&addfd->list);
+ complete(&addfd->completion);
+ }
+
/*
* Note that it's possible the listener died in between the time when
* we were notified of a respons (or a signal) and when we were able to
@@ -1060,6 +1122,11 @@ static int seccomp_notify_release(struct inode *inode, struct file *file)
knotif->error = -ENOSYS;
knotif->val = 0;
+ /*
+ * We do not need to wake up any pending addfd messages, as
+ * the notifier will do that for us, as this just looks
+ * like a standard reply.
+ */
complete(&knotif->ready);
}
@@ -1224,6 +1291,100 @@ static long seccomp_notify_id_valid(struct seccomp_filter *filter,
return ret;
}
+static long seccomp_notify_addfd(struct seccomp_filter *filter,
+ struct seccomp_notif_addfd __user *uaddfd)
+{
+ struct seccomp_notif_addfd addfd;
+ struct seccomp_knotif *knotif;
+ struct seccomp_kaddfd kaddfd;
+ u64 size;
+ int ret;
+
+ ret = get_user(size, &uaddfd->size);
+ if (ret)
+ return ret;
+
+ ret = copy_struct_from_user(&addfd, sizeof(addfd), uaddfd, size);
+ if (ret)
+ return ret;
+
+ if (addfd.newfd_flags & ~O_CLOEXEC)
+ return -EINVAL;
+
+ if (addfd.flags & ~SECCOMP_ADDFD_FLAG_SETFD)
+ return -EINVAL;
+
+ if (addfd.newfd && !(addfd.flags & SECCOMP_ADDFD_FLAG_SETFD))
+ return -EINVAL;
+
+ kaddfd.file = fget(addfd.srcfd);
+ if (!kaddfd.file)
+ return -EBADF;
+
+ kaddfd.flags = addfd.newfd_flags;
+ kaddfd.fd = (addfd.flags & SECCOMP_ADDFD_FLAG_SETFD) ?
+ addfd.newfd : -1;
+ init_completion(&kaddfd.completion);
+
+ ret = mutex_lock_interruptible(&filter->notify_lock);
+ if (ret < 0)
+ goto out;
+
+ knotif = find_notification(filter, addfd.id);
+ if (!knotif) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ /*
+ * We do not want to allow for FD injection to occur before the
+ * notification has been picked up by a userspace handler, or after
+ * the notification has been replied to.
+ */
+ if (knotif->state != SECCOMP_NOTIFY_SENT) {
+ ret = -EINPROGRESS;
+ goto out_unlock;
+ }
+
+ list_add(&kaddfd.list, &knotif->addfd);
+ complete(&knotif->ready);
+ mutex_unlock(&filter->notify_lock);
+
+ /* Now we wait for it to be processed or be interrupted */
+ ret = wait_for_completion_interruptible(&kaddfd.completion);
+ if (ret == 0) {
+ /*
+ * We had a successful completion. The other side has already
+ * removed us from the addfd queue, and
+ * wait_for_completion_interruptible has a memory barrier upon
+ * success that lets us read this value directly without
+ * locking.
+ */
+ ret = kaddfd.ret;
+ goto out;
+ }
+
+ mutex_lock(&filter->notify_lock);
+ /*
+ * Even though we were woken up by a signal and not a successful
+ * completion, a completion may have happened in the mean time.
+ *
+ * We need to check again if the addfd request has been handled,
+ * and if not, we will remove it from the queue.
+ */
+ if (list_empty(&kaddfd.list))
+ ret = kaddfd.ret;
+ else
+ list_del(&kaddfd.list);
+
+out_unlock:
+ mutex_unlock(&filter->notify_lock);
+out:
+ fput(kaddfd.file);
+
+ return ret;
+}
+
static long seccomp_notify_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -1237,6 +1398,8 @@ static long seccomp_notify_ioctl(struct file *file, unsigned int cmd,
return seccomp_notify_send(filter, buf);
case SECCOMP_IOCTL_NOTIF_ID_VALID:
return seccomp_notify_id_valid(filter, buf);
+ case SECCOMP_IOCTL_NOTIF_ADDFD:
+ return seccomp_notify_addfd(filter, buf);
default:
return -EINVAL;
}
--
2.25.1
^ permalink raw reply related
* [PATCH v4 11/11] seccomp: Fix ioctl number for SECCOMP_IOCTL_NOTIF_ID_VALID
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, stable, Sargun Dhillon, Christian Brauner,
David S. Miller, Christoph Hellwig, Tycho Andersen,
Jakub Kicinski, Alexander Viro, Aleksa Sarai, Matt Denton,
Jann Horn, Chris Palmer, Robert Sesek, Giuseppe Scrivano,
Greg Kroah-Hartman, Andy Lutomirski, Will Drewry, Shuah Khan,
netdev, containers, linux-api, linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
When SECCOMP_IOCTL_NOTIF_ID_VALID was first introduced it had the wrong
direction flag set. While this isn't a big deal as nothing currently
enforces these bits in the kernel, it should be defined correctly. Fix
the define and provide support for the old command until it is no longer
needed for backward compatibility.
Fixes: 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace")
Cc: stable@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
---
include/uapi/linux/seccomp.h | 2 +-
kernel/seccomp.c | 9 +++++++++
tools/testing/selftests/seccomp/seccomp_bpf.c | 2 +-
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index 473a61695ac3..6ba18b82a02e 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -142,7 +142,7 @@ struct seccomp_notif_addfd {
#define SECCOMP_IOCTL_NOTIF_RECV SECCOMP_IOWR(0, struct seccomp_notif)
#define SECCOMP_IOCTL_NOTIF_SEND SECCOMP_IOWR(1, \
struct seccomp_notif_resp)
-#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOR(2, __u64)
+#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOW(2, __u64)
/* On success, the return value is the remote process's added fd number */
#define SECCOMP_IOCTL_NOTIF_ADDFD SECCOMP_IOW(3, \
struct seccomp_notif_addfd)
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 9660abf91135..61e556bca338 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -43,6 +43,14 @@
#include <linux/anon_inodes.h>
#include <linux/lockdep.h>
+/*
+ * When SECCOMP_IOCTL_NOTIF_ID_VALID was first introduced, it had the
+ * wrong direction flag in the ioctl number. This is the broken one,
+ * which the kernel needs to keep supporting until all userspaces stop
+ * using the wrong command number.
+ */
+#define SECCOMP_IOCTL_NOTIF_ID_VALID_WRONG_DIR SECCOMP_IOR(2, __u64)
+
enum notify_state {
SECCOMP_NOTIFY_INIT,
SECCOMP_NOTIFY_SENT,
@@ -1397,6 +1405,7 @@ static long seccomp_notify_ioctl(struct file *file, unsigned int cmd,
return seccomp_notify_recv(filter, buf);
case SECCOMP_IOCTL_NOTIF_SEND:
return seccomp_notify_send(filter, buf);
+ case SECCOMP_IOCTL_NOTIF_ID_VALID_WRONG_DIR:
case SECCOMP_IOCTL_NOTIF_ID_VALID:
return seccomp_notify_id_valid(filter, buf);
}
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index cf1480e498ea..403c6d0f149e 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -184,7 +184,7 @@ struct seccomp_metadata {
#define SECCOMP_IOCTL_NOTIF_RECV SECCOMP_IOWR(0, struct seccomp_notif)
#define SECCOMP_IOCTL_NOTIF_SEND SECCOMP_IOWR(1, \
struct seccomp_notif_resp)
-#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOR(2, __u64)
+#define SECCOMP_IOCTL_NOTIF_ID_VALID SECCOMP_IOW(2, __u64)
struct seccomp_notif {
__u64 id;
--
2.25.1
^ permalink raw reply related
* [PATCH v4 08/11] selftests/seccomp: Make kcmp() less required
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
The seccomp tests are a bit noisy without CONFIG_CHECKPOINT_RESTORE (due
to missing the kcmp() syscall). The seccomp tests are more accurate with
kcmp(), but it's not strictly required. Refactor the tests to use
alternatives (comparing fd numbers), and provide a central test for
kcmp() so there is a single XFAIL instead of many. Continue to produce
warnings for the other tests, though.
Additionally adds some more bad flag EINVAL tests to the addfd selftest.
Signed-off-by: Kees Cook <keescook@chromium.org>
---
tools/testing/selftests/seccomp/seccomp_bpf.c | 100 +++++++++++-------
1 file changed, 64 insertions(+), 36 deletions(-)
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index c4e264b37c30..40ed846744e4 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -258,6 +258,27 @@ int seccomp(unsigned int op, unsigned int flags, void *args)
#define SIBLING_EXIT_FAILURE 0xbadface
#define SIBLING_EXIT_NEWPRIVS 0xbadfeed
+static int filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
+{
+#ifdef __NR_kcmp
+ errno = 0;
+ return syscall(__NR_kcmp, pid1, pid2, KCMP_FILE, fd1, fd2);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+TEST(kcmp)
+{
+ int ret;
+
+ ret = filecmp(getpid(), getpid(), 1, 1);
+ EXPECT_EQ(ret, 0);
+ if (ret != 0 && errno == ENOSYS)
+ XFAIL(return, "Kernel does not support kcmp() (missing CONFIG_CHECKPOINT_RESTORE?)");
+}
+
TEST(mode_strict_support)
{
long ret;
@@ -3606,16 +3627,6 @@ TEST(seccomp_get_notif_sizes)
EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp));
}
-static int filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
-{
-#ifdef __NR_kcmp
- return syscall(__NR_kcmp, pid1, pid2, KCMP_FILE, fd1, fd2);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
TEST(user_notification_continue)
{
pid_t pid;
@@ -3640,20 +3651,20 @@ TEST(user_notification_continue)
int dup_fd, pipe_fds[2];
pid_t self;
- ret = pipe(pipe_fds);
- if (ret < 0)
- exit(1);
+ ASSERT_GE(pipe(pipe_fds), 0);
dup_fd = dup(pipe_fds[0]);
- if (dup_fd < 0)
- exit(1);
+ ASSERT_GE(dup_fd, 0);
+ EXPECT_NE(pipe_fds[0], dup_fd);
self = getpid();
-
ret = filecmp(self, self, pipe_fds[0], dup_fd);
- if (ret)
- exit(2);
-
+ if (ret != 0) {
+ if (ret < 0 && errno == ENOSYS) {
+ TH_LOG("kcmp() syscall missing (test is less accurate)");
+ } else
+ ASSERT_EQ(ret, 0);
+ }
exit(0);
}
@@ -3700,12 +3711,7 @@ TEST(user_notification_continue)
skip:
EXPECT_EQ(waitpid(pid, &status, 0), pid);
EXPECT_EQ(true, WIFEXITED(status));
- EXPECT_EQ(0, WEXITSTATUS(status)) {
- if (WEXITSTATUS(status) == 2) {
- XFAIL(return, "Kernel does not support kcmp() syscall");
- return;
- }
- }
+ EXPECT_EQ(0, WEXITSTATUS(status));
}
TEST(user_notification_filter_empty)
@@ -3847,7 +3853,7 @@ TEST(user_notification_sendfd)
{
pid_t pid;
long ret;
- int status, listener, memfd;
+ int status, listener, memfd, fd;
struct seccomp_notif_addfd addfd = {};
struct seccomp_notif req = {};
struct seccomp_notif_resp resp = {};
@@ -3880,34 +3886,56 @@ TEST(user_notification_sendfd)
addfd.size = sizeof(addfd);
addfd.srcfd = memfd;
- addfd.newfd_flags = O_CLOEXEC;
addfd.newfd = 0;
addfd.id = req.id;
- addfd.flags = 0xff;
+ addfd.flags = 0;
+
+ /* Verify bad newfd_flags cannot be set */
+ addfd.newfd_flags = ~O_CLOEXEC;
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
+ EXPECT_EQ(errno, EINVAL);
+ addfd.newfd_flags = O_CLOEXEC;
/* Verify bad flags cannot be set */
+ addfd.flags = 0xff;
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
EXPECT_EQ(errno, EINVAL);
+ addfd.flags = 0;
/* Verify that remote_fd cannot be set without setting flags */
- addfd.flags = 0;
addfd.newfd = 1;
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
EXPECT_EQ(errno, EINVAL);
-
- /* Verify we can set an arbitrary remote fd */
addfd.newfd = 0;
- ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
- EXPECT_GE(ret, 0);
- EXPECT_EQ(filecmp(getpid(), pid, memfd, ret), 0);
+ /* Verify we can set an arbitrary remote fd */
+ fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
+ /*
+ * The child has fds 0(stdin), 1(stdout), 2(stderr), 3(memfd),
+ * 4(listener), so the newly allocated fd should be 5.
+ */
+ EXPECT_EQ(fd, 5);
+ ret = filecmp(getpid(), pid, memfd, fd);
+ if (ret != 0) {
+ if (ret < 0 && errno == ENOSYS) {
+ TH_LOG("kcmp() syscall missing (test is less accurate)");
+ } else
+ EXPECT_EQ(ret, 0);
+ }
/* Verify we can set a specific remote fd */
addfd.newfd = 42;
addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
- EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), 42);
- EXPECT_EQ(filecmp(getpid(), pid, memfd, 42), 0);
+ fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
+ EXPECT_EQ(fd, 42);
+ ret = filecmp(getpid(), pid, memfd, fd);
+ if (ret != 0) {
+ if (ret < 0 && errno == ENOSYS) {
+ TH_LOG("kcmp() syscall missing (test is less accurate)");
+ } else
+ EXPECT_EQ(ret, 0);
+ }
resp.id = req.id;
resp.error = 0;
--
2.25.1
^ permalink raw reply related
* [PATCH v4 10/11] seccomp: Switch addfd to Extensible Argument ioctl
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
This patch is based on discussions[1] with Sargun Dhillon, Christian
Brauner, and David Laight. Instead of building size into the addfd
structure, make it a function of the ioctl command (which is how sizes are
normally passed to ioctls). To support forward and backward compatibility,
just mask out the direction and size, and match everything. The size (and
any future direction) checks are done along with copy_struct_from_user()
logic. Also update the selftests to check size bounds.
[1] https://lore.kernel.org/lkml/20200612104629.GA15814@ircssh-2.c.rugged-nimbus-611.internal
Signed-off-by: Kees Cook <keescook@chromium.org>
---
include/uapi/linux/seccomp.h | 2 -
kernel/seccomp.c | 21 ++++++----
tools/testing/selftests/seccomp/seccomp_bpf.c | 40 ++++++++++++++++---
3 files changed, 49 insertions(+), 14 deletions(-)
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index c347160378e5..473a61695ac3 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -118,7 +118,6 @@ struct seccomp_notif_resp {
/**
* struct seccomp_notif_addfd
- * @size: The size of the seccomp_notif_addfd structure
* @id: The ID of the seccomp notification
* @flags: SECCOMP_ADDFD_FLAG_*
* @srcfd: The local fd number
@@ -126,7 +125,6 @@ struct seccomp_notif_resp {
* @newfd_flags: The O_* flags the remote FD should have applied
*/
struct seccomp_notif_addfd {
- __u64 size;
__u64 id;
__u32 flags;
__u32 srcfd;
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 3c913f3b8451..9660abf91135 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1292,17 +1292,17 @@ static long seccomp_notify_id_valid(struct seccomp_filter *filter,
}
static long seccomp_notify_addfd(struct seccomp_filter *filter,
- struct seccomp_notif_addfd __user *uaddfd)
+ struct seccomp_notif_addfd __user *uaddfd,
+ unsigned int size)
{
struct seccomp_notif_addfd addfd;
struct seccomp_knotif *knotif;
struct seccomp_kaddfd kaddfd;
- u64 size;
int ret;
- ret = get_user(size, &uaddfd->size);
- if (ret)
- return ret;
+ /* 24 is original sizeof(struct seccomp_notif_addfd) */
+ if (size < 24 || size >= PAGE_SIZE)
+ return -EINVAL;
ret = copy_struct_from_user(&addfd, sizeof(addfd), uaddfd, size);
if (ret)
@@ -1391,6 +1391,7 @@ static long seccomp_notify_ioctl(struct file *file, unsigned int cmd,
struct seccomp_filter *filter = file->private_data;
void __user *buf = (void __user *)arg;
+ /* Fixed-size ioctls */
switch (cmd) {
case SECCOMP_IOCTL_NOTIF_RECV:
return seccomp_notify_recv(filter, buf);
@@ -1398,11 +1399,17 @@ static long seccomp_notify_ioctl(struct file *file, unsigned int cmd,
return seccomp_notify_send(filter, buf);
case SECCOMP_IOCTL_NOTIF_ID_VALID:
return seccomp_notify_id_valid(filter, buf);
- case SECCOMP_IOCTL_NOTIF_ADDFD:
- return seccomp_notify_addfd(filter, buf);
+ }
+
+ /* Extensible Argument ioctls */
+#define EA_IOCTL(cmd) ((cmd) & ~(IOC_INOUT | IOCSIZE_MASK))
+ switch (EA_IOCTL(cmd)) {
+ case EA_IOCTL(SECCOMP_IOCTL_NOTIF_ADDFD):
+ return seccomp_notify_addfd(filter, buf, _IOC_SIZE(cmd));
default:
return -EINVAL;
}
+#undef EA_IOCTL
}
static __poll_t seccomp_notify_poll(struct file *file,
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index 95b134933831..cf1480e498ea 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -216,7 +216,6 @@ struct seccomp_notif_sizes {
#define SECCOMP_ADDFD_FLAG_SETFD (1UL << 0) /* Specify remote fd */
struct seccomp_notif_addfd {
- __u64 size;
__u64 id;
__u32 flags;
__u32 srcfd;
@@ -225,6 +224,22 @@ struct seccomp_notif_addfd {
};
#endif
+struct seccomp_notif_addfd_small {
+ __u64 id;
+ char weird[4];
+};
+#define SECCOMP_IOCTL_NOTIF_ADDFD_SMALL \
+ SECCOMP_IOW(3, struct seccomp_notif_addfd_small)
+
+struct seccomp_notif_addfd_big {
+ union {
+ struct seccomp_notif_addfd addfd;
+ char buf[sizeof(struct seccomp_notif_addfd) + 8];
+ };
+};
+#define SECCOMP_IOCTL_NOTIF_ADDFD_BIG \
+ SECCOMP_IOWR(3, struct seccomp_notif_addfd_big)
+
#ifndef PTRACE_EVENTMSG_SYSCALL_ENTRY
#define PTRACE_EVENTMSG_SYSCALL_ENTRY 1
#define PTRACE_EVENTMSG_SYSCALL_EXIT 2
@@ -3853,6 +3868,8 @@ TEST(user_notification_sendfd)
long ret;
int status, listener, memfd, fd;
struct seccomp_notif_addfd addfd = {};
+ struct seccomp_notif_addfd_small small = {};
+ struct seccomp_notif_addfd_big big = {};
struct seccomp_notif req = {};
struct seccomp_notif_resp resp = {};
/* 100 ms */
@@ -3882,7 +3899,6 @@ TEST(user_notification_sendfd)
ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
- addfd.size = sizeof(addfd);
addfd.srcfd = memfd;
addfd.newfd = 0;
addfd.id = req.id;
@@ -3906,6 +3922,16 @@ TEST(user_notification_sendfd)
EXPECT_EQ(errno, EINVAL);
addfd.newfd = 0;
+ /* Verify small size cannot be set */
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_SMALL, &small), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ /* Verify we can't send bits filled in unknown buffer area */
+ memset(&big, 0xAA, sizeof(big));
+ big.addfd = addfd;
+ EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_BIG, &big), -1);
+ EXPECT_EQ(errno, E2BIG);
+
/* Verify we can set an arbitrary remote fd */
fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
/*
@@ -3921,10 +3947,15 @@ TEST(user_notification_sendfd)
EXPECT_EQ(ret, 0);
}
+ /* Verify we can set an arbitrary remote fd with large size */
+ memset(&big, 0x0, sizeof(big));
+ big.addfd = addfd;
+ fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_BIG, &big);
+ EXPECT_EQ(fd, 6);
+
/* Verify we can set a specific remote fd */
addfd.newfd = 42;
addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
-
fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
EXPECT_EQ(fd, 42);
ret = filecmp(getpid(), pid, memfd, fd);
@@ -3935,10 +3966,10 @@ TEST(user_notification_sendfd)
EXPECT_EQ(ret, 0);
}
+ /* Resume syscall */
resp.id = req.id;
resp.error = 0;
resp.val = USER_NOTIF_MAGIC;
-
EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
/*
@@ -4006,7 +4037,6 @@ TEST(user_notification_sendfd_rlimit)
ASSERT_EQ(prlimit(pid, RLIMIT_NOFILE, &lim, NULL), 0);
- addfd.size = sizeof(addfd);
addfd.srcfd = memfd;
addfd.newfd_flags = O_CLOEXEC;
addfd.newfd = 0;
--
2.25.1
^ permalink raw reply related
* [PATCH v4 04/11] pidfd: Replace open-coded partial fd_install_received()
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
The sock counting (sock_update_netprioidx() and sock_update_classid()) was
missing from pidfd's implementation of received fd installation. Replace
the open-coded version with a call to the new fd_install_received()
helper.
Fixes: 8649c322f75c ("pid: Implement pidfd_getfd syscall")
Signed-off-by: Kees Cook <keescook@chromium.org>
---
kernel/pid.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/kernel/pid.c b/kernel/pid.c
index f1496b757162..24924ec5df0e 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -635,18 +635,9 @@ static int pidfd_getfd(struct pid *pid, int fd)
if (IS_ERR(file))
return PTR_ERR(file);
- ret = security_file_receive(file);
- if (ret) {
- fput(file);
- return ret;
- }
-
- ret = get_unused_fd_flags(O_CLOEXEC);
+ ret = fd_install_received(file, O_CLOEXEC);
if (ret < 0)
fput(file);
- else
- fd_install(ret, file);
-
return ret;
}
--
2.25.1
^ permalink raw reply related
* [PATCH v4 01/11] net/scm: Regularize compat handling of scm_detach_fds()
From: Kees Cook @ 2020-06-16 3:25 UTC (permalink / raw)
To: linux-kernel
Cc: Kees Cook, Sargun Dhillon, Christian Brauner, David S. Miller,
Christoph Hellwig, Tycho Andersen, Jakub Kicinski, Alexander Viro,
Aleksa Sarai, Matt Denton, Jann Horn, Chris Palmer, Robert Sesek,
Giuseppe Scrivano, Greg Kroah-Hartman, Andy Lutomirski,
Will Drewry, Shuah Khan, netdev, containers, linux-api,
linux-fsdevel, linux-kselftest
In-Reply-To: <20200616032524.460144-1-keescook@chromium.org>
Duplicate the cleanups from commit 2618d530dd8b ("net/scm: cleanup
scm_detach_fds") into the compat code.
Move the check added in commit 1f466e1f15cf ("net: cleanly handle kernel
vs user buffers for ->msg_control") to before the compat call, even
though it should be impossible for an in-kernel call to also be compat.
Correct the int "flags" argument to unsigned int to match fd_install()
and similar APIs.
Regularize any remaining differences, including a whitespace issue,
a checkpatch warning, and add the check from commit 6900317f5eff ("net,
scm: fix PaX detected msg_controllen overflow in scm_detach_fds") which
fixed an overflow unique to 64-bit. To avoid confusion when comparing
the compat handler to the native handler, just include the same check
in the compat handler.
Fixes: 48a87cc26c13 ("net: netprio: fd passed in SCM_RIGHTS datagram not set correctly")
Fixes: d84295067fc7 ("net: net_cls: fd passed in SCM_RIGHTS datagram not set correctly")
Signed-off-by: Kees Cook <keescook@chromium.org>
---
include/net/scm.h | 1 +
net/compat.c | 55 +++++++++++++++++++++--------------------------
net/core/scm.c | 18 ++++++++--------
3 files changed, 35 insertions(+), 39 deletions(-)
diff --git a/include/net/scm.h b/include/net/scm.h
index 1ce365f4c256..581a94d6c613 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -37,6 +37,7 @@ struct scm_cookie {
#endif
};
+int __scm_install_fd(struct file *file, int __user *ufd, unsigned int o_flags);
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
diff --git a/net/compat.c b/net/compat.c
index 5e3041a2c37d..27d477fdcaa0 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -281,39 +281,31 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
return 0;
}
-void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
+static int scm_max_fds_compat(struct msghdr *msg)
{
- struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
- int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
- int fdnum = scm->fp->count;
- struct file **fp = scm->fp->fp;
- int __user *cmfptr;
- int err = 0, i;
+ if (msg->msg_controllen <= sizeof(struct compat_cmsghdr))
+ return 0;
+ return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
+}
- if (fdnum < fdmax)
- fdmax = fdnum;
+void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
+{
+ struct compat_cmsghdr __user *cm =
+ (struct compat_cmsghdr __user *)msg->msg_control;
+ unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
+ int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count);
+ int __user *cmsg_data = CMSG_USER_DATA(cm);
+ int err = 0, i;
- for (i = 0, cmfptr = (int __user *) CMSG_COMPAT_DATA(cm); i < fdmax; i++, cmfptr++) {
- int new_fd;
- err = security_file_receive(fp[i]);
+ for (i = 0; i < fdmax; i++) {
+ err = __scm_install_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
if (err)
break;
- err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags
- ? O_CLOEXEC : 0);
- if (err < 0)
- break;
- new_fd = err;
- err = put_user(new_fd, cmfptr);
- if (err) {
- put_unused_fd(new_fd);
- break;
- }
- /* Bump the usage count and install the file. */
- fd_install(new_fd, get_file(fp[i]));
}
if (i > 0) {
int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
+
err = put_user(SOL_SOCKET, &cm->cmsg_level);
if (!err)
err = put_user(SCM_RIGHTS, &cm->cmsg_type);
@@ -321,16 +313,19 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
err = put_user(cmlen, &cm->cmsg_len);
if (!err) {
cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
- kmsg->msg_control += cmlen;
- kmsg->msg_controllen -= cmlen;
+ if (msg->msg_controllen < cmlen)
+ cmlen = msg->msg_controllen;
+ msg->msg_control += cmlen;
+ msg->msg_controllen -= cmlen;
}
}
- if (i < fdnum)
- kmsg->msg_flags |= MSG_CTRUNC;
+
+ if (i < scm->fp->count || (scm->fp->count && fdmax <= 0))
+ msg->msg_flags |= MSG_CTRUNC;
/*
- * All of the files that fit in the message have had their
- * usage counts incremented, so we just free the list.
+ * All of the files that fit in the message have had their usage counts
+ * incremented, so we just free the list.
*/
__scm_destroy(scm);
}
diff --git a/net/core/scm.c b/net/core/scm.c
index 875df1c2989d..6151678c73ed 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -280,7 +280,7 @@ void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_inter
}
EXPORT_SYMBOL(put_cmsg_scm_timestamping);
-static int __scm_install_fd(struct file *file, int __user *ufd, int o_flags)
+int __scm_install_fd(struct file *file, int __user *ufd, unsigned int o_flags)
{
struct socket *sock;
int new_fd;
@@ -319,29 +319,29 @@ static int scm_max_fds(struct msghdr *msg)
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
{
- struct cmsghdr __user *cm
- = (__force struct cmsghdr __user*)msg->msg_control;
- int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
+ struct cmsghdr __user *cm =
+ (__force struct cmsghdr __user *)msg->msg_control;
+ unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
int fdmax = min_t(int, scm_max_fds(msg), scm->fp->count);
int __user *cmsg_data = CMSG_USER_DATA(cm);
int err = 0, i;
+ /* no use for FD passing from kernel space callers */
+ if (WARN_ON_ONCE(!msg->msg_control_is_user))
+ return;
+
if (msg->msg_flags & MSG_CMSG_COMPAT) {
scm_detach_fds_compat(msg, scm);
return;
}
- /* no use for FD passing from kernel space callers */
- if (WARN_ON_ONCE(!msg->msg_control_is_user))
- return;
-
for (i = 0; i < fdmax; i++) {
err = __scm_install_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
if (err)
break;
}
- if (i > 0) {
+ if (i > 0) {
int cmlen = CMSG_LEN(i * sizeof(int));
err = put_user(SOL_SOCKET, &cm->cmsg_level);
--
2.25.1
^ permalink raw reply related
* [PATCH net v3 4/4] flow_offload: fix the list_del corruption in the driver list
From: wenxu @ 2020-06-16 3:19 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu
In-Reply-To: <1592277580-5524-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
When a indr device add in offload success. After the representor
go away. All the flow_block_cb cleanup but miss del form driver
list.
Fixes: 0fdcf78d5973 ("net: use flow_indr_dev_setup_offload()")
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
net/netfilter/nf_flow_table_offload.c | 1 +
net/netfilter/nf_tables_offload.c | 1 +
net/sched/cls_api.c | 1 +
3 files changed, 3 insertions(+)
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index 62651e6..5fff1e0 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -950,6 +950,7 @@ static void nf_flow_table_indr_cleanup(struct flow_block_cb *block_cb)
nf_flow_table_gc_cleanup(flowtable, dev);
down_write(&flowtable->flow_block_lock);
list_del(&block_cb->list);
+ list_del(&block_cb->driver_list);
flow_block_cb_free(block_cb);
up_write(&flowtable->flow_block_lock);
}
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
index 185fc82..c7cf1cd 100644
--- a/net/netfilter/nf_tables_offload.c
+++ b/net/netfilter/nf_tables_offload.c
@@ -296,6 +296,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb)
nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
basechain, &extack);
mutex_lock(&net->nft.commit_mutex);
+ list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list);
nft_flow_offload_unbind(&bo, basechain);
mutex_unlock(&net->nft.commit_mutex);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 86c3937..faa78b7 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -652,6 +652,7 @@ static void tc_block_indr_cleanup(struct flow_block_cb *block_cb)
&block->flow_block, tcf_block_shared(block),
&extack);
down_write(&block->cb_lock);
+ list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list);
up_write(&block->cb_lock);
rtnl_lock();
--
1.8.3.1
^ permalink raw reply related
* [PATCH net v3 2/4] flow_offload: fix incorrect cb_priv check for flow_block_cb
From: wenxu @ 2020-06-16 3:19 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu
In-Reply-To: <1592277580-5524-1-git-send-email-wenxu@ucloud.cn>
From: wenxu <wenxu@ucloud.cn>
In the function __flow_block_indr_cleanup, The match stataments
this->cb_priv == cb_priv is always false, the flow_block_cb->cb_priv
is totally different data with the flow_indr_dev->cb_priv.
Store the representor cb_priv to the flow_block_cb->indr.cb_priv in
the driver.
Fixes: 1fac52da5942 ("net: flow_offload: consolidate indirect flow_block infrastructure")
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 1 +
drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c | 2 +-
drivers/net/ethernet/netronome/nfp/flower/offload.c | 1 +
include/net/flow_offload.h | 1 +
net/core/flow_offload.c | 2 +-
5 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index ef7f6bc..042c285 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -1918,6 +1918,7 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, &bnxt_block_cb_list);
+ block_cb->indr.cb_priv = bp;
break;
case FLOW_BLOCK_UNBIND:
cb_priv = bnxt_tc_indr_block_cb_lookup(bp, netdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index a62bcf0..187f84c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -447,7 +447,7 @@ static void mlx5e_rep_indr_block_unbind(void *cb_priv)
}
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, &mlx5e_block_cb_list);
-
+ block_cb->indr.cb_priv = rpriv;
return 0;
case FLOW_BLOCK_UNBIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 28de905..ca2f01a 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1687,6 +1687,7 @@ void nfp_flower_setup_indr_tc_release(void *cb_priv)
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, &nfp_block_cb_list);
+ block_cb->indr.cb_priv = app;
return 0;
case FLOW_BLOCK_UNBIND:
cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 3a2d6b4..ef4d8b0 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -450,6 +450,7 @@ struct flow_block_indr {
struct net_device *dev;
enum flow_block_binder_type binder_type;
void *data;
+ void *cb_priv;
void (*cleanup)(struct flow_block_cb *block_cb);
};
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index b288d2f..6614351 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -380,7 +380,7 @@ static void __flow_block_indr_cleanup(void (*release)(void *cb_priv),
list_for_each_entry_safe(this, next, &flow_block_indr_list, indr.list) {
if (this->release == release &&
- this->cb_priv == cb_priv) {
+ this->indr.cb_priv == cb_priv) {
list_move(&this->indr.list, cleanup_list);
return;
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH net v3 0/4] several fixes for indirect flow_blocks offload
From: wenxu @ 2020-06-16 3:19 UTC (permalink / raw)
To: netdev; +Cc: davem, pablo, vladbu
From: wenxu <wenxu@ucloud.cn>
v2:
patch2: store the cb_priv of representor to the flow_block_cb->indr.cb_priv
in the driver. And make the correct check with the statments
this->indr.cb_priv == cb_priv
patch4: del the driver list only in the indriect cleanup callbacks
v3:
add the cover letter and changlogs.
This series fixes commit 1fac52da5942 ("net: flow_offload: consolidate
indirect flow_block infrastructure") that revists the flow_block
infrastructure.
The first patch fix the miss cleanup for flowtable indirect flow_block.
The cleanup operation based on the setup callback. But in the mlx5e
driver there are tc and flowtable indrict setup callback and shared
the same release callbacks. So when the representor is removed,
then identify the indirect flow_blocks that need to be removed by
the release callback.
The second patch fix the incorrect cb_priv check in flow_block_cb.
In the function __flow_block_indr_cleanup, stataments
this->cb_priv == cb_priv is always false(the flow_block_cb->cb_priv
is totally different data with the flow_indr_dev->cb_priv). So there
will always miss cleanup when the HW goaway and lead the memory leak.
After fix the first two patches. When the HW goaway, the indirect
flow_block can be cleanup. But It takes another two problem.
The third patch fix block->nooffloaddevcnt warning dmesg log.
When a indr device add in offload success. The block->nooffloaddevcnt
should be 0. After the representor go away. When the dir device go away
the flow_block UNBIND operation with -EOPNOTSUPP which lead the warning
demesg log.
The block->nooffloaddevcnt should always count for indr block.
even the indr block offload successful. The representor maybe
gone away and the ingress qdisc can work in software mode.
The last patch fix the list_del corruption in the driver list.
When a indr device add in offload success. After the representor
go away. All the flow_block_cb cleanup but miss del form driver
list.
All the problem can be reproduce through making real hw go away
after setup the block offoaded.
wenxu (4):
flow_offload: fix incorrect cleanup for indirect flow_blocks
flow_offload: fix incorrect cb_priv check for flow_block_cb
net/sched: cls_api: fix nooffloaddevcnt warning dmesg log
flow_offload: fix the list_del corruption in the driver list
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 3 ++-
.../net/ethernet/mellanox/mlx5/core/en/rep/tc.c | 4 ++--
drivers/net/ethernet/netronome/nfp/flower/main.c | 2 +-
drivers/net/ethernet/netronome/nfp/flower/main.h | 3 +--
.../net/ethernet/netronome/nfp/flower/offload.c | 7 +++---
include/net/flow_offload.h | 3 ++-
net/core/flow_offload.c | 11 +++++-----
net/netfilter/nf_flow_table_offload.c | 1 +
net/netfilter/nf_tables_offload.c | 1 +
net/sched/cls_api.c | 25 +++++++++++++---------
10 files changed, 35 insertions(+), 25 deletions(-)
--
1.8.3.1
^ permalink raw reply
* Re: [PATCH v3 03/13] RDMA/rds: Remove FMR support for memory registration
From: santosh.shilimkar @ 2020-06-16 2:33 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: linux-rdma, netdev, aron.silverton, Max Gurtovoy, oren, shlomin,
vladimirk
In-Reply-To: <20200529191248.GB21651@ziepe.ca>
On 5/29/20 12:12 PM, Jason Gunthorpe wrote:
> On Thu, May 28, 2020 at 01:21:33PM -0700, santosh.shilimkar@oracle.com wrote:
>> On 5/28/20 12:45 PM, Jason Gunthorpe wrote:
>>> From: Max Gurtovoy <maxg@mellanox.com>
>>>
>>> Use FRWR method for memory registration by default and remove the ancient
>>> and unsafe FMR method.
>>>
>>> Signed-off-by: Max Gurtovoy <maxg@mellanox.com>
>>> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
>>
>>> net/rds/Makefile | 2 +-
>>> net/rds/ib.c | 20 ++--
>>> net/rds/ib.h | 2 -
>>> net/rds/ib_cm.c | 4 +-
>>> net/rds/ib_fmr.c | 269 ----------------------------------------------
>>> net/rds/ib_frmr.c | 4 +-
>>> net/rds/ib_mr.h | 14 +--
>>> net/rds/ib_rdma.c | 28 ++---
>>> 8 files changed, 21 insertions(+), 322 deletions(-)
>>> delete mode 100644 net/rds/ib_fmr.c
>>>
>> Patch looks accurate to me Jason/Max. I wanted to get few regression
>> tests run with it before providing the ack. Will send a note once
>> its tested ok.
>
> Okay, since we are at the merge window I'm going to put it in
> linux-next to look for build regressions with the idea to send it on
> Thursday
>
I know you sent this to net-next already but just to close the loop,
regression testing went ok.
Regards,
Santosh
^ permalink raw reply
* [PATCH 1/1] openvswitch: fix infoleak in conntrack
From: Xidong Wang @ 2020-06-16 2:13 UTC (permalink / raw)
To: Xidong Wang, Pravin B Shelar, David S . Miller, Jakub Kicinski,
netdev, dev, linux-kernel
From: xidongwang <wangxidong_97@163.com>
The stack object “zone_limit” has 3 members. In function
ovs_ct_limit_get_default_limit(), the member "count" is
not initialized and sent out via “nla_put_nohdr”.
Signed-off-by: xidongwang <wangxidong_97@163.com>
---
net/openvswitch/conntrack.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index 4340f25..1b7820a 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -2020,6 +2020,7 @@ static int ovs_ct_limit_get_default_limit(struct ovs_ct_limit_info *info,
{
struct ovs_zone_limit zone_limit;
int err;
+ memset(&zone_limit, 0, sizeof(zone_limit));
zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE;
zone_limit.limit = info->default_limit;
--
2.7.4
^ permalink raw reply related
* [PATCH 5/5] Huawei BMA: Adding Huawei BMA driver: host_kbox_drv
From: yunaixin03610 @ 2020-06-16 2:05 UTC (permalink / raw)
To: netdev; +Cc: yunaixin
From: yunaixin <yunaixin@huawei.com>
The BMA software is a system management software offered by Huawei. It supports the status monitoring, performance monitoring, and event monitoring of various components, including server CPUs, memory, hard disks, NICs, IB cards, PCIe cards, RAID controller cards, and optical modules.
The host_kbox_drv driver serves the function of a black box. When a panic or mce event happen to the system, it will record the event time, system's status and system logs and send them to BMC before the OS shutdown. This driver depends on the host_edms_drv driver.
Signed-off-by: yunaixin <yunaixin@huawei.com>
---
drivers/net/ethernet/huawei/bma/Kconfig | 1 +
drivers/net/ethernet/huawei/bma/Makefile | 1 +
.../net/ethernet/huawei/bma/kbox_drv/Kconfig | 11 +
.../net/ethernet/huawei/bma/kbox_drv/Makefile | 2 +
.../ethernet/huawei/bma/kbox_drv/kbox_dump.c | 122 +++
.../ethernet/huawei/bma/kbox_drv/kbox_dump.h | 33 +
.../ethernet/huawei/bma/kbox_drv/kbox_hook.c | 101 ++
.../ethernet/huawei/bma/kbox_drv/kbox_hook.h | 33 +
.../huawei/bma/kbox_drv/kbox_include.h | 42 +
.../ethernet/huawei/bma/kbox_drv/kbox_main.c | 168 +++
.../ethernet/huawei/bma/kbox_drv/kbox_main.h | 23 +
.../ethernet/huawei/bma/kbox_drv/kbox_mce.c | 264 +++++
.../ethernet/huawei/bma/kbox_drv/kbox_mce.h | 23 +
.../ethernet/huawei/bma/kbox_drv/kbox_panic.c | 187 ++++
.../ethernet/huawei/bma/kbox_drv/kbox_panic.h | 25 +
.../huawei/bma/kbox_drv/kbox_printk.c | 362 +++++++
.../huawei/bma/kbox_drv/kbox_printk.h | 33 +
.../huawei/bma/kbox_drv/kbox_ram_drive.c | 188 ++++
.../huawei/bma/kbox_drv/kbox_ram_drive.h | 31 +
.../huawei/bma/kbox_drv/kbox_ram_image.c | 135 +++
.../huawei/bma/kbox_drv/kbox_ram_image.h | 84 ++
.../huawei/bma/kbox_drv/kbox_ram_op.c | 986 ++++++++++++++++++
.../huawei/bma/kbox_drv/kbox_ram_op.h | 77 ++
23 files changed, 2932 insertions(+)
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/Kconfig
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/Makefile
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.h
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c
create mode 100644 drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.h
diff --git a/drivers/net/ethernet/huawei/bma/Kconfig b/drivers/net/ethernet/huawei/bma/Kconfig
index 90b267c265e0..77041669d4b4 100644
--- a/drivers/net/ethernet/huawei/bma/Kconfig
+++ b/drivers/net/ethernet/huawei/bma/Kconfig
@@ -1,4 +1,5 @@
source "drivers/net/ethernet/huawei/bma/edma_drv/Kconfig"
source "drivers/net/ethernet/huawei/bma/cdev_drv/Kconfig"
source "drivers/net/ethernet/huawei/bma/veth_drv/Kconfig"
+source "drivers/net/ethernet/huawei/bma/kbox_drv/Kconfig"
source "drivers/net/ethernet/huawei/bma/cdev_veth_drv/Kconfig"
\ No newline at end of file
diff --git a/drivers/net/ethernet/huawei/bma/Makefile b/drivers/net/ethernet/huawei/bma/Makefile
index c626618f47fb..5caa8290a1f7 100644
--- a/drivers/net/ethernet/huawei/bma/Makefile
+++ b/drivers/net/ethernet/huawei/bma/Makefile
@@ -5,4 +5,5 @@
obj-$(CONFIG_BMA) += edma_drv/
obj-$(CONFIG_BMA) += cdev_drv/
obj-$(CONFIG_BMA) += veth_drv/
+obj-$(CONFIG_BMA) += kbox_drv/
obj-$(CONFIG_BMA) += cdev_veth_drv/
\ No newline at end of file
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/Kconfig b/drivers/net/ethernet/huawei/bma/kbox_drv/Kconfig
new file mode 100644
index 000000000000..97829c5487c2
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/Kconfig
@@ -0,0 +1,11 @@
+#
+# Huawei BMA software driver configuration
+#
+
+config BMA
+ tristate "Huawei BMA Software Communication Driver"
+
+ ---help---
+ This driver supports Huawei BMA Software. It is used
+ to communication between Huawei BMA and BMC software.
+
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/Makefile b/drivers/net/ethernet/huawei/bma/kbox_drv/Makefile
new file mode 100644
index 000000000000..9565a00fee44
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_BMA) += host_kbox_drv.o
+host_kbox_drv-y := kbox_main.o kbox_ram_drive.o kbox_ram_image.o kbox_ram_op.o kbox_printk.o kbox_dump.o kbox_hook.o kbox_panic.o
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.c
new file mode 100644
index 000000000000..3ce6c099277d
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/utsname.h> /* system_utsname */
+#include <linux/rtc.h> /* struct rtc_time */
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_printk.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+#include "kbox_dump.h"
+#include "kbox_panic.h"
+
+#ifdef CONFIG_X86
+#include "kbox_mce.h"
+#endif
+
+#define THREAD_TMP_BUF_SIZE 256
+
+static DEFINE_SPINLOCK(g_dump_lock);
+
+static const char g_day_in_month[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
+#define LEAP_YEAR(year) \
+ ((!((year) % 4) && ((year) % 100)) || !((year) % 400))
+#define MONTH_DAYS(month, year) \
+ (g_day_in_month[(month)] + (int)(LEAP_YEAR(year) && (month == 1)))
+
+static void kbox_show_kernel_version(void)
+{
+ (void)kbox_dump_painc_info
+ ("\nOS : %s,\nRelease : %s,\nVersion : %s,\n",
+ init_uts_ns.name.sysname,
+ init_uts_ns.name.release,
+ init_uts_ns.name.version);
+ (void)kbox_dump_painc_info
+ ("Machine : %s,\nNodename : %s\n",
+ init_uts_ns.name.machine,
+ init_uts_ns.name.nodename);
+}
+
+static void kbox_show_version(void)
+{
+ (void)kbox_dump_painc_info("\nKBOX_VERSION : %s\n",
+ KBOX_VERSION);
+}
+
+static void kbox_show_time_stamps(void)
+{
+ struct rtc_time rtc_time_val = { };
+ struct timeval time_value = { };
+
+ do_gettimeofday(&time_value);
+ time_value.tv_sec = time_value.tv_sec - sys_tz.tz_minuteswest * 60;
+ rtc_time_to_tm(time_value.tv_sec, &rtc_time_val);
+
+ (void)kbox_dump_painc_info
+ ("Current time : %04d-%02d-%02d %02d:%02d:%02d\n",
+ rtc_time_val.tm_year + 1900, rtc_time_val.tm_mon + 1,
+ rtc_time_val.tm_mday, rtc_time_val.tm_hour,
+ rtc_time_val.tm_min, rtc_time_val.tm_sec);
+}
+
+void kbox_dump_event(enum kbox_error_type_e type, unsigned long event,
+ const char *msg)
+{
+ if (!spin_trylock(&g_dump_lock))
+ return;
+
+ (void)kbox_dump_painc_info("\n====kbox begin dumping...====\n");
+
+ switch (type) {
+#ifdef CONFIG_X86
+ case KBOX_MCE_EVENT:
+
+ kbox_handle_mce_dump(msg);
+
+ break;
+#endif
+
+ case KBOX_OPPS_EVENT:
+
+ break;
+ case KBOX_PANIC_EVENT:
+ if (kbox_handle_panic_dump(msg) == KBOX_FALSE)
+ goto end;
+
+ break;
+ default:
+ break;
+ }
+
+ kbox_show_kernel_version();
+
+ kbox_show_version();
+
+ kbox_show_time_stamps();
+
+ (void)kbox_dump_painc_info("\n====kbox end dump====\n");
+
+ kbox_output_syslog_info();
+ kbox_output_printk_info();
+
+end:
+ spin_unlock(&g_dump_lock);
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.h
new file mode 100644
index 000000000000..cba31377fbf3
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_dump.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_DUMP_H_
+#define _KBOX_DUMP_H_
+
+#define DUMPSTATE_MCE_RESET 1
+#define DUMPSTATE_OPPS_RESET 2
+#define DUMPSTATE_PANIC_RESET 3
+
+enum kbox_error_type_e {
+ KBOX_MCE_EVENT = 1,
+ KBOX_OPPS_EVENT,
+ KBOX_PANIC_EVENT
+};
+
+int kbox_dump_thread_info(const char *fmt, ...);
+void kbox_dump_event(enum kbox_error_type_e type, unsigned long event,
+ const char *msg);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.c
new file mode 100644
index 000000000000..b2acdf24188b
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/notifier.h>
+#include "kbox_include.h"
+#include "kbox_dump.h"
+#include "kbox_hook.h"
+
+int panic_notify(struct notifier_block *this,
+ unsigned long event, void *msg);
+
+static int die_notify(struct notifier_block *self,
+ unsigned long val, void *data);
+
+static struct notifier_block g_panic_nb = {
+ .notifier_call = panic_notify,
+ .priority = 100,
+};
+
+static struct notifier_block g_die_nb = {
+ .notifier_call = die_notify,
+};
+
+int panic_notify(struct notifier_block *pthis, unsigned long event, void *msg)
+{
+ UNUSED(pthis);
+ UNUSED(event);
+
+ kbox_dump_event(KBOX_PANIC_EVENT, DUMPSTATE_PANIC_RESET,
+ (const char *)msg);
+
+ return NOTIFY_OK;
+}
+
+int die_notify(struct notifier_block *self, unsigned long val, void *data)
+{
+ struct kbox_die_args *args = (struct kbox_die_args *)data;
+
+ if (!args)
+ return NOTIFY_OK;
+
+ switch (val) {
+ case 1:
+ break;
+ case 5:
+ if (strcmp(args->str, "nmi") == 0)
+ return NOTIFY_OK;
+#ifdef CONFIG_X86
+ kbox_dump_event(KBOX_MCE_EVENT, DUMPSTATE_MCE_RESET, args->str);
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+int kbox_register_hook(void)
+{
+ int ret = 0;
+
+ ret = atomic_notifier_chain_register(&panic_notifier_list, &g_panic_nb);
+ if (ret)
+ KBOX_MSG("atomic_notifier_chain_register g_panic_nb failed!\n");
+
+ ret = register_die_notifier(&g_die_nb);
+ if (ret)
+ KBOX_MSG("register_die_notifier g_die_nb failed!\n");
+
+ return ret;
+}
+
+void kbox_unregister_hook(void)
+{
+ int ret = 0;
+
+ ret =
+ atomic_notifier_chain_unregister(&panic_notifier_list, &g_panic_nb);
+ if (ret < 0) {
+ KBOX_MSG
+ ("atomic_notifier_chain_unregister g_panic_nb failed!\n");
+ }
+
+ ret = unregister_die_notifier(&g_die_nb);
+ if (ret < 0)
+ KBOX_MSG("unregister_die_notifier g_die_nb failed!\n");
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.h
new file mode 100644
index 000000000000..00b3deb510b7
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_hook.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_PANIC_HOOK_H_
+#define _KBOX_PANIC_HOOK_H_
+
+struct kbox_die_args {
+ struct pt_regs *regs;
+ const char *str;
+ long err;
+ int trapnr;
+ int signr;
+};
+
+int register_die_notifier(struct notifier_block *nb);
+int unregister_die_notifier(struct notifier_block *nb);
+
+int kbox_register_hook(void);
+void kbox_unregister_hook(void);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h
new file mode 100644
index 000000000000..d8424ea494b0
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_INCLUDE_H_
+#define _KBOX_INCLUDE_H_
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/netdevice.h>
+
+#ifdef DRV_VERSION
+#define KBOX_VERSION MICRO_TO_STR(DRV_VERSION)
+#else
+#define KBOX_VERSION "0.3.4"
+#endif
+
+#define UNUSED(x) (x = x)
+#define KBOX_FALSE (-1)
+#define KBOX_TRUE 0
+
+#ifdef KBOX_DEBUG
+#define KBOX_MSG(fmt, args...) \
+ netdev_notice(0, "kbox: %s(), %d, " fmt, __func__, __LINE__, ## args)
+#else
+#define KBOX_MSG(fmt, args...)
+#endif
+
+#define BAD_FUNC_ADDR(x) ((0xFFFFFFFF == (x)) || (0 == (x)))
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.c
new file mode 100644
index 000000000000..374ce49d570e
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/processor.h> /* for rdmsr and MSR_IA32_MCG_STATUS */
+#include <linux/fs.h> /* everything... */
+#include <linux/file.h> /* for fput */
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h> /* copy_*_user */
+#include <linux/version.h>
+#include "kbox_include.h"
+#include "kbox_panic.h"
+#include "kbox_main.h"
+#include "kbox_printk.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+#include "kbox_dump.h"
+#include "kbox_hook.h"
+#include "kbox_ram_drive.h"
+
+#ifdef CONFIG_X86
+#include <asm/msr.h>
+#include "kbox_mce.h"
+#endif
+
+#define KBOX_LOADED_FILE ("/proc/kbox")
+
+#define KBOX_ROOT_ENTRY_NAME ("kbox")
+
+static int kbox_is_loaded(void)
+{
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+
+ old_fs = get_fs(); /* save old flag */
+ set_fs(KERNEL_DS); /* mark data from kernel space */
+
+ fp = filp_open(KBOX_LOADED_FILE, O_RDONLY, 0);
+
+ if (IS_ERR(fp)) {
+ set_fs(old_fs);
+ return KBOX_FALSE;
+ }
+
+ (void)filp_close(fp, NULL);
+
+ set_fs(old_fs); /* restore old flag */
+
+ return KBOX_TRUE;
+}
+
+static int kbox_printk_proc_init(void)
+{
+ struct proc_dir_entry *kbox_entry = NULL;
+
+ if (kbox_is_loaded() != KBOX_TRUE) {
+ kbox_entry = proc_mkdir(KBOX_ROOT_ENTRY_NAME, NULL);
+ if (!kbox_entry) {
+ KBOX_MSG("can not create %s entry\n",
+ KBOX_ROOT_ENTRY_NAME);
+ return -ENOMEM;
+ }
+ }
+
+ return KBOX_TRUE;
+}
+
+int __init kbox_init(void)
+{
+ int ret = KBOX_TRUE;
+ int kbox_proc_exist = 0;
+
+ if (!kbox_get_base_phy_addr())
+ return -ENXIO;
+
+ ret = kbox_super_block_init();
+ if (ret) {
+ KBOX_MSG("kbox_super_block_init failed!\n");
+ return ret;
+ }
+
+ if (kbox_is_loaded() == KBOX_TRUE)
+ kbox_proc_exist = 1;
+
+ ret = kbox_printk_init(kbox_proc_exist);
+ if (ret)
+ KBOX_MSG("kbox_printk_init failed!\n");
+
+ ret = kbox_panic_init();
+ if (ret) {
+ KBOX_MSG("kbox_panic_init failed!\n");
+ goto fail1;
+ }
+
+ ret = kbox_register_hook();
+ if (ret) {
+ KBOX_MSG("kbox_register_hook failed!\n");
+ goto fail2;
+ }
+
+#ifdef CONFIG_X86
+ (void)kbox_mce_init();
+#endif
+ ret = kbox_read_super_block();
+ if (ret) {
+ KBOX_MSG("update super block failed!\n");
+ goto fail3;
+ }
+
+ if (kbox_printk_proc_init() != 0) {
+ KBOX_MSG("kbox_printk_proc_init failed!\n");
+ goto fail4;
+ }
+
+ ret = kbox_drive_init();
+ if (ret) {
+ KBOX_MSG("kbox_drive_init failed!\n");
+ goto fail5;
+ }
+
+ return KBOX_TRUE;
+
+fail5:
+fail4:
+fail3:
+#ifdef CONFIG_X86
+ kbox_mce_exit();
+#endif
+ kbox_unregister_hook();
+fail2:
+ kbox_panic_exit();
+fail1:
+ kbox_printk_exit();
+
+ return ret;
+}
+
+void __exit kbox_cleanup(void)
+{
+ kbox_drive_cleanup();
+#ifdef CONFIG_X86
+ kbox_mce_exit();
+#endif
+ kbox_unregister_hook();
+ kbox_panic_exit();
+ kbox_printk_exit();
+}
+
+MODULE_AUTHOR("HUAWEI TECHNOLOGIES CO., LTD.");
+MODULE_DESCRIPTION("HUAWEI KBOX DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(KBOX_VERSION);
+#ifndef _lint
+module_init(kbox_init);
+module_exit(kbox_cleanup);
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.h
new file mode 100644
index 000000000000..2ae02b736529
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_main.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_MAIN_H_
+#define _KBOX_MAIN_H_
+
+#include "../edma_drv/bma_include.h"
+int kbox_init(void);
+void kbox_cleanup(void);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.c
new file mode 100644
index 000000000000..e9bd931b826e
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/smp.h>
+#include <linux/notifier.h>
+#include <asm/mce.h>
+#include <asm/msr.h>
+
+#include "kbox_include.h"
+#include "kbox_mce.h"
+#include "kbox_dump.h"
+#include "kbox_printk.h"
+#include "kbox_panic.h"
+
+enum context {
+ KBOX_IN_KERNEL = 1, KBOX_IN_USER = 2
+};
+
+enum ser {
+ KBOX_SER_REQUIRED = 1, KBOX_NO_SER = 2
+};
+
+enum severity_level {
+ KBOX_MCE_NO_SEVERITY,
+ KBOX_MCE_KEEP_SEVERITY,
+ KBOX_MCE_SOME_SEVERITY,
+ KBOX_MCE_AO_SEVERITY,
+ KBOX_MCE_UC_SEVERITY,
+ KBOX_MCE_AR_SEVERITY,
+ KBOX_MCE_PANIC_SEVERITY,
+};
+
+static struct severity {
+ u64 kbox_mask;
+ u64 kbox_result;
+ unsigned char kbox_sev;
+ unsigned char kbox_mcgmask;
+ unsigned char kbox_mcgres;
+ unsigned char kbox_ser;
+ unsigned char kbox_context;
+ unsigned char kbox_covered;
+ char *kbox_msg;
+} kbox_severities[] = {
+#define KBOX_KERNEL .kbox_context = KBOX_IN_KERNEL
+#define KBOX_USER .kbox_context = KBOX_IN_USER
+#define KBOX_SER .kbox_ser = KBOX_SER_REQUIRED
+#define KBOX_NOSER .kbox_ser = KBOX_NO_SER
+#define KBOX_SEV(s) .kbox_sev = KBOX_MCE_ ## s ## _SEVERITY
+#define KBOX_BITCLR(x, s, m, r...) \
+ { .kbox_mask = x, .kbox_result = 0, KBOX_SEV(s), .kbox_msg = m, ## r }
+#define KBOX_BITSET(x, s, m, r...) \
+ { .kbox_mask = x, .kbox_result = x, KBOX_SEV(s), .kbox_msg = m, ## r }
+#define KBOX_MCGMASK(x, res, s, m, r...) \
+ { .kbox_mcgmask = x, .kbox_mcgres = res, KBOX_SEV(s), \
+ .kbox_msg = m, ## r }
+#define KBOX_MASK(x, y, s, m, r...) \
+ { .kbox_mask = x, .kbox_result = y, KBOX_SEV(s), .kbox_msg = m, ## r }
+#define KBOX_MCI_UC_S (MCI_STATUS_UC | MCI_STATUS_S)
+#define KBOX_MCI_UC_SAR (MCI_STATUS_UC | MCI_STATUS_S | MCI_STATUS_AR)
+#define KBOX_MCACOD 0xffff
+
+KBOX_BITCLR(MCI_STATUS_VAL, NO, "Invalid"),
+KBOX_BITCLR(MCI_STATUS_EN, NO, "Not enabled"),
+KBOX_BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"),
+
+KBOX_MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"),
+
+KBOX_MCGMASK(MCG_STATUS_RIPV | MCG_STATUS_EIPV, 0, PANIC,
+ "Neither restart nor error IP"),
+KBOX_MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP",
+ KBOX_KERNEL),
+KBOX_BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", KBOX_NOSER),
+KBOX_MASK(MCI_STATUS_OVER | MCI_STATUS_UC | MCI_STATUS_EN, MCI_STATUS_UC, SOME,
+ "Spurious not enabled", KBOX_SER),
+
+KBOX_MASK(KBOX_MCI_UC_SAR, MCI_STATUS_UC, KEEP,
+ "Uncorrected no action required", KBOX_SER),
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, MCI_STATUS_UC | MCI_STATUS_AR,
+ PANIC, "Illegal combination (UCNA with AR=1)", KBOX_SER),
+KBOX_MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", KBOX_SER),
+
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, MCI_STATUS_OVER | KBOX_MCI_UC_SAR,
+ PANIC, "Action required with lost events", KBOX_SER),
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR | KBOX_MCACOD, KBOX_MCI_UC_SAR,
+ PANIC, "Action required; unknown MCACOD", KBOX_SER),
+
+KBOX_MASK(KBOX_MCI_UC_SAR | MCI_STATUS_OVER | 0xfff0, KBOX_MCI_UC_S | 0xc0,
+ AO, "Action optional: memory scrubbing error", KBOX_SER),
+KBOX_MASK(KBOX_MCI_UC_SAR | MCI_STATUS_OVER | KBOX_MCACOD,
+ KBOX_MCI_UC_S | 0x17a, AO,
+ "Action optional: last level cache writeback error", KBOX_SER),
+
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, KBOX_MCI_UC_S, SOME,
+ "Action optional unknown MCACOD", KBOX_SER),
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, KBOX_MCI_UC_S | MCI_STATUS_OVER,
+ SOME, "Action optional with lost events", KBOX_SER),
+KBOX_BITSET(MCI_STATUS_UC | MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"),
+KBOX_BITSET(MCI_STATUS_UC, UC, "Uncorrected"),
+KBOX_BITSET(0, SOME, "No match")
+};
+
+static unsigned int g_kbox_nr_mce_banks;
+static unsigned int g_kbox_mce_ser;
+static atomic_t g_mce_dump_state = ATOMIC_INIT(0);
+
+static int kbox_mce_severity(u64 mcgstatus, u64 status)
+{
+ struct severity *s;
+
+ for (s = kbox_severities;; s++) {
+ if ((status & s->kbox_mask) != s->kbox_result)
+ continue;
+
+ if ((mcgstatus & s->kbox_mcgmask) != s->kbox_mcgres)
+ continue;
+
+ if (s->kbox_ser == KBOX_SER_REQUIRED && !g_kbox_mce_ser)
+ continue;
+
+ if (s->kbox_ser == KBOX_NO_SER && g_kbox_mce_ser)
+ continue;
+
+ break;
+ }
+
+ return s->kbox_sev;
+}
+
+static u64 kbox_mce_rdmsrl(u32 ulmsr)
+{
+ u64 ullv = 0;
+
+ if (rdmsrl_safe(ulmsr, &ullv)) {
+ (void)kbox_dump_painc_info("mce: Unable to read msr %d!\n",
+ ulmsr);
+ ullv = 0;
+ }
+
+ return ullv;
+}
+
+static int kbox_intel_machine_check(void)
+{
+ unsigned int idx = 0;
+ u64 mcgstatus = 0;
+ int worst = 0;
+
+ mcgstatus = kbox_mce_rdmsrl(MSR_IA32_MCG_STATUS);
+
+ (void)
+ kbox_dump_painc_info
+ ("CPU %d: Machine Check Exception MCG STATUS: 0x%016llx\n",
+ smp_processor_id(), mcgstatus);
+
+ if (!(mcgstatus & MCG_STATUS_RIPV))
+ (void)kbox_dump_painc_info("Unable to continue\n");
+
+ for (idx = 0; idx < g_kbox_nr_mce_banks; idx++) {
+ u64 status = 0;
+ u64 misc = 0;
+ u64 addr = 0;
+ int lseverity = 0;
+
+ status = kbox_mce_rdmsrl(MSR_IA32_MCx_STATUS(idx));
+
+ (void)kbox_dump_painc_info("Bank %d STATUS: 0x%016llx\n", idx,
+ status);
+
+ if (0 == (status & MCI_STATUS_VAL))
+ continue;
+
+ lseverity = kbox_mce_severity(mcgstatus, status);
+ if (lseverity == KBOX_MCE_KEEP_SEVERITY ||
+ lseverity == KBOX_MCE_NO_SEVERITY)
+ continue;
+
+ (void)kbox_dump_painc_info("severity = %d\n", lseverity);
+
+ if (status & MCI_STATUS_MISCV) {
+ misc = kbox_mce_rdmsrl(MSR_IA32_MCx_MISC(idx));
+ (void)kbox_dump_painc_info("misc = 0x%016llx\n", misc);
+ }
+
+ if (status & MCI_STATUS_ADDRV) {
+ addr = kbox_mce_rdmsrl(MSR_IA32_MCx_ADDR(idx));
+ (void)kbox_dump_painc_info("addr = 0x%016llx\n", addr);
+ }
+
+ (void)kbox_dump_painc_info("\n");
+
+ if (lseverity > worst)
+ worst = lseverity;
+ }
+
+ if (worst >= KBOX_MCE_UC_SEVERITY)
+ return KBOX_FALSE;
+
+ (void)kbox_dump_painc_info("Attempting to continue.\n");
+
+ return KBOX_TRUE;
+}
+
+int kbox_handle_mce_dump(const char *msg)
+{
+ int mce_recoverable = KBOX_FALSE;
+
+ atomic_read(&g_mce_dump_state);
+
+ mce_recoverable = kbox_intel_machine_check();
+ if (mce_recoverable != KBOX_TRUE) {
+ static atomic_t mce_entry_tmp;
+ int flag = atomic_add_return(1, &mce_entry_tmp);
+
+ if (flag != 1)
+ return KBOX_FALSE;
+ }
+
+ atomic_set(&g_mce_dump_state, DUMPSTATE_MCE_RESET);
+
+ if (msg) {
+ (void)
+ kbox_dump_painc_info
+ ("-------[ System may reset by %s! ]-------\n\n", msg);
+ }
+
+ return KBOX_TRUE;
+}
+
+int kbox_mce_init(void)
+{
+ u64 cap = 0;
+
+ cap = kbox_mce_rdmsrl(MSR_IA32_MCG_CAP);
+ g_kbox_nr_mce_banks = cap & MCG_BANKCNT_MASK;
+
+ if (cap & MCG_SER_P)
+ g_kbox_mce_ser = 1;
+
+ KBOX_MSG("get nr_mce_banks:%d, g_kbox_mce_ser = %d, cap = 0x%016llx\n",
+ g_kbox_nr_mce_banks, g_kbox_mce_ser, cap);
+
+ return KBOX_TRUE;
+}
+
+void kbox_mce_exit(void)
+{
+ g_kbox_nr_mce_banks = 0;
+ g_kbox_mce_ser = 0;
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.h
new file mode 100644
index 000000000000..00d3b787c140
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_mce.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_MCE_H_
+#define _KBOX_MCE_H_
+
+int kbox_handle_mce_dump(const char *msg);
+int kbox_mce_init(void);
+void kbox_mce_exit(void);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c
new file mode 100644
index 000000000000..0c17cd2bae49
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/types.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "kbox_include.h"
+#include "kbox_panic.h"
+#include "kbox_ram_op.h"
+
+#ifdef CONFIG_X86
+#include <asm/msr.h>
+#endif
+
+#define PANIC_TMP_BUF_SIZE 256
+
+static int g_panic_init_ok = KBOX_FALSE;
+
+static char *g_panic_info_buf_tmp;
+static char *g_panic_info_buf;
+
+static unsigned int g_panic_info_start;
+
+static unsigned int g_panic_info_end;
+
+static unsigned int g_panic_info_len;
+
+static DEFINE_SPINLOCK(g_panic_buf_lock);
+
+static void kbox_emit_syslog_char(const char c)
+{
+ if (unlikely(!g_panic_info_buf))
+ return;
+
+ *(g_panic_info_buf + (g_panic_info_end % SLOT_LENGTH)) = c;
+ g_panic_info_end++;
+
+ if (g_panic_info_end > SLOT_LENGTH)
+ g_panic_info_start++;
+
+ if (g_panic_info_len < SLOT_LENGTH)
+ g_panic_info_len++;
+}
+
+static int kbox_duplicate_syslog_info(const char *syslog_buf,
+ unsigned int buf_len)
+{
+ unsigned int idx = 0;
+ unsigned long flags = 0;
+
+ if (!syslog_buf)
+ return 0;
+
+ spin_lock_irqsave(&g_panic_buf_lock, flags);
+
+ for (idx = 0; idx < buf_len; idx++)
+ kbox_emit_syslog_char(*syslog_buf++);
+
+ spin_unlock_irqrestore(&g_panic_buf_lock, flags);
+
+ return buf_len;
+}
+
+int kbox_dump_painc_info(const char *fmt, ...)
+{
+ va_list args;
+ int num = 0;
+ char tmp_buf[PANIC_TMP_BUF_SIZE] = { };
+
+ va_start(args, fmt);
+
+ num = vsnprintf(tmp_buf, sizeof(tmp_buf) - 1, fmt, args);
+ if (num >= 0)
+ (void)kbox_duplicate_syslog_info(tmp_buf, num);
+
+ va_end(args);
+
+ return num;
+}
+
+void kbox_output_syslog_info(void)
+{
+ unsigned int start_tmp = 0;
+ unsigned int end_tmp = 0;
+ unsigned int len_tmp = 0;
+ unsigned long flags = 0;
+
+ if (unlikely
+ (!g_panic_info_buf || !g_panic_info_buf_tmp))
+ return;
+
+ spin_lock_irqsave(&g_panic_buf_lock, flags);
+ if (g_panic_info_len == 0) {
+ spin_unlock_irqrestore(&g_panic_buf_lock, flags);
+ return;
+ }
+
+ start_tmp = (g_panic_info_start % SLOT_LENGTH);
+ end_tmp = ((g_panic_info_end - 1) % SLOT_LENGTH);
+ len_tmp = g_panic_info_len;
+
+ if (start_tmp > end_tmp) {
+ memcpy(g_panic_info_buf_tmp,
+ (g_panic_info_buf + start_tmp),
+ len_tmp - start_tmp);
+ memcpy((g_panic_info_buf_tmp + len_tmp - start_tmp),
+ g_panic_info_buf,
+ end_tmp + 1);
+ } else {
+ memcpy(g_panic_info_buf_tmp,
+ (char *)(g_panic_info_buf + start_tmp),
+ len_tmp);
+ }
+
+ spin_unlock_irqrestore(&g_panic_buf_lock, flags);
+
+ (void)kbox_write_panic_info(g_panic_info_buf_tmp, len_tmp);
+}
+
+int kbox_panic_init(void)
+{
+ int ret = KBOX_TRUE;
+
+ g_panic_info_buf = kmalloc(SLOT_LENGTH, GFP_KERNEL);
+ if (IS_ERR(g_panic_info_buf) || !g_panic_info_buf) {
+ KBOX_MSG("kmalloc g_panic_info_buf fail!\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ memset(g_panic_info_buf, 0, SLOT_LENGTH);
+
+ g_panic_info_buf_tmp = kmalloc(SLOT_LENGTH, GFP_KERNEL);
+ if (IS_ERR(g_panic_info_buf_tmp) || !g_panic_info_buf_tmp) {
+ KBOX_MSG("kmalloc g_panic_info_buf_tmp fail!\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ memset(g_panic_info_buf_tmp, 0, SLOT_LENGTH);
+
+ g_panic_init_ok = KBOX_TRUE;
+
+ return ret;
+fail:
+
+ kfree(g_panic_info_buf);
+ g_panic_info_buf = NULL;
+
+ kfree(g_panic_info_buf_tmp);
+ g_panic_info_buf_tmp = NULL;
+
+ return ret;
+}
+
+void kbox_panic_exit(void)
+{
+ if (g_panic_init_ok != KBOX_TRUE)
+ return;
+
+ kfree(g_panic_info_buf);
+ g_panic_info_buf = NULL;
+
+ kfree(g_panic_info_buf_tmp);
+ g_panic_info_buf_tmp = NULL;
+}
+
+int kbox_handle_panic_dump(const char *msg)
+{
+ if (msg)
+ (void)kbox_dump_painc_info("panic string: %s\n", msg);
+
+ return KBOX_TRUE;
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.h
new file mode 100644
index 000000000000..5715b66c0659
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_PANIC_H_
+#define _KBOX_PANIC_H_
+
+int kbox_handle_panic_dump(const char *msg);
+void kbox_output_syslog_info(void);
+int kbox_dump_painc_info(const char *fmt, ...);
+int kbox_panic_init(void);
+void kbox_panic_exit(void);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c
new file mode 100644
index 000000000000..969c0c0cc630
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/console.h> /* struct console */
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_printk.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+
+#define TMP_BUF_SIZE 256
+
+static int g_printk_init_ok = KBOX_FALSE;
+static char *g_printk_info_buf;
+static char *g_printk_info_buf_tmp;
+static struct printk_ctrl_block_tmp_s g_printk_ctrl_block_tmp = { };
+
+static DEFINE_SPINLOCK(g_printk_buf_lock);
+
+static void kbox_printk_info_write(struct console *console,
+ const char *printk_buf,
+ unsigned int buf_len);
+
+static struct console g_printk_console = {
+ .name = "k_prtk",
+ .flags = CON_ENABLED | CON_PRINTBUFFER,
+ .write = kbox_printk_info_write,
+};
+
+static int kbox_printk_format_is_order(struct printk_info_ctrl_block_s *
+ printk_ctrl_blk_first,
+ struct printk_info_ctrl_block_s *
+ printk_ctrl_blk_second)
+{
+ if (!printk_ctrl_blk_first || !printk_ctrl_blk_second)
+ return KBOX_FALSE;
+
+ if (!memcmp(printk_ctrl_blk_first->flag, PRINTK_CURR_FLAG,
+ PRINTK_FLAG_LEN) &&
+ !memcmp(printk_ctrl_blk_second->flag, PRINTK_LAST_FLAG,
+ PRINTK_FLAG_LEN)) {
+ return KBOX_TRUE;
+ }
+
+ return KBOX_FALSE;
+}
+
+static void kbox_printk_format(struct printk_info_ctrl_block_s *printk_ctrl_blk,
+ const unsigned int len, const char *flag)
+{
+ if (!printk_ctrl_blk || !flag)
+ return;
+
+ memset(printk_ctrl_blk, 0, len);
+ memcpy(printk_ctrl_blk->flag, flag, PRINTK_FLAG_LEN);
+}
+
+static void kbox_printk_init_info_first
+ (struct image_super_block_s *kbox_super_block)
+{
+ KBOX_MSG("\n");
+ if (kbox_printk_format_is_order(kbox_super_block->printk_ctrl_blk,
+ kbox_super_block->printk_ctrl_blk +
+ 1) == KBOX_TRUE) {
+ memcpy(kbox_super_block->printk_ctrl_blk[0].flag,
+ PRINTK_LAST_FLAG, PRINTK_FLAG_LEN);
+ memcpy(kbox_super_block->printk_ctrl_blk[1].flag,
+ PRINTK_CURR_FLAG, PRINTK_FLAG_LEN);
+ kbox_super_block->printk_ctrl_blk[1].len = 0;
+ g_printk_ctrl_block_tmp.printk_region = 1;
+ g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK2;
+ (void)kbox_clear_region(KBOX_SECTION_PRINTK2);
+ } else if (kbox_printk_format_is_order
+ (kbox_super_block->printk_ctrl_blk + 1,
+ kbox_super_block->printk_ctrl_blk) == KBOX_TRUE) {
+ memcpy(kbox_super_block->printk_ctrl_blk[1].flag,
+ PRINTK_LAST_FLAG,
+ PRINTK_FLAG_LEN);
+ memcpy(kbox_super_block->printk_ctrl_blk[0].flag,
+ PRINTK_CURR_FLAG,
+ PRINTK_FLAG_LEN);
+
+ kbox_super_block->printk_ctrl_blk[0].len = 0;
+ g_printk_ctrl_block_tmp.printk_region = 0;
+ g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+ (void)kbox_clear_region(KBOX_SECTION_PRINTK1);
+ } else {
+ kbox_printk_format(kbox_super_block->printk_ctrl_blk,
+ sizeof(struct printk_info_ctrl_block_s),
+ PRINTK_CURR_FLAG);
+ kbox_printk_format(kbox_super_block->printk_ctrl_blk + 1,
+ sizeof(struct printk_info_ctrl_block_s),
+ PRINTK_LAST_FLAG);
+ g_printk_ctrl_block_tmp.printk_region = 0;
+ g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+ (void)kbox_clear_region(KBOX_SECTION_PRINTK1);
+ (void)kbox_clear_region(KBOX_SECTION_PRINTK2);
+ }
+
+ g_printk_ctrl_block_tmp.start = 0;
+ g_printk_ctrl_block_tmp.end = 0;
+ g_printk_ctrl_block_tmp.valid_len = 0;
+}
+
+static void kbox_printk_init_info_not_first
+ (struct image_super_block_s *kbox_super_block)
+{
+ KBOX_MSG("\n");
+ if (KBOX_TRUE ==
+ kbox_printk_format_is_order(kbox_super_block->printk_ctrl_blk,
+ kbox_super_block->printk_ctrl_blk +
+ 1)) {
+ g_printk_ctrl_block_tmp.printk_region = 0;
+ g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+
+ } else if (KBOX_TRUE ==
+ kbox_printk_format_is_order
+ (kbox_super_block->printk_ctrl_blk + 1,
+ kbox_super_block->printk_ctrl_blk)) {
+ g_printk_ctrl_block_tmp.printk_region = 1;
+ g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK2;
+
+ } else {
+ kbox_printk_format(kbox_super_block->printk_ctrl_blk,
+ sizeof(struct printk_info_ctrl_block_s),
+ PRINTK_CURR_FLAG);
+ kbox_printk_format(kbox_super_block->printk_ctrl_blk + 1,
+ sizeof(struct printk_info_ctrl_block_s),
+ PRINTK_LAST_FLAG);
+ g_printk_ctrl_block_tmp.printk_region = 0;
+ g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+ (void)kbox_clear_region(KBOX_SECTION_PRINTK1);
+ (void)kbox_clear_region(KBOX_SECTION_PRINTK2);
+ }
+
+ g_printk_ctrl_block_tmp.start = 0;
+}
+
+static int kbox_printk_init_info(int kbox_proc_exist)
+{
+ struct image_super_block_s kbox_super_block = { };
+ unsigned int read_len = 0;
+ unsigned int write_len = 0;
+
+ read_len =
+ kbox_read_from_ram(SECTION_KERNEL_OFFSET,
+ (unsigned int)sizeof(struct image_super_block_s),
+ (char *)&kbox_super_block, KBOX_SECTION_KERNEL);
+ if (read_len != sizeof(struct image_super_block_s)) {
+ KBOX_MSG("fail to get superblock data!\n");
+ return KBOX_FALSE;
+ }
+
+ if (kbox_proc_exist) {
+ kbox_printk_init_info_not_first(&kbox_super_block);
+ if (KBOX_TRUE !=
+ kbox_read_printk_info(g_printk_info_buf,
+ &g_printk_ctrl_block_tmp)) {
+ g_printk_ctrl_block_tmp.end = 0;
+ g_printk_ctrl_block_tmp.valid_len = 0;
+ }
+ } else {
+ kbox_printk_init_info_first(&kbox_super_block);
+ }
+
+ kbox_super_block.checksum = 0;
+ kbox_super_block.checksum =
+ ~((unsigned char)
+ kbox_checksum((char *)&kbox_super_block,
+ (unsigned int)sizeof(kbox_super_block))) + 1;
+ write_len =
+ kbox_write_to_ram(SECTION_KERNEL_OFFSET,
+ (unsigned int)sizeof(struct image_super_block_s),
+ (char *)&kbox_super_block, KBOX_SECTION_KERNEL);
+ if (write_len <= 0) {
+ KBOX_MSG("fail to write superblock data!\n");
+ return KBOX_FALSE;
+ }
+
+ return KBOX_TRUE;
+}
+
+void kbox_output_printk_info(void)
+{
+ unsigned int start_tmp = 0;
+ unsigned int end_tmp = 0;
+ unsigned int len_tmp = 0;
+ unsigned long flags = 0;
+
+ if (unlikely(!g_printk_info_buf || !g_printk_info_buf_tmp))
+ return;
+
+ if (g_printk_init_ok != KBOX_TRUE)
+ return;
+
+ spin_lock_irqsave(&g_printk_buf_lock, flags);
+ if (g_printk_ctrl_block_tmp.valid_len == 0) {
+ spin_unlock_irqrestore(&g_printk_buf_lock, flags);
+ return;
+ }
+
+ start_tmp = (g_printk_ctrl_block_tmp.start % SECTION_PRINTK_LEN);
+ end_tmp = ((g_printk_ctrl_block_tmp.end - 1) % SECTION_PRINTK_LEN);
+ len_tmp = g_printk_ctrl_block_tmp.valid_len;
+
+ if (start_tmp > end_tmp) {
+ memcpy(g_printk_info_buf_tmp,
+ g_printk_info_buf + start_tmp,
+ len_tmp - start_tmp);
+ memcpy(g_printk_info_buf_tmp + len_tmp - start_tmp,
+ g_printk_info_buf,
+ end_tmp + 1);
+ memcpy(g_printk_info_buf_tmp,
+ g_printk_info_buf + start_tmp,
+ len_tmp);
+ }
+
+ spin_unlock_irqrestore(&g_printk_buf_lock, flags);
+
+ (void)kbox_write_printk_info(g_printk_info_buf_tmp,
+ &g_printk_ctrl_block_tmp);
+}
+
+static void kbox_emit_printk_char(const char c)
+{
+ if (unlikely(!g_printk_info_buf))
+ return;
+
+ *(g_printk_info_buf +
+ (g_printk_ctrl_block_tmp.end % SECTION_PRINTK_LEN)) = c;
+ g_printk_ctrl_block_tmp.end++;
+
+ if (g_printk_ctrl_block_tmp.end > SECTION_PRINTK_LEN)
+ g_printk_ctrl_block_tmp.start++;
+
+ if (g_printk_ctrl_block_tmp.end < SECTION_PRINTK_LEN)
+ g_printk_ctrl_block_tmp.valid_len++;
+}
+
+static int kbox_duplicate_printk_info(const char *printk_buf,
+ unsigned int buf_len)
+{
+ unsigned int idx = 0;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&g_printk_buf_lock, flags);
+ for (idx = 0; idx < buf_len; idx++)
+ kbox_emit_printk_char(*printk_buf++);
+
+ spin_unlock_irqrestore(&g_printk_buf_lock, flags);
+
+ return buf_len;
+}
+
+int kbox_dump_printk_info(const char *fmt, ...)
+{
+ va_list args;
+ int num = 0;
+ char tmp_buf[TMP_BUF_SIZE] = { };
+
+ if (g_printk_init_ok != KBOX_TRUE)
+ return 0;
+
+ va_start(args, fmt);
+ num = vsnprintf(tmp_buf, sizeof(tmp_buf) - 1, fmt, args);
+ if (num >= 0)
+ (void)kbox_duplicate_printk_info(tmp_buf, num);
+
+ va_end(args);
+
+ return num;
+}
+
+static void kbox_printk_info_write(struct console *pconsole,
+ const char *printk_buf, unsigned int buf_len)
+{
+ UNUSED(pconsole);
+
+ if (unlikely(!printk_buf))
+ return;
+
+ (void)kbox_duplicate_printk_info(printk_buf, buf_len);
+}
+
+int kbox_printk_init(int kbox_proc_exist)
+{
+ int ret = KBOX_TRUE;
+
+ g_printk_info_buf = kmalloc(SECTION_PRINTK_LEN,
+ GFP_KERNEL);
+ if (IS_ERR(g_printk_info_buf) || !g_printk_info_buf) {
+ KBOX_MSG("kmalloc g_printk_info_buf fail!\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ memset(g_printk_info_buf, 0, SECTION_PRINTK_LEN);
+
+ g_printk_info_buf_tmp = kmalloc(SECTION_PRINTK_LEN,
+ GFP_KERNEL);
+ if (IS_ERR(g_printk_info_buf_tmp) || !g_printk_info_buf_tmp) {
+ KBOX_MSG("kmalloc g_printk_info_buf_tmp fail!\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ memset(g_printk_info_buf_tmp, 0, SECTION_PRINTK_LEN);
+
+ ret = kbox_printk_init_info(kbox_proc_exist);
+ if (ret != KBOX_TRUE) {
+ KBOX_MSG("kbox_printk_init_info failed!\n");
+ goto fail;
+ }
+
+ register_console(&g_printk_console);
+
+ g_printk_init_ok = KBOX_TRUE;
+
+ return ret;
+fail:
+
+ kfree(g_printk_info_buf);
+ g_printk_info_buf = NULL;
+
+ kfree(g_printk_info_buf_tmp);
+ g_printk_info_buf_tmp = NULL;
+
+ return ret;
+}
+
+void kbox_printk_exit(void)
+{
+ int ret = 0;
+
+ if (g_printk_init_ok != KBOX_TRUE)
+ return;
+
+ kfree(g_printk_info_buf);
+ g_printk_info_buf = NULL;
+
+ kfree(g_printk_info_buf_tmp);
+ g_printk_info_buf_tmp = NULL;
+
+ ret = unregister_console(&g_printk_console);
+ if (ret)
+ KBOX_MSG("unregister_console failed!\n");
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.h
new file mode 100644
index 000000000000..cece825626a8
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_PRINTK_H_
+#define _KBOX_PRINTK_H_
+#include "kbox_ram_image.h"
+
+struct printk_ctrl_block_tmp_s {
+ int printk_region;
+ enum kbox_section_e section;
+ unsigned int start;
+ unsigned int end;
+ unsigned int valid_len;/* valid length of printk section */
+};
+
+int kbox_printk_init(int kbox_proc_exist);
+void kbox_output_printk_info(void);
+int kbox_dump_printk_info(const char *fmt, ...);
+void kbox_printk_exit(void);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.c
new file mode 100644
index 000000000000..829e2a498843
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/fs.h> /* everything... */
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <asm/ioctls.h>
+#include <linux/slab.h>
+#include "kbox_include.h"
+#include "kbox_ram_drive.h"
+#include "kbox_main.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+
+#define KBOX_DEVICE_NAME "kbox"
+#define KBOX_DEVICE_MINOR 255
+
+static struct kbox_dev_s *g_kbox_dev;
+static ssize_t kbox_read(struct file *filp, char __user *data, size_t count,
+ loff_t *ppos);
+static ssize_t kbox_write(struct file *filp, const char __user *data,
+ size_t count, loff_t *ppos);
+
+static long kbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+static int kbox_mmap(struct file *filp, struct vm_area_struct *vma);
+static int kbox_open(struct inode *inode, struct file *filp);
+static int kbox_release(struct inode *inode, struct file *filp);
+
+const struct file_operations kbox_fops = {
+ .owner = THIS_MODULE,
+ .read = kbox_read,
+ .write = kbox_write,
+ .unlocked_ioctl = kbox_ioctl,
+ .mmap = kbox_mmap,
+ .open = kbox_open,
+ .release = kbox_release,
+};
+
+static struct miscdevice kbox_device = {
+ KBOX_DEVICE_MINOR,
+ KBOX_DEVICE_NAME,
+ &kbox_fops,
+};
+
+static ssize_t kbox_read(struct file *filp, char __user *data, size_t count,
+ loff_t *ppos)
+{
+ int read_len = 0;
+
+ if (!filp || !data || !ppos) {
+ KBOX_MSG("input NULL point!\n");
+ return -EFAULT;
+ }
+
+ read_len = kbox_read_op((long long)(*ppos),
+ count,
+ data,
+ KBOX_SECTION_USER);
+ if (read_len < 0)
+ return -EFAULT;
+
+ *ppos += read_len;
+
+ return read_len;
+}
+
+static ssize_t kbox_write(struct file *filp, const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ int write_len = 0;
+
+ if (!filp || !data || !ppos) {
+ KBOX_MSG("input NULL point!\n");
+ return -EFAULT;
+ }
+
+ write_len = kbox_write_op((long long)(*ppos),
+ count, data, KBOX_SECTION_USER);
+ if (write_len < 0)
+ return -EFAULT;
+
+ *ppos += write_len;
+
+ return write_len;
+}
+
+static long kbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ UNUSED(filp);
+
+ if (kbox_ioctl_detail(cmd, arg) < 0)
+ return -ENOTTY;
+
+ return 0;
+}
+
+static int kbox_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ if (!filp || !vma) {
+ KBOX_MSG("input NULL point!\n");
+ return -EFAULT;
+ }
+
+ if (kbox_mmap_ram(filp, vma, KBOX_SECTION_USER) < 0)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int kbox_open(struct inode *pinode, struct file *filp)
+{
+ UNUSED(pinode);
+
+ if ((g_kbox_dev) && (!atomic_dec_and_test(&g_kbox_dev->au_count))) {
+ atomic_inc(&g_kbox_dev->au_count);
+ KBOX_MSG("EBUSY\n");
+ return -EBUSY;
+ }
+
+ filp->private_data = (void *)g_kbox_dev;
+
+ return 0;
+}
+
+int kbox_release(struct inode *pinode, struct file *filp)
+{
+ struct kbox_dev_s *kbox_dev = (struct kbox_dev_s *)filp->private_data;
+
+ UNUSED(pinode);
+
+ KBOX_MSG("\n");
+
+ if (kbox_dev)
+ atomic_inc(&kbox_dev->au_count);
+
+ return 0;
+}
+
+int kbox_drive_init(void)
+{
+ int ret = 0;
+
+ KBOX_MSG("\n");
+
+ g_kbox_dev =
+ kmalloc(sizeof(struct kbox_dev_s), GFP_KERNEL);
+ if (!g_kbox_dev)
+ return -ENOMEM;
+
+ ret = misc_register(&kbox_device);
+ if (ret)
+ goto fail;
+
+ atomic_set(&g_kbox_dev->au_count, 1);
+
+ KBOX_MSG("ok!\n");
+
+ return ret;
+
+fail:
+ kfree(g_kbox_dev);
+ g_kbox_dev = NULL;
+
+ return ret;
+}
+
+void kbox_drive_cleanup(void)
+{
+ if (!g_kbox_dev)
+ return;
+
+ misc_deregister(&kbox_device);
+
+ kfree(g_kbox_dev);
+ g_kbox_dev = NULL;
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.h
new file mode 100644
index 000000000000..52707c4b82c5
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_drive.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_RAM_DRIVE_H_
+#define _KBOX_RAM_DRIVE_H_
+
+#include <linux/types.h>
+#include <linux/atomic.h>
+
+struct kbox_dev_s {
+ atomic_t au_count;
+
+ struct kbox_pci_dev_s *kbox_pci_dev;
+};
+
+int kbox_drive_init(void);
+void kbox_drive_cleanup(void);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.c
new file mode 100644
index 000000000000..f57083261983
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_ram_image.h"
+
+void __iomem *kbox_get_section_addr(enum kbox_section_e kbox_section)
+{
+ void __iomem *kbox_addr = kbox_get_base_addr();
+ unsigned long kbox_len = kbox_get_io_len();
+
+ if (!kbox_addr || kbox_len == 0) {
+ KBOX_MSG("get kbox_addr or kbox_len failed!\n");
+ return NULL;
+ }
+
+ switch (kbox_section) {
+ case KBOX_SECTION_KERNEL:
+ return kbox_addr;
+
+ case KBOX_SECTION_PANIC:
+ return kbox_addr + SECTION_KERNEL_LEN;
+
+ case KBOX_SECTION_THREAD:
+ return kbox_addr + SECTION_KERNEL_LEN + SECTION_PANIC_LEN;
+
+ case KBOX_SECTION_PRINTK1:
+ return kbox_addr + (kbox_len - (2 * SECTION_PRINTK_LEN) -
+ SECTION_USER_LEN);
+
+ case KBOX_SECTION_PRINTK2:
+ return kbox_addr + (kbox_len - SECTION_PRINTK_LEN -
+ SECTION_USER_LEN);
+
+ case KBOX_SECTION_USER:
+ return kbox_addr + (kbox_len - SECTION_USER_LEN);
+
+ case KBOX_SECTION_ALL:
+ return kbox_addr;
+
+ default:
+ KBOX_MSG("input kbox_section error!\n");
+ return NULL;
+ }
+}
+
+unsigned long kbox_get_section_len(enum kbox_section_e kbox_section)
+{
+ unsigned long kbox_len = kbox_get_io_len();
+
+ if (kbox_len == 0) {
+ KBOX_MSG("get kbox_len failed!\n");
+ return 0;
+ }
+
+ switch (kbox_section) {
+ case KBOX_SECTION_KERNEL:
+ return SECTION_KERNEL_LEN;
+
+ case KBOX_SECTION_PANIC:
+ return SECTION_PANIC_LEN;
+
+ case KBOX_SECTION_THREAD:
+ return (kbox_len - (2 * SECTION_PRINTK_LEN) -
+ SECTION_USER_LEN - SECTION_KERNEL_LEN -
+ SECTION_PANIC_LEN);
+
+ case KBOX_SECTION_PRINTK1:
+ case KBOX_SECTION_PRINTK2:
+ return SECTION_PRINTK_LEN;
+
+ case KBOX_SECTION_USER:
+ return SECTION_USER_LEN;
+
+ case KBOX_SECTION_ALL:
+ return kbox_len;
+
+ default:
+ KBOX_MSG("input kbox_section error!\n");
+ return 0;
+ }
+}
+
+unsigned long kbox_get_section_phy_addr(enum kbox_section_e kbox_section)
+{
+ unsigned long kbox_phy_addr = kbox_get_base_phy_addr();
+ unsigned long kbox_len = kbox_get_io_len();
+
+ if (kbox_phy_addr == 0 || kbox_len == 0) {
+ KBOX_MSG("get kbox_phy_addr or kbox_len failed!\n");
+ return 0;
+ }
+
+ switch (kbox_section) {
+ case KBOX_SECTION_KERNEL:
+ return kbox_phy_addr;
+
+ case KBOX_SECTION_PANIC:
+ return kbox_phy_addr + SECTION_KERNEL_LEN;
+
+ case KBOX_SECTION_THREAD:
+ return kbox_phy_addr + SECTION_KERNEL_LEN + SECTION_PANIC_LEN;
+
+ case KBOX_SECTION_PRINTK1:
+ return kbox_phy_addr + (kbox_len - (2 * SECTION_PRINTK_LEN) -
+ SECTION_USER_LEN);
+
+ case KBOX_SECTION_PRINTK2:
+ return kbox_phy_addr + (kbox_len - SECTION_PRINTK_LEN -
+ SECTION_USER_LEN);
+
+ case KBOX_SECTION_USER:
+ return kbox_phy_addr + (kbox_len - SECTION_USER_LEN);
+
+ case KBOX_SECTION_ALL:
+ return kbox_phy_addr;
+
+ default:
+ KBOX_MSG("input kbox_section error!\n");
+ return 0;
+ }
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.h
new file mode 100644
index 000000000000..d1b01bd9ea11
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_image.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_RAM_IMAGE_H_
+#define _KBOX_RAM_IMAGE_H_
+
+enum kbox_section_e {
+ KBOX_SECTION_KERNEL = 1,
+ KBOX_SECTION_PANIC = 2,
+ KBOX_SECTION_THREAD = 3,
+ KBOX_SECTION_PRINTK1 = 4,
+ KBOX_SECTION_PRINTK2 = 5,
+ KBOX_SECTION_USER = 6,
+ KBOX_SECTION_ALL = 7
+};
+
+#define KBOX_BIG_ENDIAN (0x2B)
+#define KBOX_LITTLE_ENDIAN (0xB2)
+#define IMAGE_VER (0x0001)
+#define IMAGE_MAGIC (0xB202C086)
+#define VALID_IMAGE(x) (IMAGE_MAGIC == (x)->magic_flag)
+#define SLOT_NUM (8)
+#define SLOT_LENGTH (16 * 1024)
+#define MAX_RECORD_NO (0xFF)
+#define MAX_USE_NUMS (0xFF)
+
+#define PRINTK_NUM (2)
+#define PRINTK_CURR_FLAG ("curr")
+#define PRINTK_LAST_FLAG ("last")
+#define PRINTK_FLAG_LEN (4)
+
+struct panic_ctrl_block_s {
+ unsigned char use_nums;
+ unsigned char number;
+ unsigned short len;
+ unsigned int time;
+};
+
+struct thread_info_ctrl_block_s {
+ unsigned int thread_info_len;
+};
+
+struct printk_info_ctrl_block_s {
+ unsigned char flag[PRINTK_FLAG_LEN];
+ unsigned int len;
+};
+
+struct image_super_block_s {
+ unsigned char byte_order;
+ unsigned char checksum;
+ unsigned short version;
+ unsigned int magic_flag;
+ unsigned int panic_nums;
+ struct panic_ctrl_block_s panic_ctrl_blk[SLOT_NUM];
+ struct printk_info_ctrl_block_s printk_ctrl_blk[PRINTK_NUM];
+ struct thread_info_ctrl_block_s thread_ctrl_blk;
+};
+
+#define SECTION_KERNEL_LEN (sizeof(struct image_super_block_s))
+#define SECTION_PANIC_LEN (8 * SLOT_LENGTH)
+#define SECTION_PRINTK_LEN (512 * 1024)
+#define SECTION_USER_LEN (2 * 1024 * 1024)
+
+#define SECTION_KERNEL_OFFSET (0)
+#define SECTION_PANIC_OFFSET SECTION_KERNEL_LEN
+#define SECTION_THREAD_OFFSET (SECTION_KERNEL_LEN + SECTION_PANIC_LEN)
+
+void __iomem *kbox_get_section_addr(enum kbox_section_e kbox_section);
+unsigned long kbox_get_section_len(enum kbox_section_e kbox_section);
+unsigned long kbox_get_section_phy_addr(enum kbox_section_e kbox_section);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c
new file mode 100644
index 000000000000..49690bab1cef
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c
@@ -0,0 +1,986 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+#include <linux/capability.h>
+#include <linux/uaccess.h> /* copy_*_user */
+#include <linux/delay.h> /* udelay */
+#include <linux/mm.h>
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+
+#ifndef VM_RESERVED
+#define VM_RESERVED 0x00080000
+#endif
+
+static DEFINE_SPINLOCK(g_kbox_super_block_lock);
+static DEFINE_SEMAPHORE(user_sem);
+
+union char_int_transfer_u {
+ int data_int;
+ char data_char[KBOX_RW_UNIT];
+};
+
+static struct image_super_block_s g_kbox_super_block = { };
+
+void kbox_write_to_pci(void __iomem *dest, const void *src, int len,
+ unsigned long offset)
+{
+ union char_int_transfer_u transfer = { };
+ int idx = 0;
+ int j = 0;
+ int four_byte_len = 0;
+ int left_len = 0;
+ char *src_temp = (char *)src;
+ char *dest_temp = (char *)dest;
+ int first_write_num = 0;
+
+ if ((offset % KBOX_RW_UNIT) != 0) {
+ transfer.data_int =
+ *(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT));
+
+ rmb();/* memory barriers. */
+ first_write_num =
+ ((len + (offset % KBOX_RW_UNIT)) >
+ KBOX_RW_UNIT) ? (KBOX_RW_UNIT -
+ (offset % KBOX_RW_UNIT)) : len;
+ for (idx = (int)(offset % KBOX_RW_UNIT);
+ idx < (int)(first_write_num + (offset % KBOX_RW_UNIT));
+ idx++) {
+ if (!src_temp)
+ return;
+
+ transfer.data_char[idx] = *src_temp;
+ src_temp++;
+ }
+ *(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT)) =
+ transfer.data_int;
+ wmb();/* memory barriers. */
+ len -= first_write_num;
+ offset += first_write_num;
+ }
+
+ four_byte_len = (len / KBOX_RW_UNIT);
+ left_len = (len % KBOX_RW_UNIT);
+ for (idx = 0; idx < four_byte_len; idx++) {
+ for (j = 0; j < KBOX_RW_UNIT; j++) {
+ if (!src_temp)
+ return;
+
+ transfer.data_char[j] = *src_temp;
+ src_temp++;
+ }
+ *(int *)(dest_temp + offset) = transfer.data_int;
+ wmb();/* memory barriers. */
+ offset += KBOX_RW_UNIT;
+ }
+
+ if (left_len != 0) {
+ transfer.data_int = *(int *)(dest_temp + offset);
+ rmb();/* memory barriers. */
+ for (idx = 0; idx < left_len; idx++) {
+ if (!src_temp)
+ return;
+
+ transfer.data_char[idx] = *src_temp;
+ src_temp++;
+ }
+ *(int *)(dest_temp + offset) = transfer.data_int;
+ wmb();/* memory barriers. */
+ }
+
+ udelay(1);
+}
+
+void kbox_read_from_pci(void *dest, void __iomem *src, int len,
+ unsigned long offset)
+{
+ union char_int_transfer_u transfer = { };
+ int idx = 0;
+ int j = 0;
+ int four_byte_len = 0;
+ int left_len = 0;
+ char *dest_temp = (char *)dest;
+ char *src_temp = (char *)src;
+ int first_read_num = 0;
+
+ if ((offset % KBOX_RW_UNIT) != 0) {
+ transfer.data_int =
+ *(int *)(src_temp + offset - (offset % KBOX_RW_UNIT));
+ first_read_num =
+ ((len + (offset % KBOX_RW_UNIT)) >
+ KBOX_RW_UNIT) ? (KBOX_RW_UNIT -
+ (offset % KBOX_RW_UNIT)) : len;
+ rmb();/* memory barriers. */
+ for (idx = (int)(offset % KBOX_RW_UNIT);
+ idx < (int)(first_read_num + (offset % KBOX_RW_UNIT));
+ idx++) {
+ if (!dest_temp)
+ return;
+
+ *dest_temp = transfer.data_char[idx];
+ dest_temp++;
+ }
+ len -= first_read_num;
+ offset += first_read_num;
+ }
+
+ four_byte_len = (len / KBOX_RW_UNIT);
+ left_len = (len % KBOX_RW_UNIT);
+ for (idx = 0; idx < four_byte_len; idx++) {
+ transfer.data_int = *(int *)(src_temp + offset);
+ rmb();/* memory barriers. */
+ for (j = 0; j < KBOX_RW_UNIT; j++) {
+ if (!dest_temp)
+ return;
+
+ *dest_temp = transfer.data_char[j];
+ dest_temp++;
+ }
+ offset += KBOX_RW_UNIT;
+ }
+
+ if (left_len != 0) {
+ transfer.data_int = *(int *)(src_temp + offset);
+ rmb();/* memory barriers. */
+ for (idx = 0; idx < left_len; idx++) {
+ if (!dest_temp)
+ return;
+
+ *dest_temp = transfer.data_char[idx];
+ dest_temp++;
+ }
+ }
+}
+
+void kbox_memset_pci(void __iomem *dest, const char set_byte, int len,
+ unsigned long offset)
+{
+ union char_int_transfer_u transfer = { };
+ int idx = 0;
+ int four_byte_len = 0;
+ int left_len = 0;
+ char *dest_temp = (char *)dest;
+ int first_memset_num = 0;
+
+ if ((offset % KBOX_RW_UNIT) != 0) {
+ transfer.data_int =
+ *(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT));
+ rmb();/* memory barriers. */
+ first_memset_num =
+ ((len + (offset % KBOX_RW_UNIT)) >
+ KBOX_RW_UNIT) ? (KBOX_RW_UNIT -
+ (offset % KBOX_RW_UNIT)) : len;
+ for (idx = (int)(offset % KBOX_RW_UNIT);
+ idx < (int)(first_memset_num + (offset % KBOX_RW_UNIT));
+ idx++) {
+ transfer.data_char[idx] = set_byte;
+ }
+ *(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT)) =
+ transfer.data_int;
+ wmb();/* memory barriers. */
+ len -= first_memset_num;
+ offset += first_memset_num;
+ }
+
+ four_byte_len = (len / KBOX_RW_UNIT);
+ left_len = (len % KBOX_RW_UNIT);
+ for (idx = 0; idx < KBOX_RW_UNIT; idx++)
+ transfer.data_char[idx] = set_byte;
+
+ for (idx = 0; idx < four_byte_len; idx++) {
+ *(int *)(dest_temp + offset) = transfer.data_int;
+ wmb();/* memory barriers. */
+ offset += KBOX_RW_UNIT;
+ }
+
+ if (left_len != 0) {
+ transfer.data_int = *(int *)(dest_temp + offset);
+ rmb();/* memory barriers. */
+ for (idx = 0; idx < left_len; idx++)
+ transfer.data_char[idx] = set_byte;
+
+ *(int *)(dest_temp + offset) = transfer.data_int;
+ wmb();/* memory barriers. */
+ }
+
+ udelay(1);
+}
+
+int kbox_read_from_ram(unsigned long offset, unsigned int count, char *data,
+ enum kbox_section_e section)
+{
+ unsigned int read_len_total = count;
+ unsigned long offset_temp = offset;
+ void __iomem *kbox_section_addr = kbox_get_section_addr(section);
+ unsigned long kbox_section_len = kbox_get_section_len(section);
+ unsigned int read_len_real = 0;
+
+ if (!data) {
+ KBOX_MSG("input NULL point!\n");
+ return -EFAULT;
+ }
+
+ if (!kbox_section_addr || kbox_section_len == 0) {
+ KBOX_MSG("get kbox_section_addr or kbox_section_len failed!\n");
+ return -EFAULT;
+ }
+
+ if (offset >= kbox_section_len) {
+ KBOX_MSG("input offset is error!\n");
+ return -EFAULT;
+ }
+
+ if ((offset + count) > kbox_section_len)
+ read_len_total = (unsigned int)(kbox_section_len - offset);
+
+ while (1) {
+ unsigned int read_bytes = 0;
+
+ if (read_len_real >= count)
+ break;
+
+ read_bytes =
+ (read_len_total >
+ TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : read_len_total;
+
+ kbox_read_from_pci(data, kbox_section_addr, read_bytes,
+ offset_temp);
+
+ read_len_total -= read_bytes;
+ read_len_real += read_bytes;
+ data += read_bytes;
+ offset_temp += read_bytes;
+ }
+
+ return (int)read_len_real;
+}
+
+int kbox_write_to_ram(unsigned long offset, unsigned int count,
+ const char *data, enum kbox_section_e section)
+{
+ unsigned int write_len_total = count;
+ unsigned long offset_temp = offset;
+ void __iomem *kbox_section_addr = kbox_get_section_addr(section);
+ unsigned long kbox_section_len = kbox_get_section_len(section);
+ unsigned int write_len_real = 0;
+
+ if (!data) {
+ KBOX_MSG("input NULL point!\n");
+ return -EFAULT;
+ }
+
+ if (!kbox_section_addr || kbox_section_len == 0) {
+ KBOX_MSG("get kbox_section_addr or kbox_section_len failed!\n");
+ return -EFAULT;
+ }
+
+ if (offset >= kbox_section_len) {
+ KBOX_MSG("input offset is error!\n");
+ return -EFAULT;
+ }
+
+ if ((offset + count) > kbox_section_len)
+ write_len_total = (unsigned int)(kbox_section_len - offset);
+
+ KBOX_MSG("struct image_super_block_s = %x\n", count);
+ while (1) {
+ unsigned int write_bytes = 0;
+
+ if (write_len_real >= count) {
+ KBOX_MSG("write_len_real = %x\n", write_len_real);
+ break;
+ }
+ KBOX_MSG("write_len_total = %x\n", write_len_total);
+
+ write_bytes =
+ (write_len_total >
+ TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : write_len_total;
+ KBOX_MSG("write_bytes = %x\n", write_bytes);
+
+ kbox_write_to_pci(kbox_section_addr, data, write_bytes,
+ offset_temp);
+
+ write_len_total -= write_bytes;
+ write_len_real += write_bytes;
+ data += write_bytes;
+ offset_temp += write_bytes;
+ }
+
+ return (int)write_len_real;
+}
+
+int kbox_memset_ram(unsigned long offset, unsigned int count,
+ const char set_byte, enum kbox_section_e section)
+{
+ unsigned int memset_len = count;
+ void __iomem *kbox_section_addr = kbox_get_section_addr(section);
+ unsigned long kbox_section_len = kbox_get_section_len(section);
+
+ if (!kbox_section_addr || kbox_section_len == 0) {
+ KBOX_MSG("get kbox_section_addr or kbox_section_len failed!\n");
+ return -EFAULT;
+ }
+
+ if (offset >= kbox_section_len) {
+ KBOX_MSG("input offset is error!\n");
+ return -EFAULT;
+ }
+
+ if ((offset + count) > kbox_section_len)
+ memset_len = (unsigned int)(kbox_section_len - offset);
+
+ kbox_memset_pci(kbox_section_addr, set_byte, memset_len, offset);
+
+ return KBOX_TRUE;
+}
+
+int kbox_read_op(long long offset, unsigned int count, char __user *data,
+ enum kbox_section_e section)
+{
+ unsigned int read_bytes = 0;
+ unsigned int read_len = 0;
+ unsigned int left_len = count;
+ char *user_buf = data;
+ char *temp_buf_char = NULL;
+ unsigned long offset_tmp = offset;
+
+ if (!data) {
+ KBOX_MSG("input NULL point!\n");
+ return -EFAULT;
+ }
+
+ if (down_interruptible(&user_sem) != 0)
+ return KBOX_FALSE;
+
+ temp_buf_char = kmalloc(TEMP_BUF_DATA_SIZE, GFP_KERNEL);
+ if (!temp_buf_char) {
+ KBOX_MSG("kmalloc temp_buf_char fail!\n");
+ up(&user_sem);
+ return -ENOMEM;
+ }
+
+ memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+ while (1) {
+ if (read_len >= count)
+ break;
+
+ read_bytes =
+ (left_len >
+ TEMP_BUF_DATA_SIZE) ? TEMP_BUF_DATA_SIZE : left_len;
+
+ if (kbox_read_from_ram
+ (offset_tmp, read_bytes, temp_buf_char, section) < 0) {
+ KBOX_MSG("kbox_read_from_ram fail!\n");
+ break;
+ }
+
+ if (copy_to_user(user_buf, temp_buf_char, read_bytes)) {
+ KBOX_MSG("copy_to_user fail!\n");
+ break;
+ }
+
+ left_len -= read_bytes;
+ read_len += read_bytes;
+ user_buf += read_bytes;
+
+ offset_tmp += read_bytes;
+ memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+ msleep(20);
+ }
+
+ kfree(temp_buf_char);
+
+ up(&user_sem);
+
+ return (int)read_len;
+}
+
+int kbox_write_op(long long offset, unsigned int count,
+ const char __user *data, enum kbox_section_e section)
+{
+ unsigned int write_len = 0;
+ unsigned int left_len = count;
+ const char *user_buf = data;
+ char *temp_buf_char = NULL;
+ unsigned long offset_tmp = offset;
+
+ if (!data) {
+ KBOX_MSG("input NULL point!\n");
+ return -EFAULT;
+ }
+
+ if (down_interruptible(&user_sem) != 0)
+ return KBOX_FALSE;
+
+ temp_buf_char = kmalloc(TEMP_BUF_DATA_SIZE, GFP_KERNEL);
+ if (!temp_buf_char || IS_ERR(temp_buf_char)) {
+ KBOX_MSG("kmalloc temp_buf_char fail!\n");
+ up(&user_sem);
+ return -ENOMEM;
+ }
+
+ memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+ while (1) {
+ unsigned int write_bytes = 0;
+
+ if (write_len >= count)
+ break;
+
+ write_bytes =
+ (left_len >
+ TEMP_BUF_DATA_SIZE) ? TEMP_BUF_DATA_SIZE : left_len;
+
+ if (copy_from_user(temp_buf_char, user_buf, write_bytes)) {
+ KBOX_MSG("copy_from_user fail!\n");
+ break;
+ }
+
+ if (kbox_write_to_ram
+ (offset_tmp, write_bytes, temp_buf_char, section) < 0) {
+ KBOX_MSG("kbox_write_to_ram fail!\n");
+ break;
+ }
+
+ left_len -= write_bytes;
+ write_len += write_bytes;
+ user_buf += write_bytes;
+
+ offset_tmp += write_bytes;
+ memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+ msleep(20);
+ }
+
+ kfree(temp_buf_char);
+
+ up(&user_sem);
+
+ return (int)write_len;
+}
+
+char kbox_checksum(const char *input_buf, unsigned int len)
+{
+ unsigned int idx = 0;
+ char checksum = 0;
+
+ for (idx = 0; idx < len; idx++)
+ checksum += input_buf[idx];
+
+ return checksum;
+}
+
+static int kbox_update_super_block(void)
+{
+ int write_len = 0;
+
+ g_kbox_super_block.checksum = 0;
+ g_kbox_super_block.checksum =
+ ~((unsigned char)
+ kbox_checksum((char *)&g_kbox_super_block,
+ (unsigned int)sizeof(g_kbox_super_block))) + 1;
+ write_len =
+ kbox_write_to_ram(SECTION_KERNEL_OFFSET,
+ (unsigned int)sizeof(struct image_super_block_s),
+ (char *)&g_kbox_super_block, KBOX_SECTION_KERNEL);
+ if (write_len <= 0) {
+ KBOX_MSG("fail to write superblock data!\n");
+ return KBOX_FALSE;
+ }
+
+ return KBOX_TRUE;
+}
+
+int kbox_read_super_block(void)
+{
+ int read_len = 0;
+
+ read_len =
+ kbox_read_from_ram(SECTION_KERNEL_OFFSET,
+ (unsigned int)sizeof(struct image_super_block_s),
+ (char *)&g_kbox_super_block,
+ KBOX_SECTION_KERNEL);
+ if (read_len != sizeof(struct image_super_block_s)) {
+ KBOX_MSG("fail to get superblock data!\n");
+ return KBOX_FALSE;
+ }
+
+ return KBOX_TRUE;
+}
+
+static unsigned char kbox_get_byte_order(void)
+{
+ unsigned short data_short = 0xB22B;
+ unsigned char *data_char = (unsigned char *)&data_short;
+
+ return (unsigned char)((*data_char == 0xB2) ? KBOX_BIG_ENDIAN :
+ KBOX_LITTLE_ENDIAN);
+}
+
+int kbox_super_block_init(void)
+{
+ int ret = 0;
+
+ ret = kbox_read_super_block();
+ if (ret != KBOX_TRUE) {
+ KBOX_MSG("kbox_read_super_block fail!\n");
+ return ret;
+ }
+
+ if (!VALID_IMAGE(&g_kbox_super_block) ||
+ kbox_checksum((char *)&g_kbox_super_block,
+ (unsigned int)sizeof(g_kbox_super_block)) != 0) {
+ if (!VALID_IMAGE(&g_kbox_super_block)) {
+ memset((void *)&g_kbox_super_block, 0x00,
+ sizeof(struct image_super_block_s));
+ }
+
+ g_kbox_super_block.byte_order = kbox_get_byte_order();
+ g_kbox_super_block.version = IMAGE_VER;
+ g_kbox_super_block.magic_flag = IMAGE_MAGIC;
+ }
+
+ g_kbox_super_block.thread_ctrl_blk.thread_info_len = 0;
+
+ if (kbox_update_super_block() != KBOX_TRUE) {
+ KBOX_MSG("kbox_update_super_block failed!\n");
+ return KBOX_FALSE;
+ }
+
+ return KBOX_TRUE;
+}
+
+static unsigned char kbox_get_write_slot_num(void)
+{
+ struct panic_ctrl_block_s *panic_ctrl_block = NULL;
+ unsigned int idx = 0;
+ unsigned char slot_num = 0;
+ unsigned char min_use_nums = 0;
+
+ panic_ctrl_block = g_kbox_super_block.panic_ctrl_blk;
+ min_use_nums = panic_ctrl_block->use_nums;
+
+ for (idx = 1; idx < SLOT_NUM; idx++) {
+ panic_ctrl_block++;
+ if (panic_ctrl_block->use_nums < min_use_nums) {
+ min_use_nums = panic_ctrl_block->use_nums;
+ slot_num = (unsigned char)idx;
+ }
+ }
+
+ if (min_use_nums == MAX_USE_NUMS) {
+ panic_ctrl_block = g_kbox_super_block.panic_ctrl_blk;
+ for (idx = 0; idx < SLOT_NUM; idx++) {
+ panic_ctrl_block->use_nums = 1;
+ panic_ctrl_block++;
+ }
+ }
+
+ return slot_num;
+}
+
+static unsigned char kbox_get_new_record_number(void)
+{
+ struct panic_ctrl_block_s *panic_ctrl_block = NULL;
+ unsigned int idx = 0;
+ unsigned char max_number = 0;
+
+ panic_ctrl_block = g_kbox_super_block.panic_ctrl_blk;
+ for (idx = 0; idx < SLOT_NUM; idx++) {
+ if (panic_ctrl_block->number >= max_number)
+ max_number = panic_ctrl_block->number;
+
+ panic_ctrl_block++;
+ }
+
+ return (unsigned char)((max_number + 1) % MAX_RECORD_NO);
+}
+
+int kbox_write_panic_info(const char *input_data, unsigned int data_len)
+{
+ int write_len = 0;
+ unsigned int offset = 0;
+ struct panic_ctrl_block_s *panic_ctrl_block = NULL;
+ unsigned long time = get_seconds();
+ unsigned char slot_num = 0;
+ unsigned long flags = 0;
+
+ if (!input_data || data_len == 0) {
+ KBOX_MSG("input parameter error!\n");
+ return KBOX_FALSE;
+ }
+
+ if (data_len > SLOT_LENGTH)
+ data_len = SLOT_LENGTH;
+
+ spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+ slot_num = kbox_get_write_slot_num();
+
+ panic_ctrl_block = &g_kbox_super_block.panic_ctrl_blk[slot_num];
+ panic_ctrl_block->use_nums++;
+
+ panic_ctrl_block->number = kbox_get_new_record_number();
+ panic_ctrl_block->len = 0;
+ panic_ctrl_block->time = (unsigned int)time;
+
+ g_kbox_super_block.panic_nums++;
+
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+ offset = slot_num * SLOT_LENGTH;
+ write_len =
+ kbox_write_to_ram(offset, data_len, input_data, KBOX_SECTION_PANIC);
+ if (write_len <= 0) {
+ KBOX_MSG("fail to save panic information!\n");
+ return KBOX_FALSE;
+ }
+
+ spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+ panic_ctrl_block->len += (unsigned short)write_len;
+
+ if (kbox_update_super_block() != KBOX_TRUE) {
+ KBOX_MSG("kbox_update_super_block failed!\n");
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+ return KBOX_FALSE;
+ }
+
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+ return KBOX_TRUE;
+}
+
+int kbox_write_thread_info(const char *input_data, unsigned int data_len)
+{
+ int write_len = 0;
+ unsigned int offset = 0;
+ unsigned long flags = 0;
+ unsigned int date_len_tmp = data_len;
+
+ if (!input_data || date_len_tmp == 0) {
+ KBOX_MSG("input parameter error!\n");
+ return KBOX_FALSE;
+ }
+
+ spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+ offset = g_kbox_super_block.thread_ctrl_blk.thread_info_len;
+ write_len =
+ kbox_write_to_ram(offset, date_len_tmp, input_data,
+ KBOX_SECTION_THREAD);
+ if (write_len <= 0) {
+ KBOX_MSG("fail to save thread information!\n");
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+ return KBOX_FALSE;
+ }
+
+ g_kbox_super_block.thread_ctrl_blk.thread_info_len += write_len;
+
+ if (kbox_update_super_block() != KBOX_TRUE) {
+ KBOX_MSG("kbox_update_super_block failed!\n");
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+ return KBOX_FALSE;
+ }
+
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+ return KBOX_TRUE;
+}
+
+int kbox_read_printk_info(char *input_data,
+ struct printk_ctrl_block_tmp_s *printk_ctrl_block_tmp)
+{
+ int read_len = 0;
+ int printk_region = printk_ctrl_block_tmp->printk_region;
+ unsigned int len = 0;
+
+ if (!input_data) {
+ KBOX_MSG("input parameter error!\n");
+ return KBOX_FALSE;
+ }
+
+ len = g_kbox_super_block.printk_ctrl_blk[printk_region].len;
+ if (len <= 0) {
+ printk_ctrl_block_tmp->end = 0;
+ printk_ctrl_block_tmp->valid_len = 0;
+ return KBOX_TRUE;
+ }
+
+ read_len =
+ kbox_read_from_ram(0, len, input_data,
+ printk_ctrl_block_tmp->section);
+ if (read_len < 0) {
+ KBOX_MSG("fail to read printk information!(1)\n");
+ return KBOX_FALSE;
+ }
+
+ printk_ctrl_block_tmp->end = len;
+ printk_ctrl_block_tmp->valid_len = len;
+
+ return KBOX_TRUE;
+}
+
+int kbox_write_printk_info(const char *input_data,
+ struct printk_ctrl_block_tmp_s *
+ printk_ctrl_block_tmp)
+{
+ int write_len = 0;
+ int printk_region = printk_ctrl_block_tmp->printk_region;
+ unsigned long flags = 0;
+ unsigned int len = 0;
+
+ if (!input_data) {
+ KBOX_MSG("input parameter error!\n");
+ return KBOX_FALSE;
+ }
+
+ len = printk_ctrl_block_tmp->valid_len;
+ write_len =
+ kbox_write_to_ram(0, len, input_data,
+ printk_ctrl_block_tmp->section);
+ if (write_len <= 0) {
+ KBOX_MSG("fail to save printk information!(1)\n");
+ return KBOX_FALSE;
+ }
+
+ spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+ g_kbox_super_block.printk_ctrl_blk[printk_region].len = len;
+
+ if (kbox_update_super_block() != KBOX_TRUE) {
+ KBOX_MSG("kbox_update_super_block failed!\n");
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+ return KBOX_FALSE;
+ }
+
+ spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+ return KBOX_TRUE;
+}
+
+static int kbox_read_region(unsigned long arg)
+{
+ unsigned int read_len = 0;
+ struct kbox_region_arg_s region_arg = { };
+
+ if (copy_from_user
+ ((void *)®ion_arg, (void __user *)arg,
+ sizeof(struct kbox_region_arg_s))) {
+ KBOX_MSG("fail to copy_from_user!\n");
+ return KBOX_FALSE;
+ }
+
+ read_len = kbox_read_op((long long)region_arg.offset, region_arg.count,
+ (char __user *)region_arg.data,
+ KBOX_SECTION_ALL);
+ if (read_len <= 0) {
+ KBOX_MSG("fail to get kbox data!\n");
+ return KBOX_FALSE;
+ }
+
+ if (copy_to_user
+ ((void __user *)arg, (void *)®ion_arg,
+ sizeof(struct kbox_region_arg_s))) {
+ KBOX_MSG("fail to copy_to_user!\n");
+ return KBOX_FALSE;
+ }
+
+ return KBOX_TRUE;
+}
+
+static int kbox_writer_region(unsigned long arg)
+{
+ unsigned int write_len = 0;
+ struct kbox_region_arg_s region_arg = { };
+
+ if (copy_from_user
+ ((void *)®ion_arg, (void __user *)arg,
+ sizeof(struct kbox_region_arg_s))) {
+ KBOX_MSG("fail to copy_from_user!\n");
+ return KBOX_FALSE;
+ }
+
+ write_len = kbox_write_op((long long)region_arg.offset,
+ region_arg.count,
+ (char __user *)region_arg.data,
+ KBOX_SECTION_ALL);
+ if (write_len <= 0) {
+ KBOX_MSG("fail to write kbox data!\n");
+ return KBOX_FALSE;
+ }
+
+ if (copy_to_user
+ ((void __user *)arg, (void *)®ion_arg,
+ sizeof(struct kbox_region_arg_s))) {
+ KBOX_MSG("fail to copy_to_user!\n");
+ return KBOX_FALSE;
+ }
+
+ return KBOX_TRUE;
+}
+
+int kbox_clear_region(enum kbox_section_e section)
+{
+ int ret = KBOX_TRUE;
+ unsigned long kbox_section_len = kbox_get_section_len(section);
+
+ if (kbox_section_len == 0) {
+ KBOX_MSG("get kbox_section_len failed!\n");
+ return -EFAULT;
+ }
+
+ ret = kbox_memset_ram(0, (unsigned int)kbox_section_len, 0, section);
+ if (ret != KBOX_TRUE) {
+ KBOX_MSG("kbox_memset_ram failed!\n");
+ return -EFAULT;
+ }
+
+ return KBOX_TRUE;
+}
+
+static int kbox_get_image_len(unsigned long arg)
+{
+ unsigned long __user *ptr = (unsigned long __user *)arg;
+ unsigned long kbox_len = 0;
+
+ kbox_len = kbox_get_section_len(KBOX_SECTION_ALL);
+ if (kbox_len == 0) {
+ KBOX_MSG("kbox_get_section_len section all fail!\n");
+ return -EFAULT;
+ }
+
+ return put_user(kbox_len, ptr);
+}
+
+static int kbox_get_user_region_len(unsigned long arg)
+{
+ unsigned long __user *ptr = (unsigned long __user *)arg;
+ unsigned long kbox_user_region_len = 0;
+
+ kbox_user_region_len = kbox_get_section_len(KBOX_SECTION_USER);
+ if (kbox_user_region_len == 0) {
+ KBOX_MSG("kbox_get_section_len section user fail!\n");
+ return -EFAULT;
+ }
+
+ return put_user(kbox_user_region_len, ptr);
+}
+
+static int kbox_ioctl_verify_cmd(unsigned int cmd, unsigned long arg)
+{
+ if (arg == 0 || (_IOC_TYPE(cmd) != KBOX_IOC_MAGIC))
+ return KBOX_FALSE;
+
+ if (_IOC_NR(cmd) > KBOX_IOC_MAXNR)
+ return KBOX_FALSE;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ KBOX_MSG("permit error\n");
+ return KBOX_FALSE;
+ }
+
+ return KBOX_TRUE;
+}
+
+int kbox_ioctl_detail(unsigned int cmd, unsigned long arg)
+{
+ if (kbox_ioctl_verify_cmd(cmd, arg) != KBOX_TRUE)
+ return -EFAULT;
+
+ switch (cmd) {
+ case GET_KBOX_TOTAL_LEN:
+ return kbox_get_image_len(arg);
+
+ case GET_KBOX_REGION_USER_LEN:
+ return kbox_get_user_region_len(arg);
+
+ case KBOX_REGION_READ:
+ return kbox_read_region(arg);
+
+ case KBOX_REGION_WRITE:
+ return kbox_writer_region(arg);
+
+ case CLEAR_KBOX_REGION_ALL:
+ return kbox_clear_region(KBOX_SECTION_ALL);
+
+ case CLEAR_KBOX_REGION_USER:
+ return kbox_clear_region(KBOX_SECTION_USER);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+int kbox_mmap_ram(struct file *pfile, struct vm_area_struct *vma,
+ enum kbox_section_e section)
+{
+ unsigned long kbox_section_phy_addr =
+ kbox_get_section_phy_addr(section);
+ unsigned long kbox_section_len = kbox_get_section_len(section);
+ unsigned long offset = 0;
+ unsigned long length = 0;
+ unsigned long vm_size = 0;
+ int ret = 0;
+
+ UNUSED(pfile);
+
+ if (kbox_section_phy_addr == 0 || kbox_section_len == 0) {
+ KBOX_MSG
+ ("get kbox_section_phy_addr or kbox_section_len failed!\n");
+ return -EFAULT;
+ }
+
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+ vm_size = vma->vm_end - vma->vm_start;
+
+ if (offset >= kbox_section_len) {
+ KBOX_MSG("vma offset is invalid!\n");
+ return -ESPIPE;
+ }
+
+ if (vma->vm_flags & VM_LOCKED) {
+ KBOX_MSG("vma is locked!\n");
+ return -EPERM;
+ }
+
+ length = kbox_section_len - offset;
+ if (vm_size > length) {
+ KBOX_MSG("vm_size is invalid!\n");
+ return -ENOSPC;
+ }
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_flags |= VM_IO;
+
+ ret = remap_pfn_range(vma,
+ vma->vm_start,
+ (unsigned long)(kbox_section_phy_addr >>
+ PAGE_SHIFT), vm_size,
+ vma->vm_page_prot);
+ if (ret) {
+ KBOX_MSG("remap_pfn_range failed! ret = %d\n", ret);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.h
new file mode 100644
index 000000000000..4a92c87de139
--- /dev/null
+++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_RAM_OP_H_
+#define _KBOX_RAM_OP_H_
+
+#include <asm/ioctls.h>
+#include <linux/fs.h>
+#include "kbox_printk.h"
+
+#define KBOX_IOC_MAGIC (0xB2)
+
+#define GET_KBOX_TOTAL_LEN _IOR(KBOX_IOC_MAGIC, 0, unsigned long)
+
+#define GET_KBOX_REGION_USER_LEN _IOR(KBOX_IOC_MAGIC, 1, unsigned long)
+
+#define CLEAR_KBOX_REGION_ALL _IO(KBOX_IOC_MAGIC, 2)
+
+#define CLEAR_KBOX_REGION_USER _IO(KBOX_IOC_MAGIC, 3)
+
+#define KBOX_REGION_READ _IOR(KBOX_IOC_MAGIC, 4, struct kbox_region_arg_s)
+
+#define KBOX_REGION_WRITE _IOW(KBOX_IOC_MAGIC, 5, struct kbox_region_arg_s)
+
+#define KBOX_IOC_MAXNR 6
+
+#define TEMP_BUF_SIZE (32 * 1024)
+#define TEMP_BUF_DATA_SIZE (128 * 1024)
+#define KBOX_RW_UNIT 4
+
+struct kbox_region_arg_s {
+ unsigned long offset;
+ unsigned int count;
+ char *data;
+};
+
+enum kbox_section_e;
+
+int kbox_read_op(long long offset, unsigned int count, char __user *data,
+ enum kbox_section_e section);
+int kbox_write_op(long long offset, unsigned int count,
+ const char __user *data, enum kbox_section_e section);
+int kbox_read_super_block(void);
+int kbox_super_block_init(void);
+int kbox_write_panic_info(const char *input_data, unsigned int data_len);
+int kbox_write_thread_info(const char *input_data, unsigned int data_len);
+int kbox_write_printk_info(const char *input_data,
+ struct printk_ctrl_block_tmp_s
+ *printk_ctrl_block_tmp);
+int kbox_read_printk_info(char *input_data,
+ struct printk_ctrl_block_tmp_s
+ *printk_ctrl_block_tmp);
+int kbox_ioctl_detail(unsigned int cmd, unsigned long arg);
+int kbox_mmap_ram(struct file *file, struct vm_area_struct *vma,
+ enum kbox_section_e section);
+char kbox_checksum(const char *input_buf, unsigned int len);
+int kbox_write_to_ram(unsigned long offset, unsigned int count,
+ const char *data, enum kbox_section_e section);
+int kbox_read_from_ram(unsigned long offset, unsigned int count, char *data,
+ enum kbox_section_e section);
+int kbox_clear_region(enum kbox_section_e section);
+int kbox_memset_ram(unsigned long offset, unsigned int count,
+ const char set_byte, enum kbox_section_e section);
+
+#endif
--
2.26.2.windows.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox