* Re: KASAN: use-after-free Read in sctp_packet_transmit
From: Eric Biggers @ 2018-05-12 20:00 UTC (permalink / raw)
To: syzbot
Cc: davem, linux-kernel, linux-sctp, netdev, nhorman, syzkaller-bugs,
vyasevich
In-Reply-To: <94eb2c1fcf4cf899b405620eaa66@google.com>
On Fri, Jan 05, 2018 at 02:07:01PM -0800, syzbot wrote:
> Hello,
>
> syzkaller hit the following crash on
> 8a4816cad00bf14642f0ed6043b32d29a05006ce
> git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/master
> compiler: gcc (GCC) 7.1.1 20170620
> .config is attached
> Raw console output is attached.
> Unfortunately, I don't have any reproducer for this bug yet.
>
>
> IMPORTANT: if you fix the bug, please add the following tag to the commit:
> Reported-by: syzbot+5adcca18fca253b4cb15@syzkaller.appspotmail.com
> It will help syzbot understand when the bug is fixed. See footer for
> details.
> If you forward the report, please keep this part and the footer.
>
> ==================================================================
> BUG: KASAN: use-after-free in sctp_packet_transmit+0x3505/0x3750
> net/sctp/output.c:643
> Read of size 8 at addr ffff8801bda9fb80 by task modprobe/23740
>
> CPU: 1 PID: 23740 Comm: modprobe Not tainted 4.15.0-rc5+ #175
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
> Google 01/01/2011
> Call Trace:
> <IRQ>
> __dump_stack lib/dump_stack.c:17 [inline]
> dump_stack+0x194/0x257 lib/dump_stack.c:53
> print_address_description+0x73/0x250 mm/kasan/report.c:252
> kasan_report_error mm/kasan/report.c:351 [inline]
> kasan_report+0x25b/0x340 mm/kasan/report.c:409
> __asan_report_load8_noabort+0x14/0x20 mm/kasan/report.c:430
> sctp_packet_transmit+0x3505/0x3750 net/sctp/output.c:643
> sctp_outq_flush+0x121b/0x4060 net/sctp/outqueue.c:1197
> sctp_outq_uncork+0x5a/0x70 net/sctp/outqueue.c:776
> sctp_cmd_interpreter net/sctp/sm_sideeffect.c:1807 [inline]
> sctp_side_effects net/sctp/sm_sideeffect.c:1210 [inline]
> sctp_do_sm+0x4e0/0x6ed0 net/sctp/sm_sideeffect.c:1181
> sctp_generate_heartbeat_event+0x292/0x3f0 net/sctp/sm_sideeffect.c:406
> call_timer_fn+0x228/0x820 kernel/time/timer.c:1320
> expire_timers kernel/time/timer.c:1357 [inline]
> __run_timers+0x7ee/0xb70 kernel/time/timer.c:1660
> run_timer_softirq+0x4c/0xb0 kernel/time/timer.c:1686
> __do_softirq+0x2d7/0xb85 kernel/softirq.c:285
> invoke_softirq kernel/softirq.c:365 [inline]
> irq_exit+0x1cc/0x200 kernel/softirq.c:405
> exiting_irq arch/x86/include/asm/apic.h:540 [inline]
> smp_apic_timer_interrupt+0x16b/0x700 arch/x86/kernel/apic/apic.c:1052
> apic_timer_interrupt+0xa9/0xb0 arch/x86/entry/entry_64.S:904
> </IRQ>
> RIP: 0010:__preempt_count_add arch/x86/include/asm/preempt.h:76 [inline]
> RIP: 0010:__rcu_read_lock include/linux/rcupdate.h:83 [inline]
> RIP: 0010:rcu_read_lock include/linux/rcupdate.h:629 [inline]
> RIP: 0010:__is_insn_slot_addr+0x8f/0x330 kernel/kprobes.c:303
> RSP: 0018:ffff8801d4937430 EFLAGS: 00000283 ORIG_RAX: ffffffffffffff11
> RAX: ffff8801bf13c000 RBX: ffffffff8656dd00 RCX: ffffffff8170bd88
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff8656dd00
> RBP: ffff8801d4937518 R08: 0000000000000000 R09: 1ffff1003a926e67
> R10: ffff8801d4937300 R11: 0000000000000000 R12: 0000000000000000
> R13: 0000000000000000 R14: ffff8801d49374f0 R15: ffff8801dae230c0
> is_kprobe_insn_slot include/linux/kprobes.h:318 [inline]
> kernel_text_address+0x132/0x140 kernel/extable.c:150
> __kernel_text_address+0xd/0x40 kernel/extable.c:107
> unwind_get_return_address+0x61/0xa0 arch/x86/kernel/unwind_frame.c:18
> __save_stack_trace+0x7e/0xd0 arch/x86/kernel/stacktrace.c:45
> save_stack_trace+0x1a/0x20 arch/x86/kernel/stacktrace.c:60
> save_stack+0x43/0xd0 mm/kasan/kasan.c:447
> set_track mm/kasan/kasan.c:459 [inline]
> kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:551
> kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:489
> kmem_cache_alloc+0x12e/0x760 mm/slab.c:3544
> kmem_cache_zalloc include/linux/slab.h:678 [inline]
> file_alloc_security security/selinux/hooks.c:369 [inline]
> selinux_file_alloc_security+0xae/0x190 security/selinux/hooks.c:3454
> security_file_alloc+0x6d/0xa0 security/security.c:873
> get_empty_filp+0x189/0x4f0 fs/file_table.c:129
> path_openat+0xed/0x3530 fs/namei.c:3496
> do_filp_open+0x25b/0x3b0 fs/namei.c:3554
> do_sys_open+0x502/0x6d0 fs/open.c:1059
> SYSC_open fs/open.c:1077 [inline]
> SyS_open+0x2d/0x40 fs/open.c:1072
> entry_SYSCALL_64_fastpath+0x23/0x9a
> RIP: 0033:0x7efdff1bb120
> RSP: 002b:00007ffde6213c08 EFLAGS: 00000246 ORIG_RAX: 0000000000000002
> RAX: ffffffffffffffda RBX: 000055c34fab4090 RCX: 00007efdff1bb120
> RDX: 00000000000001b6 RSI: 0000000000080000 RDI: 00007ffde6213d20
> RBP: 00007ffde6214d90 R08: 0000000000000008 R09: 0000000000000001
> R10: 0000000000000000 R11: 0000000000000246 R12: 000055c34fab4090
> R13: 00007ffde6215de0 R14: 0000000000000000 R15: 0000000000000000
>
> Allocated by task 23739:
> save_stack+0x43/0xd0 mm/kasan/kasan.c:447
> set_track mm/kasan/kasan.c:459 [inline]
> kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:551
> kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:489
> kmem_cache_alloc+0x12e/0x760 mm/slab.c:3544
> kmem_cache_zalloc include/linux/slab.h:678 [inline]
> sctp_chunkify+0xce/0x3f0 net/sctp/sm_make_chunk.c:1329
> _sctp_make_chunk+0x13c/0x260 net/sctp/sm_make_chunk.c:1397
> sctp_make_control+0x39/0x150 net/sctp/sm_make_chunk.c:1433
> sctp_make_heartbeat+0x90/0x420 net/sctp/sm_make_chunk.c:1151
> sctp_sf_heartbeat.isra.24+0x26/0x180 net/sctp/sm_statefuns.c:973
> sctp_sf_do_prm_requestheartbeat+0x27/0x100 net/sctp/sm_statefuns.c:5251
> sctp_do_sm+0x192/0x6ed0 net/sctp/sm_sideeffect.c:1178
> sctp_primitive_REQUESTHEARTBEAT+0xa0/0xd0 net/sctp/primitive.c:200
> sctp_apply_peer_addr_params+0x759/0xf30 net/sctp/socket.c:2462
> sctp_setsockopt_peer_addr_params+0x36f/0x5f0 net/sctp/socket.c:2658
> sctp_setsockopt+0x199a/0x61a0 net/sctp/socket.c:4173
> sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978
> SYSC_setsockopt net/socket.c:1821 [inline]
> SyS_setsockopt+0x189/0x360 net/socket.c:1800
> entry_SYSCALL_64_fastpath+0x23/0x9a
>
> Freed by task 23739:
> save_stack+0x43/0xd0 mm/kasan/kasan.c:447
> set_track mm/kasan/kasan.c:459 [inline]
> kasan_slab_free+0x71/0xc0 mm/kasan/kasan.c:524
> __cache_free mm/slab.c:3488 [inline]
> kmem_cache_free+0x83/0x2a0 mm/slab.c:3746
> sctp_chunk_destroy net/sctp/sm_make_chunk.c:1450 [inline]
> sctp_chunk_put+0x2fd/0x420 net/sctp/sm_make_chunk.c:1473
> sctp_chunk_free+0x53/0x60 net/sctp/sm_make_chunk.c:1460
> sctp_packet_transmit+0xf5d/0x3750 net/sctp/output.c:646
> sctp_outq_flush+0x121b/0x4060 net/sctp/outqueue.c:1197
> sctp_outq_uncork+0x5a/0x70 net/sctp/outqueue.c:776
> sctp_cmd_interpreter net/sctp/sm_sideeffect.c:1807 [inline]
> sctp_side_effects net/sctp/sm_sideeffect.c:1210 [inline]
> sctp_do_sm+0x4e0/0x6ed0 net/sctp/sm_sideeffect.c:1181
> sctp_primitive_REQUESTHEARTBEAT+0xa0/0xd0 net/sctp/primitive.c:200
> sctp_apply_peer_addr_params+0x759/0xf30 net/sctp/socket.c:2462
> sctp_setsockopt_peer_addr_params+0x36f/0x5f0 net/sctp/socket.c:2658
> sctp_setsockopt+0x199a/0x61a0 net/sctp/socket.c:4173
> sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978
> SYSC_setsockopt net/socket.c:1821 [inline]
> SyS_setsockopt+0x189/0x360 net/socket.c:1800
> entry_SYSCALL_64_fastpath+0x23/0x9a
>
> The buggy address belongs to the object at ffff8801bda9fb80
> which belongs to the cache sctp_chunk of size 256
> The buggy address is located 0 bytes inside of
> 256-byte region [ffff8801bda9fb80, ffff8801bda9fc80)
> The buggy address belongs to the page:
> page:00000000d1261812 count:1 mapcount:0 mapping:000000003e733284 index:0x0
> flags: 0x2fffc0000000100(slab)
> raw: 02fffc0000000100 ffff8801bda9f040 0000000000000000 000000010000000c
> raw: ffffea000714c9e0 ffffea0006fa8520 ffff8801d3246c80 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff8801bda9fa80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801bda9fb00: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> > ffff8801bda9fb80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff8801bda9fc00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801bda9fc80: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
> ==================================================================
>
>
> ---
> This bug is generated by a dumb bot. It may contain errors.
> See https://goo.gl/tpsmEJ for details.
> Direct all questions to syzkaller@googlegroups.com.
>
> syzbot will keep track of this bug report.
> If you forgot to add the Reported-by tag, once the fix for this bug is
> merged
> into any tree, please reply to this email with:
> #syz fix: exact-commit-title
> To mark this as a duplicate of another syzbot report, please reply with:
> #syz dup: exact-subject-of-another-report
> If it's a one-off invalid bug report, please reply with:
> #syz invalid
> Note: if the crash happens again, it will cause creation of a new bug
> report.
> Note: all commands must start from beginning of the line in the email body.
No reproducer, this only happened once (Jan 5 on net-next), and there have been
a lot of SCTP fixes in the mean time including commit 6910e25de225 ("sctp:
remove sctp_chunk_put from fail_mark err path in sctp_ulpevent_make_rcvmsg")
which may be relevant since it fixed a case of incorrect reference counting of
'struct sctp_chunk', which is the struct in which the use-after-free occurred
here. So I'm just invalidating this bug:
#syz invalid
- Eric
^ permalink raw reply
* Re: KASAN: use-after-free Read in sit_tunnel_xmit
From: Eric Biggers @ 2018-05-12 20:06 UTC (permalink / raw)
To: Cong Wang
Cc: Dmitry Vyukov, syzbot, David Miller, Alexey Kuznetsov, LKML,
Linux Kernel Network Developers, syzkaller-bugs,
Hideaki YOSHIFUJI, Eric Dumazet, Willem de Bruijn
In-Reply-To: <CAM_iQpVEAZ3wOuKV_zbQ_j+1nzKyNHBb5Ne+OfGWDc7EKrPQrQ@mail.gmail.com>
On Thu, Feb 15, 2018 at 04:22:28PM -0800, Cong Wang wrote:
> On Tue, Feb 13, 2018 at 10:48 AM, Dmitry Vyukov <dvyukov@google.com> wrote:
> > On Mon, Oct 30, 2017 at 7:41 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> >> On Mon, Oct 30, 2017 at 8:34 AM, syzbot
> >> <bot+1aa412fe58f4059538c0204a0f096524e6dce60b@syzkaller.appspotmail.com>
> >> wrote:
> >>> Hello,
> >>>
> >>> syzkaller hit the following crash on
> >>> 4dc12ffeaeac939097a3f55c881d3dc3523dff0c
> >>> git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/master
> >>> compiler: gcc (GCC) 7.1.1 20170620
> >>> .config is attached
> >>> Raw console output is attached.
> >>>
> >>> skbuff: bad partial csum: csum=53081/14726 len=2273
> >>> ==================================================================
> >>> BUG: KASAN: use-after-free in ipv6_get_dsfield include/net/dsfield.h:23
> >>> [inline]
> >>> BUG: KASAN: use-after-free in ipip6_tunnel_xmit net/ipv6/sit.c:968 [inline]
> >>> BUG: KASAN: use-after-free in sit_tunnel_xmit+0x2a41/0x3130
> >>> net/ipv6/sit.c:1016
> >>> Read of size 2 at addr ffff8801c64afd00 by task syz-executor3/16942
> >>>
> >>> CPU: 0 PID: 16942 Comm: syz-executor3 Not tainted 4.14.0-rc5+ #97
> >>> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
> >>> Google 01/01/2011
> >>> Call Trace:
> >>> __dump_stack lib/dump_stack.c:16 [inline]
> >>> dump_stack+0x194/0x257 lib/dump_stack.c:52
> >>> print_address_description+0x73/0x250 mm/kasan/report.c:252
> >>> kasan_report_error mm/kasan/report.c:351 [inline]
> >>> kasan_report+0x25b/0x340 mm/kasan/report.c:409
> >>> __asan_report_load2_noabort+0x14/0x20 mm/kasan/report.c:428
> >>> ipv6_get_dsfield include/net/dsfield.h:23 [inline]
> >>> ipip6_tunnel_xmit net/ipv6/sit.c:968 [inline]
> >>> sit_tunnel_xmit+0x2a41/0x3130 net/ipv6/sit.c:1016
> >>> __netdev_start_xmit include/linux/netdevice.h:4022 [inline]
> >>> netdev_start_xmit include/linux/netdevice.h:4031 [inline]
> >>> xmit_one net/core/dev.c:3008 [inline]
> >>> dev_hard_start_xmit+0x248/0xac0 net/core/dev.c:3024
> >>> __dev_queue_xmit+0x17d2/0x2070 net/core/dev.c:3505
> >>> dev_queue_xmit+0x17/0x20 net/core/dev.c:3538
> >>> neigh_direct_output+0x15/0x20 net/core/neighbour.c:1390
> >>> neigh_output include/net/neighbour.h:481 [inline]
> >>> ip6_finish_output2+0xad1/0x22a0 net/ipv6/ip6_output.c:120
> >>> ip6_fragment+0x25ae/0x3420 net/ipv6/ip6_output.c:723
> >>> ip6_finish_output+0x319/0x920 net/ipv6/ip6_output.c:144
> >>> NF_HOOK_COND include/linux/netfilter.h:238 [inline]
> >>> ip6_output+0x1f4/0x850 net/ipv6/ip6_output.c:163
> >>> dst_output include/net/dst.h:459 [inline]
> >>> ip6_local_out+0x95/0x160 net/ipv6/output_core.c:176
> >>> ip6_send_skb+0xa1/0x330 net/ipv6/ip6_output.c:1658
> >>> ip6_push_pending_frames+0xb3/0xe0 net/ipv6/ip6_output.c:1678
> >>> rawv6_push_pending_frames net/ipv6/raw.c:616 [inline]
> >>> rawv6_sendmsg+0x2eb9/0x3e40 net/ipv6/raw.c:935
> >>> inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:763
> >>> sock_sendmsg_nosec net/socket.c:633 [inline]
> >>> sock_sendmsg+0xca/0x110 net/socket.c:643
> >>> SYSC_sendto+0x352/0x5a0 net/socket.c:1750
> >>> SyS_sendto+0x40/0x50 net/socket.c:1718
> >>> entry_SYSCALL_64_fastpath+0x1f/0xbe
> >>> RIP: 0033:0x452869
> >>> RSP: 002b:00007fe3c12e5be8 EFLAGS: 00000212 ORIG_RAX: 000000000000002c
> >>> RAX: ffffffffffffffda RBX: 00000000007580d8 RCX: 0000000000452869
> >>> RDX: 00000000000007f1 RSI: 000000002013b7ff RDI: 0000000000000014
> >>> RBP: 0000000000000161 R08: 00000000204e8fe4 R09: 000000000000001c
> >>> R10: 0000000001000000 R11: 0000000000000212 R12: 00000000006f01b8
> >>> R13: 00000000ffffffff R14: 00007fe3c12e66d4 R15: 0000000000000017
> >>>
> >>> Allocated by task 16924:
> >>> save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
> >>> save_stack+0x43/0xd0 mm/kasan/kasan.c:447
> >>> set_track mm/kasan/kasan.c:459 [inline]
> >>> kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:551
> >>> __do_kmalloc_node mm/slab.c:3689 [inline]
> >>> __kmalloc_node_track_caller+0x47/0x70 mm/slab.c:3703
> >>> __kmalloc_reserve.isra.40+0x41/0xd0 net/core/skbuff.c:138
> >>> __alloc_skb+0x13b/0x780 net/core/skbuff.c:206
> >>> alloc_skb include/linux/skbuff.h:985 [inline]
> >>> sock_wmalloc+0x140/0x1d0 net/core/sock.c:1932
> >>> __ip6_append_data.isra.43+0x2681/0x3340 net/ipv6/ip6_output.c:1397
> >>> ip6_append_data+0x189/0x290 net/ipv6/ip6_output.c:1552
> >>> rawv6_sendmsg+0x1dd9/0x3e40 net/ipv6/raw.c:928
> >>> inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:763
> >>> sock_sendmsg_nosec net/socket.c:633 [inline]
> >>> sock_sendmsg+0xca/0x110 net/socket.c:643
> >>> SYSC_sendto+0x352/0x5a0 net/socket.c:1750
> >>> SyS_sendto+0x40/0x50 net/socket.c:1718
> >>> entry_SYSCALL_64_fastpath+0x1f/0xbe
> >>>
> >>> Freed by task 16942:
> >>> save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
> >>> save_stack+0x43/0xd0 mm/kasan/kasan.c:447
> >>> set_track mm/kasan/kasan.c:459 [inline]
> >>> kasan_slab_free+0x71/0xc0 mm/kasan/kasan.c:524
> >>> __cache_free mm/slab.c:3503 [inline]
> >>> kfree+0xca/0x250 mm/slab.c:3820
> >>> skb_free_head+0x74/0xb0 net/core/skbuff.c:554
> >>> pskb_expand_head+0x36b/0x1210 net/core/skbuff.c:1494
> >>> __pskb_pull_tail+0x14a/0x17c0 net/core/skbuff.c:1877
> >>> pskb_may_pull include/linux/skbuff.h:2102 [inline]
> >>> _decode_session6+0x8a4/0x1100 net/ipv6/xfrm6_policy.c:148
> >>
> >> Looks like we should indicate error by returning some int
> >> for afinfo->decode_session().
> >
> >
> > Cong, do you want to do something with this bug? Otherwise I want to
> > close this as part of old bug bankruptcy.
>
> I will work on a patch to address this.
>
> Thanks.
Hi Cong, have you sent a patch for this yet?
Thanks,
Eric
^ permalink raw reply
* Re: [PATCH bpf v3] x86/cpufeature: bpf hack for clang not supporting asm goto
From: Thomas Gleixner @ 2018-05-12 20:30 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Borislav Petkov, Peter Zijlstra, Yonghong Song, Ingo Molnar,
Linus Torvalds, Alexei Starovoitov, Daniel Borkmann, LKML, X86 ML,
Network Development, Kernel Team
In-Reply-To: <CAADnVQKVEmD4RrcTAiuMn-uua5TP0N-buvRHXq6Mgp1ZeF=G_Q@mail.gmail.com>
On Sat, 12 May 2018, Alexei Starovoitov wrote:
> On Thu, May 10, 2018 at 10:58 AM, Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> > I see no option, but to fix the kernel.
> > Regardless whether it's called user space breakage or kernel breakage.
There is a big difference. If you are abusing a kernel internal header in a
user space tool, then there is absolutely ZERO excuse for requesting that
the header in question has to be modified.
But yes, the situation is slightly different here because tools which
create trace event magic _HAVE_ to pull in kernel headers. At the same time
these tools depend on a compiler which failed to implement asm_goto for
fricking 8 years.
So while Boris is right, that nothing has to fiddle with a kernel only
header, I grumpily agree with you that we need a workaround in the kernel
for this particular issue.
> could you please ack the patch or better yet take it into tip tree
> and send to Linus asap ?
Nope. The patch is a horrible hack.
Why the heck do we need that extra fugly define? That has exactly zero
value simply because we already have a define which denotes availablity of
ASM GOTO: CC_HAVE_ASM_GOTO.
In case of samples/bpf/ and libbcc the compile does not go through the
arch/x86 Makefile which stops the build anyway when ASM_GOTO is
missing. Those builds merily pull in the headers and have their own build
magic, which is broken btw: Changing a kernel header which gets pulled into
the build does not rebuild anything in samples/bpf. Qualitee..
So we can just use CC_HAVE_ASM_GOTO and be done with it.
But we also want the tools which needs this to be aware of this. Peter
requested -D __BPF__ several times which got ignored. It's not too much of
a request to add that.
Find a patch which deos exactly this for samples/bpf, but also allows other
tools to build with a warning emitted so they get fixed.
Thanks,
tglx
8<----------------
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -140,6 +140,20 @@ extern void clear_cpu_cap(struct cpuinfo
#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
+#ifndef CC_HAVE_ASM_GOTO
+
+/*
+ * Workaround for the sake of BPF compilation which utilizes kernel
+ * headers, but clang does not support ASM GOTO and fails the build.
+ */
+#ifndef __BPF__
+#warning "Compiler lacks ASM_GOTO support. Add -D __BPF__ to your compiler arguments"
+#endif
+
+#define static_cpu_has(bit) boot_cpu_has(bit)
+
+#else
+
/*
* Static testing of CPU features. Used the same as boot_cpu_has().
* These will statically patch the target code for additional
@@ -195,6 +209,7 @@ static __always_inline __pure bool _stat
boot_cpu_has(bit) : \
_static_cpu_has(bit) \
)
+#endif
#define cpu_has_bug(c, bit) cpu_has(c, (bit))
#define set_cpu_bug(c, bit) set_cpu_cap(c, (bit))
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -255,7 +255,7 @@ verify_target_bpf: verify_cmds
$(obj)/%.o: $(src)/%.c
$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) -I$(obj) \
-I$(srctree)/tools/testing/selftests/bpf/ \
- -D__KERNEL__ -Wno-unused-value -Wno-pointer-sign \
+ -D__KERNEL__ -D__BPF__ -Wno-unused-value -Wno-pointer-sign \
-D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
-Wno-address-of-packed-member -Wno-tautological-compare \
^ permalink raw reply
* Re: [PATCH v6 1/6] net: phy: at803x: Export at803x_debug_reg_mask()
From: Andrew Lunn @ 2018-05-12 21:37 UTC (permalink / raw)
To: Paul Burton; +Cc: Darren Hart, netdev, linux-mips, David S . Miller
In-Reply-To: <20180511222239.aznt4ngtnrbnvshf@pburton-laptop>
On Fri, May 11, 2018 at 03:22:39PM -0700, Paul Burton wrote:
> Hi Andrew,
>
> On Fri, May 11, 2018 at 09:24:46PM +0200, Andrew Lunn wrote:
> > > I could reorder the probe function a little to initialize the PHY before
> > > performing the MAC reset, drop this patch and the AR803X hibernation
> > > stuff from patch 2 if you like. But again, I can't actually test the
> > > result on the affected hardware.
> >
> > Hi Paul
> >
> > I don't like a MAC driver poking around in PHY registers.
> >
> > So if you can rearrange the code, that would be great.
> >
> > Thanks
> > Andrew
>
> Sure, I'll give it a shot.
>
> After digging into it I see 2 ways to go here:
>
> 1) We could just always reset the PHY before we reset the MAC. That
> would give us a window of however long the PHY takes to enter its
> low power state & stop providing the RX clock during which we'd
> need the MAC reset to complete. In the case of the AR8031 that's
> "about 10 seconds" according to its data sheet. In this particular
> case that feels like plenty, but it does also feel a bit icky to
> rely on the timing chosen by the PHY manufacturer to line up with
> that of the MAC reset.
>
> 2) We could introduce a couple of new phy_* functions to disable &
> enable low power states like the AR8031's hibernation feature, by
> calling new function pointers in struct phy_driver. Then pch_gbe &
> other MACs could call those to have the PHY driver disable
> hibernation at times where we know we'll need the RX clock and
> re-enable it afterwards.
Hi Paul
When there is no link, you don't need the MAC running. My assumption
is that the PHY is designed around that idea, you leave the MAC idle
until there is a link. When the phylib calls the link_change handler,
the MAC should then be started/stopped depending on the state of the
link. You are then guaranteed to have the clock when you need it.
I've no idea how easy this is to implement given the current code...
Andrew
^ permalink raw reply
* [PATCH net-next v2 0/8] sctp: refactor sctp_outq_flush
From: Marcelo Ricardo Leitner @ 2018-05-12 22:20 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
Currently sctp_outq_flush does many different things and arguably
unrelated, such as doing transport selection and outq dequeueing.
This patchset refactors it into smaller and more dedicated functions.
The end behavior should be the same.
The next patchset will rework the function parameters.
Changes since v1:
- fix build issues on patches 3 and 4, and updated 5 and 8 because of
it.
Marcelo Ricardo Leitner (8):
sctp: add sctp_packet_singleton
sctp: factor out sctp_outq_select_transport
sctp: move the flush of ctrl chunks into its own function
sctp: move outq data rtx code out of sctp_outq_flush
sctp: move flushing of data chunks out of sctp_outq_flush
sctp: move transport flush code out of sctp_outq_flush
sctp: make use of gfp on retransmissions
sctp: rework switch cases in sctp_outq_flush_data
net/sctp/outqueue.c | 593 +++++++++++++++++++++++++++-------------------------
1 file changed, 311 insertions(+), 282 deletions(-)
^ permalink raw reply
* [PATCH net-next v2 1/8] sctp: add sctp_packet_singleton
From: Marcelo Ricardo Leitner @ 2018-05-12 22:20 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
Factor out the code for generating singletons. It's used only once, but
helps to keep the context contained.
The const variables are to ease the reading of subsequent calls in there.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index dee7cbd5483149024f2f3195db2fe4d473b1a00a..300bd0dfc7c14c9df579dbe2f9e78dd8356ae1a3 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -776,6 +776,20 @@ void sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp)
sctp_outq_flush(q, 0, gfp);
}
+static int sctp_packet_singleton(struct sctp_transport *transport,
+ struct sctp_chunk *chunk, gfp_t gfp)
+{
+ const struct sctp_association *asoc = transport->asoc;
+ const __u16 sport = asoc->base.bind_addr.port;
+ const __u16 dport = asoc->peer.port;
+ const __u32 vtag = asoc->peer.i.init_tag;
+ struct sctp_packet singleton;
+
+ sctp_packet_init(&singleton, transport, sport, dport);
+ sctp_packet_config(&singleton, vtag, 0);
+ sctp_packet_append_chunk(&singleton, chunk);
+ return sctp_packet_transmit(&singleton, gfp);
+}
/*
* Try to flush an outqueue.
@@ -789,10 +803,7 @@ void sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp)
static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
{
struct sctp_packet *packet;
- struct sctp_packet singleton;
struct sctp_association *asoc = q->asoc;
- __u16 sport = asoc->base.bind_addr.port;
- __u16 dport = asoc->peer.port;
__u32 vtag = asoc->peer.i.init_tag;
struct sctp_transport *transport = NULL;
struct sctp_transport *new_transport;
@@ -905,10 +916,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
case SCTP_CID_SHUTDOWN_COMPLETE:
- sctp_packet_init(&singleton, transport, sport, dport);
- sctp_packet_config(&singleton, vtag, 0);
- sctp_packet_append_chunk(&singleton, chunk);
- error = sctp_packet_transmit(&singleton, gfp);
+ error = sctp_packet_singleton(transport, chunk, gfp);
if (error < 0) {
asoc->base.sk->sk_err = -error;
return;
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 2/8] sctp: factor out sctp_outq_select_transport
From: Marcelo Ricardo Leitner @ 2018-05-12 22:20 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
We had two spots doing such complex operation and they were very close to
each other, a bit more tailored to here or there.
This patch unifies these under the same function,
sctp_outq_select_transport, which knows how to handle control chunks and
original transmissions (but not retransmissions).
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 187 +++++++++++++++++++++++++---------------------------
1 file changed, 90 insertions(+), 97 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 300bd0dfc7c14c9df579dbe2f9e78dd8356ae1a3..bda50596d4bfebeac03966c5a161473df1c1986a 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -791,6 +791,90 @@ static int sctp_packet_singleton(struct sctp_transport *transport,
return sctp_packet_transmit(&singleton, gfp);
}
+static bool sctp_outq_select_transport(struct sctp_chunk *chunk,
+ struct sctp_association *asoc,
+ struct sctp_transport **transport,
+ struct list_head *transport_list)
+{
+ struct sctp_transport *new_transport = chunk->transport;
+ struct sctp_transport *curr = *transport;
+ bool changed = false;
+
+ if (!new_transport) {
+ if (!sctp_chunk_is_data(chunk)) {
+ /*
+ * If we have a prior transport pointer, see if
+ * the destination address of the chunk
+ * matches the destination address of the
+ * current transport. If not a match, then
+ * try to look up the transport with a given
+ * destination address. We do this because
+ * after processing ASCONFs, we may have new
+ * transports created.
+ */
+ if (curr && sctp_cmp_addr_exact(&chunk->dest,
+ &curr->ipaddr))
+ new_transport = curr;
+ else
+ new_transport = sctp_assoc_lookup_paddr(asoc,
+ &chunk->dest);
+ }
+
+ /* if we still don't have a new transport, then
+ * use the current active path.
+ */
+ if (!new_transport)
+ new_transport = asoc->peer.active_path;
+ } else {
+ __u8 type;
+
+ switch (new_transport->state) {
+ case SCTP_INACTIVE:
+ case SCTP_UNCONFIRMED:
+ case SCTP_PF:
+ /* If the chunk is Heartbeat or Heartbeat Ack,
+ * send it to chunk->transport, even if it's
+ * inactive.
+ *
+ * 3.3.6 Heartbeat Acknowledgement:
+ * ...
+ * A HEARTBEAT ACK is always sent to the source IP
+ * address of the IP datagram containing the
+ * HEARTBEAT chunk to which this ack is responding.
+ * ...
+ *
+ * ASCONF_ACKs also must be sent to the source.
+ */
+ type = chunk->chunk_hdr->type;
+ if (type != SCTP_CID_HEARTBEAT &&
+ type != SCTP_CID_HEARTBEAT_ACK &&
+ type != SCTP_CID_ASCONF_ACK)
+ new_transport = asoc->peer.active_path;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Are we switching transports? Take care of transport locks. */
+ if (new_transport != curr) {
+ changed = true;
+ curr = new_transport;
+ *transport = curr;
+ if (list_empty(&curr->send_ready))
+ list_add_tail(&curr->send_ready, transport_list);
+
+ sctp_packet_config(&curr->packet, asoc->peer.i.init_tag,
+ asoc->peer.ecn_capable);
+ /* We've switched transports, so apply the
+ * Burst limit to the new transport.
+ */
+ sctp_transport_burst_limited(curr);
+ }
+
+ return changed;
+}
+
/*
* Try to flush an outqueue.
*
@@ -806,7 +890,6 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
struct sctp_association *asoc = q->asoc;
__u32 vtag = asoc->peer.i.init_tag;
struct sctp_transport *transport = NULL;
- struct sctp_transport *new_transport;
struct sctp_chunk *chunk, *tmp;
enum sctp_xmit status;
int error = 0;
@@ -843,68 +926,12 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
list_del_init(&chunk->list);
- /* Pick the right transport to use. */
- new_transport = chunk->transport;
-
- if (!new_transport) {
- /*
- * If we have a prior transport pointer, see if
- * the destination address of the chunk
- * matches the destination address of the
- * current transport. If not a match, then
- * try to look up the transport with a given
- * destination address. We do this because
- * after processing ASCONFs, we may have new
- * transports created.
- */
- if (transport &&
- sctp_cmp_addr_exact(&chunk->dest,
- &transport->ipaddr))
- new_transport = transport;
- else
- new_transport = sctp_assoc_lookup_paddr(asoc,
- &chunk->dest);
-
- /* if we still don't have a new transport, then
- * use the current active path.
- */
- if (!new_transport)
- new_transport = asoc->peer.active_path;
- } else if ((new_transport->state == SCTP_INACTIVE) ||
- (new_transport->state == SCTP_UNCONFIRMED) ||
- (new_transport->state == SCTP_PF)) {
- /* If the chunk is Heartbeat or Heartbeat Ack,
- * send it to chunk->transport, even if it's
- * inactive.
- *
- * 3.3.6 Heartbeat Acknowledgement:
- * ...
- * A HEARTBEAT ACK is always sent to the source IP
- * address of the IP datagram containing the
- * HEARTBEAT chunk to which this ack is responding.
- * ...
- *
- * ASCONF_ACKs also must be sent to the source.
- */
- if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT &&
- chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK &&
- chunk->chunk_hdr->type != SCTP_CID_ASCONF_ACK)
- new_transport = asoc->peer.active_path;
- }
-
- /* Are we switching transports?
- * Take care of transport locks.
+ /* Pick the right transport to use. Should always be true for
+ * the first chunk as we don't have a transport by then.
*/
- if (new_transport != transport) {
- transport = new_transport;
- if (list_empty(&transport->send_ready)) {
- list_add_tail(&transport->send_ready,
- &transport_list);
- }
+ if (sctp_outq_select_transport(chunk, asoc, &transport,
+ &transport_list))
packet = &transport->packet;
- sctp_packet_config(packet, vtag,
- asoc->peer.ecn_capable);
- }
switch (chunk->chunk_hdr->type) {
/*
@@ -1072,43 +1099,9 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
goto sctp_flush_out;
}
- /* If there is a specified transport, use it.
- * Otherwise, we want to use the active path.
- */
- new_transport = chunk->transport;
- if (!new_transport ||
- ((new_transport->state == SCTP_INACTIVE) ||
- (new_transport->state == SCTP_UNCONFIRMED) ||
- (new_transport->state == SCTP_PF)))
- new_transport = asoc->peer.active_path;
- if (new_transport->state == SCTP_UNCONFIRMED) {
- WARN_ONCE(1, "Attempt to send packet on unconfirmed path.");
- sctp_sched_dequeue_done(q, chunk);
- sctp_chunk_fail(chunk, 0);
- sctp_chunk_free(chunk);
- continue;
- }
-
- /* Change packets if necessary. */
- if (new_transport != transport) {
- transport = new_transport;
-
- /* Schedule to have this transport's
- * packet flushed.
- */
- if (list_empty(&transport->send_ready)) {
- list_add_tail(&transport->send_ready,
- &transport_list);
- }
-
+ if (sctp_outq_select_transport(chunk, asoc, &transport,
+ &transport_list))
packet = &transport->packet;
- sctp_packet_config(packet, vtag,
- asoc->peer.ecn_capable);
- /* We've switched transports, so apply the
- * Burst limit to the new transport.
- */
- sctp_transport_burst_limited(transport);
- }
pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
"skb->users:%d\n",
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 3/8] sctp: move the flush of ctrl chunks into its own function
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
Named sctp_outq_flush_ctrl and, with that, keep the contexts contained.
One small fix embedded is the reset of one_packet at every iteration.
This allows bundling of some control chunks in case they were preceded by
another control chunk that cannot be bundled.
Other than this, it has the same behavior.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 89 ++++++++++++++++++++++++++++++++---------------------
1 file changed, 54 insertions(+), 35 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index bda50596d4bfebeac03966c5a161473df1c1986a..800202c68cb89f1086ee7d3a4493dc752c8bf6ac 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -875,45 +875,21 @@ static bool sctp_outq_select_transport(struct sctp_chunk *chunk,
return changed;
}
-/*
- * Try to flush an outqueue.
- *
- * Description: Send everything in q which we legally can, subject to
- * congestion limitations.
- * * Note: This function can be called from multiple contexts so appropriate
- * locking concerns must be made. Today we use the sock lock to protect
- * this function.
- */
-static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
+static void sctp_outq_flush_ctrl(struct sctp_outq *q,
+ struct sctp_transport **_transport,
+ struct list_head *transport_list,
+ gfp_t gfp)
{
- struct sctp_packet *packet;
+ struct sctp_transport *transport = *_transport;
struct sctp_association *asoc = q->asoc;
- __u32 vtag = asoc->peer.i.init_tag;
- struct sctp_transport *transport = NULL;
+ struct sctp_packet *packet = NULL;
struct sctp_chunk *chunk, *tmp;
enum sctp_xmit status;
- int error = 0;
- int start_timer = 0;
- int one_packet = 0;
-
- /* These transports have chunks to send. */
- struct list_head transport_list;
- struct list_head *ltransport;
-
- INIT_LIST_HEAD(&transport_list);
- packet = NULL;
-
- /*
- * 6.10 Bundling
- * ...
- * When bundling control chunks with DATA chunks, an
- * endpoint MUST place control chunks first in the outbound
- * SCTP packet. The transmitter MUST transmit DATA chunks
- * within a SCTP packet in increasing order of TSN.
- * ...
- */
+ int one_packet, error;
list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+ one_packet = 0;
+
/* RFC 5061, 5.3
* F1) This means that until such time as the ASCONF
* containing the add is acknowledged, the sender MUST
@@ -930,8 +906,10 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* the first chunk as we don't have a transport by then.
*/
if (sctp_outq_select_transport(chunk, asoc, &transport,
- &transport_list))
+ transport_list)) {
+ transport = *_transport;
packet = &transport->packet;
+ }
switch (chunk->chunk_hdr->type) {
/*
@@ -954,6 +932,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
if (sctp_test_T_bit(chunk))
packet->vtag = asoc->c.my_vtag;
/* fallthru */
+
/* The following chunks are "response" chunks, i.e.
* they are generated in response to something we
* received. If we are sending these, then we can
@@ -979,7 +958,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
case SCTP_CID_RECONF:
status = sctp_packet_transmit_chunk(packet, chunk,
one_packet, gfp);
- if (status != SCTP_XMIT_OK) {
+ if (status != SCTP_XMIT_OK) {
/* put the chunk back */
list_add(&chunk->list, &q->control_chunk_list);
break;
@@ -1006,6 +985,46 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
BUG();
}
}
+}
+
+/*
+ * Try to flush an outqueue.
+ *
+ * Description: Send everything in q which we legally can, subject to
+ * congestion limitations.
+ * * Note: This function can be called from multiple contexts so appropriate
+ * locking concerns must be made. Today we use the sock lock to protect
+ * this function.
+ */
+static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
+{
+ struct sctp_packet *packet;
+ struct sctp_association *asoc = q->asoc;
+ __u32 vtag = asoc->peer.i.init_tag;
+ struct sctp_transport *transport = NULL;
+ struct sctp_chunk *chunk;
+ enum sctp_xmit status;
+ int error = 0;
+ int start_timer = 0;
+
+ /* These transports have chunks to send. */
+ struct list_head transport_list;
+ struct list_head *ltransport;
+
+ INIT_LIST_HEAD(&transport_list);
+ packet = NULL;
+
+ /*
+ * 6.10 Bundling
+ * ...
+ * When bundling control chunks with DATA chunks, an
+ * endpoint MUST place control chunks first in the outbound
+ * SCTP packet. The transmitter MUST transmit DATA chunks
+ * within a SCTP packet in increasing order of TSN.
+ * ...
+ */
+
+ sctp_outq_flush_ctrl(q, &transport, &transport_list, gfp);
if (q->asoc->src_out_of_asoc_ok)
goto sctp_flush_out;
^ permalink raw reply related
* [PATCH net-next v2 4/8] sctp: move outq data rtx code out of sctp_outq_flush
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
This patch renames current sctp_outq_flush_rtx to __sctp_outq_flush_rtx
and create a new sctp_outq_flush_rtx, with the code that was on
sctp_outq_flush. Again, the idea is to have functions with small and
defined objectives.
Yes, there is an open-coded path selection in the now sctp_outq_flush_rtx.
That is kept as is for now because it may be very different when we
implement retransmission path selection algorithms for CMT-SCTP.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 101 ++++++++++++++++++++++++++++++----------------------
1 file changed, 58 insertions(+), 43 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 800202c68cb89f1086ee7d3a4493dc752c8bf6ac..6d7ee372a9d6b8e68a759277830d5334ec992d47 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -601,14 +601,14 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
/*
* Transmit DATA chunks on the retransmit queue. Upon return from
- * sctp_outq_flush_rtx() the packet 'pkt' may contain chunks which
+ * __sctp_outq_flush_rtx() the packet 'pkt' may contain chunks which
* need to be transmitted by the caller.
* We assume that pkt->transport has already been set.
*
* The return value is a normal kernel error return value.
*/
-static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
- int rtx_timeout, int *start_timer)
+static int __sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
+ int rtx_timeout, int *start_timer)
{
struct sctp_transport *transport = pkt->transport;
struct sctp_chunk *chunk, *chunk1;
@@ -987,6 +987,57 @@ static void sctp_outq_flush_ctrl(struct sctp_outq *q,
}
}
+/* Returns false if new data shouldn't be sent */
+static bool sctp_outq_flush_rtx(struct sctp_outq *q,
+ struct sctp_transport **_transport,
+ struct list_head *transport_list,
+ int rtx_timeout)
+{
+ struct sctp_transport *transport = *_transport;
+ struct sctp_packet *packet = transport ? &transport->packet : NULL;
+ struct sctp_association *asoc = q->asoc;
+ int error, start_timer = 0;
+
+ if (asoc->peer.retran_path->state == SCTP_UNCONFIRMED)
+ return false;
+
+ if (transport != asoc->peer.retran_path) {
+ /* Switch transports & prepare the packet. */
+ transport = asoc->peer.retran_path;
+ *_transport = transport;
+
+ if (list_empty(&transport->send_ready))
+ list_add_tail(&transport->send_ready,
+ transport_list);
+
+ packet = &transport->packet;
+ sctp_packet_config(packet, asoc->peer.i.init_tag,
+ asoc->peer.ecn_capable);
+ }
+
+ error = __sctp_outq_flush_rtx(q, packet, rtx_timeout, &start_timer);
+ if (error < 0)
+ asoc->base.sk->sk_err = -error;
+
+ if (start_timer) {
+ sctp_transport_reset_t3_rtx(transport);
+ transport->last_time_sent = jiffies;
+ }
+
+ /* This can happen on COOKIE-ECHO resend. Only
+ * one chunk can get bundled with a COOKIE-ECHO.
+ */
+ if (packet->has_cookie_echo)
+ return false;
+
+ /* Don't send new data if there is still data
+ * waiting to retransmit.
+ */
+ if (!list_empty(&q->retransmit))
+ return false;
+
+ return true;
+}
/*
* Try to flush an outqueue.
*
@@ -1000,12 +1051,10 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
{
struct sctp_packet *packet;
struct sctp_association *asoc = q->asoc;
- __u32 vtag = asoc->peer.i.init_tag;
struct sctp_transport *transport = NULL;
struct sctp_chunk *chunk;
enum sctp_xmit status;
int error = 0;
- int start_timer = 0;
/* These transports have chunks to send. */
struct list_head transport_list;
@@ -1052,45 +1101,11 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* current cwnd).
*/
if (!list_empty(&q->retransmit)) {
- if (asoc->peer.retran_path->state == SCTP_UNCONFIRMED)
- goto sctp_flush_out;
- if (transport == asoc->peer.retran_path)
- goto retran;
-
- /* Switch transports & prepare the packet. */
-
- transport = asoc->peer.retran_path;
-
- if (list_empty(&transport->send_ready)) {
- list_add_tail(&transport->send_ready,
- &transport_list);
- }
-
+ if (!sctp_outq_flush_rtx(q, &transport, &transport_list,
+ rtx_timeout))
+ break;
+ /* We may have switched current transport */
packet = &transport->packet;
- sctp_packet_config(packet, vtag,
- asoc->peer.ecn_capable);
- retran:
- error = sctp_outq_flush_rtx(q, packet,
- rtx_timeout, &start_timer);
- if (error < 0)
- asoc->base.sk->sk_err = -error;
-
- if (start_timer) {
- sctp_transport_reset_t3_rtx(transport);
- transport->last_time_sent = jiffies;
- }
-
- /* This can happen on COOKIE-ECHO resend. Only
- * one chunk can get bundled with a COOKIE-ECHO.
- */
- if (packet->has_cookie_echo)
- goto sctp_flush_out;
-
- /* Don't send new data if there is still data
- * waiting to retransmit.
- */
- if (!list_empty(&q->retransmit))
- goto sctp_flush_out;
}
/* Apply Max.Burst limitation to the current transport in
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 5/8] sctp: move flushing of data chunks out of sctp_outq_flush
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
To the new sctp_outq_flush_data. Again, smaller functions and with well
defined objectives.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 148 ++++++++++++++++++++++++++--------------------------
1 file changed, 75 insertions(+), 73 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 6d7ee372a9d6b8e68a759277830d5334ec992d47..7522188107792643f3bb5f00e5c254b00e91ef12 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -1038,45 +1038,17 @@ static bool sctp_outq_flush_rtx(struct sctp_outq *q,
return true;
}
-/*
- * Try to flush an outqueue.
- *
- * Description: Send everything in q which we legally can, subject to
- * congestion limitations.
- * * Note: This function can be called from multiple contexts so appropriate
- * locking concerns must be made. Today we use the sock lock to protect
- * this function.
- */
-static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
+
+static void sctp_outq_flush_data(struct sctp_outq *q,
+ struct sctp_transport **_transport,
+ struct list_head *transport_list,
+ int rtx_timeout, gfp_t gfp)
{
- struct sctp_packet *packet;
+ struct sctp_transport *transport = *_transport;
+ struct sctp_packet *packet = transport ? &transport->packet : NULL;
struct sctp_association *asoc = q->asoc;
- struct sctp_transport *transport = NULL;
struct sctp_chunk *chunk;
enum sctp_xmit status;
- int error = 0;
-
- /* These transports have chunks to send. */
- struct list_head transport_list;
- struct list_head *ltransport;
-
- INIT_LIST_HEAD(&transport_list);
- packet = NULL;
-
- /*
- * 6.10 Bundling
- * ...
- * When bundling control chunks with DATA chunks, an
- * endpoint MUST place control chunks first in the outbound
- * SCTP packet. The transmitter MUST transmit DATA chunks
- * within a SCTP packet in increasing order of TSN.
- * ...
- */
-
- sctp_outq_flush_ctrl(q, &transport, &transport_list, gfp);
-
- if (q->asoc->src_out_of_asoc_ok)
- goto sctp_flush_out;
/* Is it OK to send data chunks? */
switch (asoc->state) {
@@ -1101,10 +1073,11 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* current cwnd).
*/
if (!list_empty(&q->retransmit)) {
- if (!sctp_outq_flush_rtx(q, &transport, &transport_list,
+ if (!sctp_outq_flush_rtx(q, _transport, transport_list,
rtx_timeout))
break;
/* We may have switched current transport */
+ transport = *_transport;
packet = &transport->packet;
}
@@ -1130,12 +1103,14 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
sctp_outq_head_data(q, chunk);
- goto sctp_flush_out;
+ break;
}
- if (sctp_outq_select_transport(chunk, asoc, &transport,
- &transport_list))
+ if (sctp_outq_select_transport(chunk, asoc, _transport,
+ transport_list)) {
+ transport = *_transport;
packet = &transport->packet;
+ }
pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
"skb->users:%d\n",
@@ -1147,8 +1122,10 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
/* Add the chunk to the packet. */
status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
-
switch (status) {
+ case SCTP_XMIT_OK:
+ break;
+
case SCTP_XMIT_PMTU_FULL:
case SCTP_XMIT_RWND_FULL:
case SCTP_XMIT_DELAY:
@@ -1160,41 +1137,25 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
status);
sctp_outq_head_data(q, chunk);
- goto sctp_flush_out;
-
- case SCTP_XMIT_OK:
- /* The sender is in the SHUTDOWN-PENDING state,
- * The sender MAY set the I-bit in the DATA
- * chunk header.
- */
- if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
- chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM;
- if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
- asoc->stats.ouodchunks++;
- else
- asoc->stats.oodchunks++;
-
- /* Only now it's safe to consider this
- * chunk as sent, sched-wise.
- */
- sctp_sched_dequeue_done(q, chunk);
-
- break;
-
- default:
- BUG();
+ return;
}
- /* BUG: We assume that the sctp_packet_transmit()
- * call below will succeed all the time and add the
- * chunk to the transmitted list and restart the
- * timers.
- * It is possible that the call can fail under OOM
- * conditions.
- *
- * Is this really a problem? Won't this behave
- * like a lost TSN?
+ /* The sender is in the SHUTDOWN-PENDING state,
+ * The sender MAY set the I-bit in the DATA
+ * chunk header.
*/
+ if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
+ chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM;
+ if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+ asoc->stats.ouodchunks++;
+ else
+ asoc->stats.oodchunks++;
+
+ /* Only now it's safe to consider this
+ * chunk as sent, sched-wise.
+ */
+ sctp_sched_dequeue_done(q, chunk);
+
list_add_tail(&chunk->transmitted_list,
&transport->transmitted);
@@ -1205,7 +1166,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* COOKIE-ECHO chunk.
*/
if (packet->has_cookie_echo)
- goto sctp_flush_out;
+ break;
}
break;
@@ -1213,6 +1174,47 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
/* Do nothing. */
break;
}
+}
+
+/*
+ * Try to flush an outqueue.
+ *
+ * Description: Send everything in q which we legally can, subject to
+ * congestion limitations.
+ * * Note: This function can be called from multiple contexts so appropriate
+ * locking concerns must be made. Today we use the sock lock to protect
+ * this function.
+ */
+static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
+{
+ struct sctp_packet *packet;
+ struct sctp_association *asoc = q->asoc;
+ struct sctp_transport *transport = NULL;
+ int error = 0;
+
+ /* These transports have chunks to send. */
+ struct list_head transport_list;
+ struct list_head *ltransport;
+
+ INIT_LIST_HEAD(&transport_list);
+ packet = NULL;
+
+ /*
+ * 6.10 Bundling
+ * ...
+ * When bundling control chunks with DATA chunks, an
+ * endpoint MUST place control chunks first in the outbound
+ * SCTP packet. The transmitter MUST transmit DATA chunks
+ * within a SCTP packet in increasing order of TSN.
+ * ...
+ */
+
+ sctp_outq_flush_ctrl(q, &transport, &transport_list, gfp);
+
+ if (q->asoc->src_out_of_asoc_ok)
+ goto sctp_flush_out;
+
+ sctp_outq_flush_data(q, &transport, &transport_list, rtx_timeout, gfp);
sctp_flush_out:
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 6/8] sctp: move transport flush code out of sctp_outq_flush
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
To the new sctp_outq_flush_transports.
Comment on Nagle is outdated and removed. Nagle is performed earlier, while
checking if the chunk fits the packet: if the outq length is not enough to
fill the packet, it returns SCTP_XMIT_DELAY.
So by when it gets to sctp_outq_flush_transports, it has to go through all
enlisted transports.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 56 +++++++++++++++++++++++++----------------------------
1 file changed, 26 insertions(+), 30 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 7522188107792643f3bb5f00e5c254b00e91ef12..3b738fdb08b9c596e6d4d4b18bef645187e0da4a 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -1176,6 +1176,29 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
}
}
+static void sctp_outq_flush_transports(struct sctp_outq *q,
+ struct list_head *transport_list,
+ gfp_t gfp)
+{
+ struct list_head *ltransport;
+ struct sctp_packet *packet;
+ struct sctp_transport *t;
+ int error = 0;
+
+ while ((ltransport = sctp_list_dequeue(transport_list)) != NULL) {
+ t = list_entry(ltransport, struct sctp_transport, send_ready);
+ packet = &t->packet;
+ if (!sctp_packet_empty(packet)) {
+ error = sctp_packet_transmit(packet, gfp);
+ if (error < 0)
+ q->asoc->base.sk->sk_err = -error;
+ }
+
+ /* Clear the burst limited state, if any */
+ sctp_transport_burst_reset(t);
+ }
+}
+
/*
* Try to flush an outqueue.
*
@@ -1187,17 +1210,10 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
*/
static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
{
- struct sctp_packet *packet;
- struct sctp_association *asoc = q->asoc;
+ /* Current transport being used. It's NOT the same as curr active one */
struct sctp_transport *transport = NULL;
- int error = 0;
-
/* These transports have chunks to send. */
- struct list_head transport_list;
- struct list_head *ltransport;
-
- INIT_LIST_HEAD(&transport_list);
- packet = NULL;
+ LIST_HEAD(transport_list);
/*
* 6.10 Bundling
@@ -1218,27 +1234,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
sctp_flush_out:
- /* Before returning, examine all the transports touched in
- * this call. Right now, we bluntly force clear all the
- * transports. Things might change after we implement Nagle.
- * But such an examination is still required.
- *
- * --xguo
- */
- while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL) {
- struct sctp_transport *t = list_entry(ltransport,
- struct sctp_transport,
- send_ready);
- packet = &t->packet;
- if (!sctp_packet_empty(packet)) {
- error = sctp_packet_transmit(packet, gfp);
- if (error < 0)
- asoc->base.sk->sk_err = -error;
- }
-
- /* Clear the burst limited state, if any */
- sctp_transport_burst_reset(t);
- }
+ sctp_outq_flush_transports(q, &transport_list, gfp);
}
/* Update unack_data based on the incoming SACK chunk */
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 7/8] sctp: make use of gfp on retransmissions
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
Retransmissions may be triggered when in user context, so lets make use
of gfp.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 3b738fdb08b9c596e6d4d4b18bef645187e0da4a..8173dd26f5878cbf67dd7e162ac5e6b18d9a3332 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -608,7 +608,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
* The return value is a normal kernel error return value.
*/
static int __sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
- int rtx_timeout, int *start_timer)
+ int rtx_timeout, int *start_timer, gfp_t gfp)
{
struct sctp_transport *transport = pkt->transport;
struct sctp_chunk *chunk, *chunk1;
@@ -684,12 +684,12 @@ static int __sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* control chunks are already freed so there
* is nothing we can do.
*/
- sctp_packet_transmit(pkt, GFP_ATOMIC);
+ sctp_packet_transmit(pkt, gfp);
goto redo;
}
/* Send this packet. */
- error = sctp_packet_transmit(pkt, GFP_ATOMIC);
+ error = sctp_packet_transmit(pkt, gfp);
/* If we are retransmitting, we should only
* send a single packet.
@@ -705,7 +705,7 @@ static int __sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
case SCTP_XMIT_RWND_FULL:
/* Send this packet. */
- error = sctp_packet_transmit(pkt, GFP_ATOMIC);
+ error = sctp_packet_transmit(pkt, gfp);
/* Stop sending DATA as there is no more room
* at the receiver.
@@ -715,7 +715,7 @@ static int __sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
case SCTP_XMIT_DELAY:
/* Send this packet. */
- error = sctp_packet_transmit(pkt, GFP_ATOMIC);
+ error = sctp_packet_transmit(pkt, gfp);
/* Stop sending DATA because of nagle delay. */
done = 1;
@@ -991,7 +991,7 @@ static void sctp_outq_flush_ctrl(struct sctp_outq *q,
static bool sctp_outq_flush_rtx(struct sctp_outq *q,
struct sctp_transport **_transport,
struct list_head *transport_list,
- int rtx_timeout)
+ int rtx_timeout, gfp_t gfp)
{
struct sctp_transport *transport = *_transport;
struct sctp_packet *packet = transport ? &transport->packet : NULL;
@@ -1015,7 +1015,8 @@ static bool sctp_outq_flush_rtx(struct sctp_outq *q,
asoc->peer.ecn_capable);
}
- error = __sctp_outq_flush_rtx(q, packet, rtx_timeout, &start_timer);
+ error = __sctp_outq_flush_rtx(q, packet, rtx_timeout, &start_timer,
+ gfp);
if (error < 0)
asoc->base.sk->sk_err = -error;
@@ -1074,7 +1075,7 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
*/
if (!list_empty(&q->retransmit)) {
if (!sctp_outq_flush_rtx(q, _transport, transport_list,
- rtx_timeout))
+ rtx_timeout, gfp))
break;
/* We may have switched current transport */
transport = *_transport;
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 8/8] sctp: rework switch cases in sctp_outq_flush_data
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142784.git.marcelo.leitner@gmail.com>
Remove an inner one, which tended to be error prone due to the cascading
and it can be replaced by a simple if ().
Rework the outer one so that the actual flush code is not inside it. Now
we first validate if we can or cannot send data, return if not, and then
the flush code.
Suggested-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 191 +++++++++++++++++++++++++---------------------------
1 file changed, 93 insertions(+), 98 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 8173dd26f5878cbf67dd7e162ac5e6b18d9a3332..a9400cb0cc249affcf2bedfc7a070d9e48843d27 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -1058,122 +1058,117 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
* chunk.
*/
if (!packet || !packet->has_cookie_echo)
- break;
+ return;
/* fallthru */
case SCTP_STATE_ESTABLISHED:
case SCTP_STATE_SHUTDOWN_PENDING:
case SCTP_STATE_SHUTDOWN_RECEIVED:
- /*
- * RFC 2960 6.1 Transmission of DATA Chunks
- *
- * C) When the time comes for the sender to transmit,
- * before sending new DATA chunks, the sender MUST
- * first transmit any outstanding DATA chunks which
- * are marked for retransmission (limited by the
- * current cwnd).
- */
- if (!list_empty(&q->retransmit)) {
- if (!sctp_outq_flush_rtx(q, _transport, transport_list,
- rtx_timeout, gfp))
- break;
- /* We may have switched current transport */
- transport = *_transport;
- packet = &transport->packet;
- }
+ break;
- /* Apply Max.Burst limitation to the current transport in
- * case it will be used for new data. We are going to
- * rest it before we return, but we want to apply the limit
- * to the currently queued data.
- */
- if (transport)
- sctp_transport_burst_limited(transport);
-
- /* Finally, transmit new packets. */
- while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
- __u32 sid = ntohs(chunk->subh.data_hdr->stream);
-
- /* Has this chunk expired? */
- if (sctp_chunk_abandoned(chunk)) {
- sctp_sched_dequeue_done(q, chunk);
- sctp_chunk_fail(chunk, 0);
- sctp_chunk_free(chunk);
- continue;
- }
+ default:
+ /* Do nothing. */
+ return;
+ }
- if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
- sctp_outq_head_data(q, chunk);
- break;
- }
+ /*
+ * RFC 2960 6.1 Transmission of DATA Chunks
+ *
+ * C) When the time comes for the sender to transmit,
+ * before sending new DATA chunks, the sender MUST
+ * first transmit any outstanding DATA chunks which
+ * are marked for retransmission (limited by the
+ * current cwnd).
+ */
+ if (!list_empty(&q->retransmit)) {
+ if (!sctp_outq_flush_rtx(q, _transport, transport_list,
+ rtx_timeout, gfp))
+ return;
+ /* We may have switched current transport */
+ transport = *_transport;
+ packet = &transport->packet;
+ }
- if (sctp_outq_select_transport(chunk, asoc, _transport,
- transport_list)) {
- transport = *_transport;
- packet = &transport->packet;
- }
+ /* Apply Max.Burst limitation to the current transport in
+ * case it will be used for new data. We are going to
+ * rest it before we return, but we want to apply the limit
+ * to the currently queued data.
+ */
+ if (transport)
+ sctp_transport_burst_limited(transport);
- pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
- "skb->users:%d\n",
- __func__, q, chunk, chunk && chunk->chunk_hdr ?
- sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
- "illegal chunk", ntohl(chunk->subh.data_hdr->tsn),
- chunk->skb ? chunk->skb->head : NULL, chunk->skb ?
- refcount_read(&chunk->skb->users) : -1);
-
- /* Add the chunk to the packet. */
- status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
- switch (status) {
- case SCTP_XMIT_OK:
- break;
+ /* Finally, transmit new packets. */
+ while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
+ __u32 sid = ntohs(chunk->subh.data_hdr->stream);
- case SCTP_XMIT_PMTU_FULL:
- case SCTP_XMIT_RWND_FULL:
- case SCTP_XMIT_DELAY:
- /* We could not append this chunk, so put
- * the chunk back on the output queue.
- */
- pr_debug("%s: could not transmit tsn:0x%x, status:%d\n",
- __func__, ntohl(chunk->subh.data_hdr->tsn),
- status);
+ /* Has this chunk expired? */
+ if (sctp_chunk_abandoned(chunk)) {
+ sctp_sched_dequeue_done(q, chunk);
+ sctp_chunk_fail(chunk, 0);
+ sctp_chunk_free(chunk);
+ continue;
+ }
- sctp_outq_head_data(q, chunk);
- return;
- }
+ if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
+ sctp_outq_head_data(q, chunk);
+ break;
+ }
- /* The sender is in the SHUTDOWN-PENDING state,
- * The sender MAY set the I-bit in the DATA
- * chunk header.
- */
- if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
- chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM;
- if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
- asoc->stats.ouodchunks++;
- else
- asoc->stats.oodchunks++;
+ if (sctp_outq_select_transport(chunk, asoc, _transport,
+ transport_list)) {
+ transport = *_transport;
+ packet = &transport->packet;
+ }
- /* Only now it's safe to consider this
- * chunk as sent, sched-wise.
+ pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
+ "skb->users:%d\n",
+ __func__, q, chunk, chunk && chunk->chunk_hdr ?
+ sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
+ "illegal chunk", ntohl(chunk->subh.data_hdr->tsn),
+ chunk->skb ? chunk->skb->head : NULL, chunk->skb ?
+ refcount_read(&chunk->skb->users) : -1);
+
+ /* Add the chunk to the packet. */
+ status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
+ if (status != SCTP_XMIT_OK) {
+ /* We could not append this chunk, so put
+ * the chunk back on the output queue.
*/
- sctp_sched_dequeue_done(q, chunk);
+ pr_debug("%s: could not transmit tsn:0x%x, status:%d\n",
+ __func__, ntohl(chunk->subh.data_hdr->tsn),
+ status);
+
+ sctp_outq_head_data(q, chunk);
+ break;
+ }
- list_add_tail(&chunk->transmitted_list,
- &transport->transmitted);
+ /* The sender is in the SHUTDOWN-PENDING state,
+ * The sender MAY set the I-bit in the DATA
+ * chunk header.
+ */
+ if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
+ chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM;
+ if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+ asoc->stats.ouodchunks++;
+ else
+ asoc->stats.oodchunks++;
- sctp_transport_reset_t3_rtx(transport);
- transport->last_time_sent = jiffies;
+ /* Only now it's safe to consider this
+ * chunk as sent, sched-wise.
+ */
+ sctp_sched_dequeue_done(q, chunk);
- /* Only let one DATA chunk get bundled with a
- * COOKIE-ECHO chunk.
- */
- if (packet->has_cookie_echo)
- break;
- }
- break;
+ list_add_tail(&chunk->transmitted_list,
+ &transport->transmitted);
- default:
- /* Do nothing. */
- break;
+ sctp_transport_reset_t3_rtx(transport);
+ transport->last_time_sent = jiffies;
+
+ /* Only let one DATA chunk get bundled with a
+ * COOKIE-ECHO chunk.
+ */
+ if (packet->has_cookie_echo)
+ break;
}
}
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 0/3] sctp: Introduce sctp_flush_ctx
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
This struct will hold all the context used during the outq flush, so we
don't have to pass lots of pointers all around.
Checked on x86_64, the compiler inlines all these functions and there is no
derreference added because of the struct.
This patchset depends on 'sctp: refactor sctp_outq_flush'
Changes since v1:
- updated to build on top of v2 of 'sctp: refactor sctp_outq_flush'
Marcelo Ricardo Leitner (3):
sctp: add sctp_flush_ctx, a context struct on outq_flush routines
sctp: add asoc and packet to sctp_flush_ctx
sctp: checkpatch fixups
net/sctp/outqueue.c | 259 ++++++++++++++++++++++++----------------------------
1 file changed, 119 insertions(+), 140 deletions(-)
^ permalink raw reply
* [PATCH net-next v2 1/3] sctp: add sctp_flush_ctx, a context struct on outq_flush routines
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142994.git.marcelo.leitner@gmail.com>
With this struct we avoid passing lots of variables around and taking care
of updating the current transport/packet.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 182 +++++++++++++++++++++++++---------------------------
1 file changed, 88 insertions(+), 94 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index a9400cb0cc249affcf2bedfc7a070d9e48843d27..db94a2513dd874149aa77c4936f68537e97f8855 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -791,13 +791,22 @@ static int sctp_packet_singleton(struct sctp_transport *transport,
return sctp_packet_transmit(&singleton, gfp);
}
-static bool sctp_outq_select_transport(struct sctp_chunk *chunk,
- struct sctp_association *asoc,
- struct sctp_transport **transport,
- struct list_head *transport_list)
+/* Struct to hold the context during sctp outq flush */
+struct sctp_flush_ctx {
+ struct sctp_outq *q;
+ /* Current transport being used. It's NOT the same as curr active one */
+ struct sctp_transport *transport;
+ /* These transports have chunks to send. */
+ struct list_head transport_list;
+ gfp_t gfp;
+};
+
+/* transport: current transport */
+static bool sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
+ struct sctp_chunk *chunk)
{
struct sctp_transport *new_transport = chunk->transport;
- struct sctp_transport *curr = *transport;
+ struct sctp_association *asoc = ctx->q->asoc;
bool changed = false;
if (!new_transport) {
@@ -812,9 +821,9 @@ static bool sctp_outq_select_transport(struct sctp_chunk *chunk,
* after processing ASCONFs, we may have new
* transports created.
*/
- if (curr && sctp_cmp_addr_exact(&chunk->dest,
- &curr->ipaddr))
- new_transport = curr;
+ if (ctx->transport && sctp_cmp_addr_exact(&chunk->dest,
+ &ctx->transport->ipaddr))
+ new_transport = ctx->transport;
else
new_transport = sctp_assoc_lookup_paddr(asoc,
&chunk->dest);
@@ -857,37 +866,33 @@ static bool sctp_outq_select_transport(struct sctp_chunk *chunk,
}
/* Are we switching transports? Take care of transport locks. */
- if (new_transport != curr) {
+ if (new_transport != ctx->transport) {
changed = true;
- curr = new_transport;
- *transport = curr;
- if (list_empty(&curr->send_ready))
- list_add_tail(&curr->send_ready, transport_list);
+ ctx->transport = new_transport;
+ if (list_empty(&ctx->transport->send_ready))
+ list_add_tail(&ctx->transport->send_ready,
+ &ctx->transport_list);
- sctp_packet_config(&curr->packet, asoc->peer.i.init_tag,
+ sctp_packet_config(&ctx->transport->packet, asoc->peer.i.init_tag,
asoc->peer.ecn_capable);
/* We've switched transports, so apply the
* Burst limit to the new transport.
*/
- sctp_transport_burst_limited(curr);
+ sctp_transport_burst_limited(ctx->transport);
}
return changed;
}
-static void sctp_outq_flush_ctrl(struct sctp_outq *q,
- struct sctp_transport **_transport,
- struct list_head *transport_list,
- gfp_t gfp)
+static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
{
- struct sctp_transport *transport = *_transport;
- struct sctp_association *asoc = q->asoc;
+ struct sctp_association *asoc = ctx->q->asoc;
struct sctp_packet *packet = NULL;
struct sctp_chunk *chunk, *tmp;
enum sctp_xmit status;
int one_packet, error;
- list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+ list_for_each_entry_safe(chunk, tmp, &ctx->q->control_chunk_list, list) {
one_packet = 0;
/* RFC 5061, 5.3
@@ -905,11 +910,8 @@ static void sctp_outq_flush_ctrl(struct sctp_outq *q,
/* Pick the right transport to use. Should always be true for
* the first chunk as we don't have a transport by then.
*/
- if (sctp_outq_select_transport(chunk, asoc, &transport,
- transport_list)) {
- transport = *_transport;
- packet = &transport->packet;
- }
+ if (sctp_outq_select_transport(ctx, chunk))
+ packet = &ctx->transport->packet;
switch (chunk->chunk_hdr->type) {
/*
@@ -921,7 +923,8 @@ static void sctp_outq_flush_ctrl(struct sctp_outq *q,
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
case SCTP_CID_SHUTDOWN_COMPLETE:
- error = sctp_packet_singleton(transport, chunk, gfp);
+ error = sctp_packet_singleton(ctx->transport, chunk,
+ ctx->gfp);
if (error < 0) {
asoc->base.sk->sk_err = -error;
return;
@@ -957,10 +960,10 @@ static void sctp_outq_flush_ctrl(struct sctp_outq *q,
case SCTP_CID_I_FWD_TSN:
case SCTP_CID_RECONF:
status = sctp_packet_transmit_chunk(packet, chunk,
- one_packet, gfp);
+ one_packet, ctx->gfp);
if (status != SCTP_XMIT_OK) {
/* put the chunk back */
- list_add(&chunk->list, &q->control_chunk_list);
+ list_add(&chunk->list, &ctx->q->control_chunk_list);
break;
}
@@ -971,12 +974,12 @@ static void sctp_outq_flush_ctrl(struct sctp_outq *q,
*/
if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN ||
chunk->chunk_hdr->type == SCTP_CID_I_FWD_TSN) {
- sctp_transport_reset_t3_rtx(transport);
- transport->last_time_sent = jiffies;
+ sctp_transport_reset_t3_rtx(ctx->transport);
+ ctx->transport->last_time_sent = jiffies;
}
if (chunk == asoc->strreset_chunk)
- sctp_transport_reset_reconf_timer(transport);
+ sctp_transport_reset_reconf_timer(ctx->transport);
break;
@@ -988,41 +991,38 @@ static void sctp_outq_flush_ctrl(struct sctp_outq *q,
}
/* Returns false if new data shouldn't be sent */
-static bool sctp_outq_flush_rtx(struct sctp_outq *q,
- struct sctp_transport **_transport,
- struct list_head *transport_list,
- int rtx_timeout, gfp_t gfp)
+static bool sctp_outq_flush_rtx(struct sctp_flush_ctx *ctx,
+ int rtx_timeout)
{
- struct sctp_transport *transport = *_transport;
- struct sctp_packet *packet = transport ? &transport->packet : NULL;
- struct sctp_association *asoc = q->asoc;
+ struct sctp_packet *packet = ctx->transport ? &ctx->transport->packet :
+ NULL;
+ struct sctp_association *asoc = ctx->q->asoc;
int error, start_timer = 0;
if (asoc->peer.retran_path->state == SCTP_UNCONFIRMED)
return false;
- if (transport != asoc->peer.retran_path) {
+ if (ctx->transport != asoc->peer.retran_path) {
/* Switch transports & prepare the packet. */
- transport = asoc->peer.retran_path;
- *_transport = transport;
+ ctx->transport = asoc->peer.retran_path;
- if (list_empty(&transport->send_ready))
- list_add_tail(&transport->send_ready,
- transport_list);
+ if (list_empty(&ctx->transport->send_ready))
+ list_add_tail(&ctx->transport->send_ready,
+ &ctx->transport_list);
- packet = &transport->packet;
+ packet = &ctx->transport->packet;
sctp_packet_config(packet, asoc->peer.i.init_tag,
asoc->peer.ecn_capable);
}
- error = __sctp_outq_flush_rtx(q, packet, rtx_timeout, &start_timer,
- gfp);
+ error = __sctp_outq_flush_rtx(ctx->q, packet, rtx_timeout, &start_timer,
+ ctx->gfp);
if (error < 0)
asoc->base.sk->sk_err = -error;
if (start_timer) {
- sctp_transport_reset_t3_rtx(transport);
- transport->last_time_sent = jiffies;
+ sctp_transport_reset_t3_rtx(ctx->transport);
+ ctx->transport->last_time_sent = jiffies;
}
/* This can happen on COOKIE-ECHO resend. Only
@@ -1034,20 +1034,18 @@ static bool sctp_outq_flush_rtx(struct sctp_outq *q,
/* Don't send new data if there is still data
* waiting to retransmit.
*/
- if (!list_empty(&q->retransmit))
+ if (!list_empty(&ctx->q->retransmit))
return false;
return true;
}
-static void sctp_outq_flush_data(struct sctp_outq *q,
- struct sctp_transport **_transport,
- struct list_head *transport_list,
- int rtx_timeout, gfp_t gfp)
+static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
+ int rtx_timeout)
{
- struct sctp_transport *transport = *_transport;
- struct sctp_packet *packet = transport ? &transport->packet : NULL;
- struct sctp_association *asoc = q->asoc;
+ struct sctp_packet *packet = ctx->transport ? &ctx->transport->packet :
+ NULL;
+ struct sctp_association *asoc = ctx->q->asoc;
struct sctp_chunk *chunk;
enum sctp_xmit status;
@@ -1080,13 +1078,11 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
* are marked for retransmission (limited by the
* current cwnd).
*/
- if (!list_empty(&q->retransmit)) {
- if (!sctp_outq_flush_rtx(q, _transport, transport_list,
- rtx_timeout, gfp))
+ if (!list_empty(&ctx->q->retransmit)) {
+ if (!sctp_outq_flush_rtx(ctx, rtx_timeout))
return;
/* We may have switched current transport */
- transport = *_transport;
- packet = &transport->packet;
+ packet = &ctx->transport->packet;
}
/* Apply Max.Burst limitation to the current transport in
@@ -1094,42 +1090,39 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
* rest it before we return, but we want to apply the limit
* to the currently queued data.
*/
- if (transport)
- sctp_transport_burst_limited(transport);
+ if (ctx->transport)
+ sctp_transport_burst_limited(ctx->transport);
/* Finally, transmit new packets. */
- while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
+ while ((chunk = sctp_outq_dequeue_data(ctx->q)) != NULL) {
__u32 sid = ntohs(chunk->subh.data_hdr->stream);
/* Has this chunk expired? */
if (sctp_chunk_abandoned(chunk)) {
- sctp_sched_dequeue_done(q, chunk);
+ sctp_sched_dequeue_done(ctx->q, chunk);
sctp_chunk_fail(chunk, 0);
sctp_chunk_free(chunk);
continue;
}
if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
- sctp_outq_head_data(q, chunk);
+ sctp_outq_head_data(ctx->q, chunk);
break;
}
- if (sctp_outq_select_transport(chunk, asoc, _transport,
- transport_list)) {
- transport = *_transport;
- packet = &transport->packet;
- }
+ if (sctp_outq_select_transport(ctx, chunk))
+ packet = &ctx->transport->packet;
pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
"skb->users:%d\n",
- __func__, q, chunk, chunk && chunk->chunk_hdr ?
+ __func__, ctx->q, chunk, chunk && chunk->chunk_hdr ?
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
"illegal chunk", ntohl(chunk->subh.data_hdr->tsn),
chunk->skb ? chunk->skb->head : NULL, chunk->skb ?
refcount_read(&chunk->skb->users) : -1);
/* Add the chunk to the packet. */
- status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
+ status = sctp_packet_transmit_chunk(packet, chunk, 0, ctx->gfp);
if (status != SCTP_XMIT_OK) {
/* We could not append this chunk, so put
* the chunk back on the output queue.
@@ -1138,7 +1131,7 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
__func__, ntohl(chunk->subh.data_hdr->tsn),
status);
- sctp_outq_head_data(q, chunk);
+ sctp_outq_head_data(ctx->q, chunk);
break;
}
@@ -1156,13 +1149,13 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
/* Only now it's safe to consider this
* chunk as sent, sched-wise.
*/
- sctp_sched_dequeue_done(q, chunk);
+ sctp_sched_dequeue_done(ctx->q, chunk);
list_add_tail(&chunk->transmitted_list,
- &transport->transmitted);
+ &ctx->transport->transmitted);
- sctp_transport_reset_t3_rtx(transport);
- transport->last_time_sent = jiffies;
+ sctp_transport_reset_t3_rtx(ctx->transport);
+ ctx->transport->last_time_sent = jiffies;
/* Only let one DATA chunk get bundled with a
* COOKIE-ECHO chunk.
@@ -1172,22 +1165,20 @@ static void sctp_outq_flush_data(struct sctp_outq *q,
}
}
-static void sctp_outq_flush_transports(struct sctp_outq *q,
- struct list_head *transport_list,
- gfp_t gfp)
+static void sctp_outq_flush_transports(struct sctp_flush_ctx *ctx)
{
struct list_head *ltransport;
struct sctp_packet *packet;
struct sctp_transport *t;
int error = 0;
- while ((ltransport = sctp_list_dequeue(transport_list)) != NULL) {
+ while ((ltransport = sctp_list_dequeue(&ctx->transport_list)) != NULL) {
t = list_entry(ltransport, struct sctp_transport, send_ready);
packet = &t->packet;
if (!sctp_packet_empty(packet)) {
- error = sctp_packet_transmit(packet, gfp);
+ error = sctp_packet_transmit(packet, ctx->gfp);
if (error < 0)
- q->asoc->base.sk->sk_err = -error;
+ ctx->q->asoc->base.sk->sk_err = -error;
}
/* Clear the burst limited state, if any */
@@ -1204,12 +1195,15 @@ static void sctp_outq_flush_transports(struct sctp_outq *q,
* locking concerns must be made. Today we use the sock lock to protect
* this function.
*/
+
static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
{
- /* Current transport being used. It's NOT the same as curr active one */
- struct sctp_transport *transport = NULL;
- /* These transports have chunks to send. */
- LIST_HEAD(transport_list);
+ struct sctp_flush_ctx ctx = {
+ .q = q,
+ .transport = NULL,
+ .transport_list = LIST_HEAD_INIT(ctx.transport_list),
+ .gfp = gfp,
+ };
/*
* 6.10 Bundling
@@ -1221,16 +1215,16 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* ...
*/
- sctp_outq_flush_ctrl(q, &transport, &transport_list, gfp);
+ sctp_outq_flush_ctrl(&ctx);
if (q->asoc->src_out_of_asoc_ok)
goto sctp_flush_out;
- sctp_outq_flush_data(q, &transport, &transport_list, rtx_timeout, gfp);
+ sctp_outq_flush_data(&ctx, rtx_timeout);
sctp_flush_out:
- sctp_outq_flush_transports(q, &transport_list, gfp);
+ sctp_outq_flush_transports(&ctx);
}
/* Update unack_data based on the incoming SACK chunk */
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 2/3] sctp: add asoc and packet to sctp_flush_ctx
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142994.git.marcelo.leitner@gmail.com>
Pre-compute these so the compiler won't reload them (due to
no-strict-aliasing).
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 99 ++++++++++++++++++++++++-----------------------------
1 file changed, 45 insertions(+), 54 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index db94a2513dd874149aa77c4936f68537e97f8855..a594d181fa1178c34cf477e13d700f7b37e72e21 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -798,16 +798,17 @@ struct sctp_flush_ctx {
struct sctp_transport *transport;
/* These transports have chunks to send. */
struct list_head transport_list;
+ struct sctp_association *asoc;
+ /* Packet on the current transport above */
+ struct sctp_packet *packet;
gfp_t gfp;
};
/* transport: current transport */
-static bool sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
+static void sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
struct sctp_chunk *chunk)
{
struct sctp_transport *new_transport = chunk->transport;
- struct sctp_association *asoc = ctx->q->asoc;
- bool changed = false;
if (!new_transport) {
if (!sctp_chunk_is_data(chunk)) {
@@ -825,7 +826,7 @@ static bool sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
&ctx->transport->ipaddr))
new_transport = ctx->transport;
else
- new_transport = sctp_assoc_lookup_paddr(asoc,
+ new_transport = sctp_assoc_lookup_paddr(ctx->asoc,
&chunk->dest);
}
@@ -833,7 +834,7 @@ static bool sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
* use the current active path.
*/
if (!new_transport)
- new_transport = asoc->peer.active_path;
+ new_transport = ctx->asoc->peer.active_path;
} else {
__u8 type;
@@ -858,7 +859,7 @@ static bool sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
if (type != SCTP_CID_HEARTBEAT &&
type != SCTP_CID_HEARTBEAT_ACK &&
type != SCTP_CID_ASCONF_ACK)
- new_transport = asoc->peer.active_path;
+ new_transport = ctx->asoc->peer.active_path;
break;
default:
break;
@@ -867,27 +868,25 @@ static bool sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
/* Are we switching transports? Take care of transport locks. */
if (new_transport != ctx->transport) {
- changed = true;
ctx->transport = new_transport;
+ ctx->packet = &ctx->transport->packet;
+
if (list_empty(&ctx->transport->send_ready))
list_add_tail(&ctx->transport->send_ready,
&ctx->transport_list);
- sctp_packet_config(&ctx->transport->packet, asoc->peer.i.init_tag,
- asoc->peer.ecn_capable);
+ sctp_packet_config(ctx->packet,
+ ctx->asoc->peer.i.init_tag,
+ ctx->asoc->peer.ecn_capable);
/* We've switched transports, so apply the
* Burst limit to the new transport.
*/
sctp_transport_burst_limited(ctx->transport);
}
-
- return changed;
}
static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
{
- struct sctp_association *asoc = ctx->q->asoc;
- struct sctp_packet *packet = NULL;
struct sctp_chunk *chunk, *tmp;
enum sctp_xmit status;
int one_packet, error;
@@ -901,7 +900,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
* NOT use the new IP address as a source for ANY SCTP
* packet except on carrying an ASCONF Chunk.
*/
- if (asoc->src_out_of_asoc_ok &&
+ if (ctx->asoc->src_out_of_asoc_ok &&
chunk->chunk_hdr->type != SCTP_CID_ASCONF)
continue;
@@ -910,8 +909,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
/* Pick the right transport to use. Should always be true for
* the first chunk as we don't have a transport by then.
*/
- if (sctp_outq_select_transport(ctx, chunk))
- packet = &ctx->transport->packet;
+ sctp_outq_select_transport(ctx, chunk);
switch (chunk->chunk_hdr->type) {
/*
@@ -926,14 +924,14 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
error = sctp_packet_singleton(ctx->transport, chunk,
ctx->gfp);
if (error < 0) {
- asoc->base.sk->sk_err = -error;
+ ctx->asoc->base.sk->sk_err = -error;
return;
}
break;
case SCTP_CID_ABORT:
if (sctp_test_T_bit(chunk))
- packet->vtag = asoc->c.my_vtag;
+ ctx->packet->vtag = ctx->asoc->c.my_vtag;
/* fallthru */
/* The following chunks are "response" chunks, i.e.
@@ -959,7 +957,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
case SCTP_CID_FWD_TSN:
case SCTP_CID_I_FWD_TSN:
case SCTP_CID_RECONF:
- status = sctp_packet_transmit_chunk(packet, chunk,
+ status = sctp_packet_transmit_chunk(ctx->packet, chunk,
one_packet, ctx->gfp);
if (status != SCTP_XMIT_OK) {
/* put the chunk back */
@@ -967,7 +965,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
break;
}
- asoc->stats.octrlchunks++;
+ ctx->asoc->stats.octrlchunks++;
/* PR-SCTP C5) If a FORWARD TSN is sent, the
* sender MUST assure that at least one T3-rtx
* timer is running.
@@ -978,7 +976,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
ctx->transport->last_time_sent = jiffies;
}
- if (chunk == asoc->strreset_chunk)
+ if (chunk == ctx->asoc->strreset_chunk)
sctp_transport_reset_reconf_timer(ctx->transport);
break;
@@ -994,31 +992,28 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
static bool sctp_outq_flush_rtx(struct sctp_flush_ctx *ctx,
int rtx_timeout)
{
- struct sctp_packet *packet = ctx->transport ? &ctx->transport->packet :
- NULL;
- struct sctp_association *asoc = ctx->q->asoc;
int error, start_timer = 0;
- if (asoc->peer.retran_path->state == SCTP_UNCONFIRMED)
+ if (ctx->asoc->peer.retran_path->state == SCTP_UNCONFIRMED)
return false;
- if (ctx->transport != asoc->peer.retran_path) {
+ if (ctx->transport != ctx->asoc->peer.retran_path) {
/* Switch transports & prepare the packet. */
- ctx->transport = asoc->peer.retran_path;
+ ctx->transport = ctx->asoc->peer.retran_path;
+ ctx->packet = &ctx->transport->packet;
if (list_empty(&ctx->transport->send_ready))
list_add_tail(&ctx->transport->send_ready,
&ctx->transport_list);
- packet = &ctx->transport->packet;
- sctp_packet_config(packet, asoc->peer.i.init_tag,
- asoc->peer.ecn_capable);
+ sctp_packet_config(ctx->packet, ctx->asoc->peer.i.init_tag,
+ ctx->asoc->peer.ecn_capable);
}
- error = __sctp_outq_flush_rtx(ctx->q, packet, rtx_timeout, &start_timer,
- ctx->gfp);
+ error = __sctp_outq_flush_rtx(ctx->q, ctx->packet, rtx_timeout,
+ &start_timer, ctx->gfp);
if (error < 0)
- asoc->base.sk->sk_err = -error;
+ ctx->asoc->base.sk->sk_err = -error;
if (start_timer) {
sctp_transport_reset_t3_rtx(ctx->transport);
@@ -1028,7 +1023,7 @@ static bool sctp_outq_flush_rtx(struct sctp_flush_ctx *ctx,
/* This can happen on COOKIE-ECHO resend. Only
* one chunk can get bundled with a COOKIE-ECHO.
*/
- if (packet->has_cookie_echo)
+ if (ctx->packet->has_cookie_echo)
return false;
/* Don't send new data if there is still data
@@ -1043,20 +1038,17 @@ static bool sctp_outq_flush_rtx(struct sctp_flush_ctx *ctx,
static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
int rtx_timeout)
{
- struct sctp_packet *packet = ctx->transport ? &ctx->transport->packet :
- NULL;
- struct sctp_association *asoc = ctx->q->asoc;
struct sctp_chunk *chunk;
enum sctp_xmit status;
/* Is it OK to send data chunks? */
- switch (asoc->state) {
+ switch (ctx->asoc->state) {
case SCTP_STATE_COOKIE_ECHOED:
/* Only allow bundling when this packet has a COOKIE-ECHO
* chunk.
*/
- if (!packet || !packet->has_cookie_echo)
- return;
+ if (!ctx->packet || !ctx->packet->has_cookie_echo)
+ break;
/* fallthru */
case SCTP_STATE_ESTABLISHED:
@@ -1078,12 +1070,9 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
* are marked for retransmission (limited by the
* current cwnd).
*/
- if (!list_empty(&ctx->q->retransmit)) {
- if (!sctp_outq_flush_rtx(ctx, rtx_timeout))
- return;
- /* We may have switched current transport */
- packet = &ctx->transport->packet;
- }
+ if (!list_empty(&ctx->q->retransmit) &&
+ !sctp_outq_flush_rtx(ctx, rtx_timeout))
+ return;
/* Apply Max.Burst limitation to the current transport in
* case it will be used for new data. We are going to
@@ -1105,13 +1094,12 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
continue;
}
- if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
+ if (ctx->asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
sctp_outq_head_data(ctx->q, chunk);
break;
}
- if (sctp_outq_select_transport(ctx, chunk))
- packet = &ctx->transport->packet;
+ sctp_outq_select_transport(ctx, chunk);
pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
"skb->users:%d\n",
@@ -1122,7 +1110,8 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
refcount_read(&chunk->skb->users) : -1);
/* Add the chunk to the packet. */
- status = sctp_packet_transmit_chunk(packet, chunk, 0, ctx->gfp);
+ status = sctp_packet_transmit_chunk(ctx->packet, chunk, 0,
+ ctx->gfp);
if (status != SCTP_XMIT_OK) {
/* We could not append this chunk, so put
* the chunk back on the output queue.
@@ -1139,12 +1128,12 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
* The sender MAY set the I-bit in the DATA
* chunk header.
*/
- if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
+ if (ctx->asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM;
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
- asoc->stats.ouodchunks++;
+ ctx->asoc->stats.ouodchunks++;
else
- asoc->stats.oodchunks++;
+ ctx->asoc->stats.oodchunks++;
/* Only now it's safe to consider this
* chunk as sent, sched-wise.
@@ -1160,7 +1149,7 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
/* Only let one DATA chunk get bundled with a
* COOKIE-ECHO chunk.
*/
- if (packet->has_cookie_echo)
+ if (ctx->packet->has_cookie_echo)
break;
}
}
@@ -1202,6 +1191,8 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
.q = q,
.transport = NULL,
.transport_list = LIST_HEAD_INIT(ctx.transport_list),
+ .asoc = q->asoc,
+ .packet = NULL,
.gfp = gfp,
};
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 3/3] sctp: checkpatch fixups
From: Marcelo Ricardo Leitner @ 2018-05-12 22:21 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Neil Horman, Vlad Yasevich, Xin Long
In-Reply-To: <cover.1526142994.git.marcelo.leitner@gmail.com>
A collection of fixups from previous patches, left for later to not
introduce unnecessary changes while moving code around.
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/outqueue.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index a594d181fa1178c34cf477e13d700f7b37e72e21..9a2fa7d6d68b1d695cd745ed612eb32193f947e0 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -812,8 +812,7 @@ static void sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
if (!new_transport) {
if (!sctp_chunk_is_data(chunk)) {
- /*
- * If we have a prior transport pointer, see if
+ /* If we have a prior transport pointer, see if
* the destination address of the chunk
* matches the destination address of the
* current transport. If not a match, then
@@ -912,8 +911,7 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
sctp_outq_select_transport(ctx, chunk);
switch (chunk->chunk_hdr->type) {
- /*
- * 6.10 Bundling
+ /* 6.10 Bundling
* ...
* An endpoint MUST NOT bundle INIT, INIT ACK or SHUTDOWN
* COMPLETE with any other chunks. [Send them immediately.]
@@ -1061,8 +1059,7 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
return;
}
- /*
- * RFC 2960 6.1 Transmission of DATA Chunks
+ /* RFC 2960 6.1 Transmission of DATA Chunks
*
* C) When the time comes for the sender to transmit,
* before sending new DATA chunks, the sender MUST
@@ -1101,8 +1098,7 @@ static void sctp_outq_flush_data(struct sctp_flush_ctx *ctx,
sctp_outq_select_transport(ctx, chunk);
- pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
- "skb->users:%d\n",
+ pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p skb->users:%d\n",
__func__, ctx->q, chunk, chunk && chunk->chunk_hdr ?
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
"illegal chunk", ntohl(chunk->subh.data_hdr->tsn),
@@ -1175,8 +1171,7 @@ static void sctp_outq_flush_transports(struct sctp_flush_ctx *ctx)
}
}
-/*
- * Try to flush an outqueue.
+/* Try to flush an outqueue.
*
* Description: Send everything in q which we legally can, subject to
* congestion limitations.
@@ -1196,8 +1191,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
.gfp = gfp,
};
- /*
- * 6.10 Bundling
+ /* 6.10 Bundling
* ...
* When bundling control chunks with DATA chunks, an
* endpoint MUST place control chunks first in the outbound
@@ -1768,7 +1762,7 @@ static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn)
if (TSN_lte(tsn, ctsn))
goto pass;
- /* 3.3.4 Selective Acknowledgement (SACK) (3):
+ /* 3.3.4 Selective Acknowledgment (SACK) (3):
*
* Gap Ack Blocks:
* These fields contain the Gap Ack Blocks. They are repeated
--
2.14.3
^ permalink raw reply related
* Re: [PATCH bpf] tools: bpf: fix NULL return handling in bpf__prepare_load
From: Daniel Borkmann @ 2018-05-12 23:20 UTC (permalink / raw)
To: YueHaibing, alexander.shishkin, mingo, peterz; +Cc: netdev, namhyung, acme
In-Reply-To: <20180511112142.23324-1-yuehaibing@huawei.com>
[ +Arnaldo ]
On 05/11/2018 01:21 PM, YueHaibing wrote:
> bpf_object__open()/bpf_object__open_buffer can return error pointer or NULL,
> check the return values with IS_ERR_OR_NULL() in bpf__prepare_load and
> bpf__prepare_load_buffer
>
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
> ---
> tools/perf/util/bpf-loader.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
This should probably be routed via Arnaldo due to the fix in perf itself. If
there's no particular preference on which tree, we could potentially route it
as well via bpf with Acked-by from Arnaldo, but that is up to him. Arnaldo,
any preference?
> diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
> index af7ad81..cee6587 100644
> --- a/tools/perf/util/bpf-loader.c
> +++ b/tools/perf/util/bpf-loader.c
> @@ -66,7 +66,7 @@ bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
> }
>
> obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name);
> - if (IS_ERR(obj)) {
> + if (IS_ERR_OR_NULL(obj)) {
> pr_debug("bpf: failed to load buffer\n");
> return ERR_PTR(-EINVAL);
> }
> @@ -102,14 +102,14 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
> pr_debug("bpf: successfull builtin compilation\n");
> obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
>
> - if (!IS_ERR(obj) && llvm_param.dump_obj)
> + if (!IS_ERR_OR_NULL(obj) && llvm_param.dump_obj)
> llvm__dump_obj(filename, obj_buf, obj_buf_sz);
>
> free(obj_buf);
> } else
> obj = bpf_object__open(filename);
>
> - if (IS_ERR(obj)) {
> + if (IS_ERR_OR_NULL(obj)) {
> pr_debug("bpf: failed to load %s\n", filename);
> return obj;
> }
>
^ permalink raw reply
* Re: [PATCH bpf-next 3/4] samples: bpf: fix build after move to compiling full libbpf.a
From: Daniel Borkmann @ 2018-05-12 23:22 UTC (permalink / raw)
To: Jakub Kicinski, alexei.starovoitov
Cc: oss-drivers, netdev, Björn Töpel
In-Reply-To: <20180512123757.7970f381@cakuba>
On 05/12/2018 09:38 PM, Jakub Kicinski wrote:
> On Fri, 11 May 2018 17:17:28 -0700, Jakub Kicinski wrote:
>> There are many ways users may compile samples, some of them got
>> broken by commit 5f9380572b4b ("samples: bpf: compile and link
>> against full libbpf"). Improve path resolution and make libbpf
>> building a dependency of source files to force its build.
>>
>> Samples should now again build with any of:
>> cd samples/bpf; make
>> make samples/bpf
>> make -C samples/bpf
>> cd samples/bpf; make O=builddir
>> make samples/bpf O=builddir
>> make -C samples/bpf O=builddir
>>
>> Fixes: 5f9380572b4b ("samples: bpf: compile and link against full libbpf")
>> Reported-by: Björn Töpel <bjorn.topel@gmail.com>
>> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
>
> Unfortunately Björn reports this still doesn't fix the build for him.
> Investigating further.
Ok, thanks for letting us know.
^ permalink raw reply
* [PATCH ghak81 RFC V2 0/5] audit: group task params
From: Richard Guy Briggs @ 2018-05-13 1:58 UTC (permalink / raw)
To: Linux-Audit Mailing List, LKML,
Linux NetDev Upstream Mailing List, Netfilter Devel List,
Linux Security Module list, Integrity Measurement Architecture,
SElinux list
Cc: Eric Paris, Paul Moore, Steve Grubb, Ingo Molnar, David Howells,
Richard Guy Briggs
Group the audit parameters for each task into one structure.
In particular, remove the loginuid and sessionid values and the audit
context pointer from the task structure, replacing them with an audit
task information structure to contain them. Use access functions to
access audit values.
Note: Use static allocation of the audit task information structure
initially. Dynamic allocation was considered and attempted, but isn't
ready yet. Static allocation has the limitation that future audit task
information structure changes would cause a visible change to the rest
of the kernel, whereas dynamic allocation would mostly hide any future
changes.
The first four access normalization patches could stand alone.
Passes audit-testsuite.
Changelog:
v2
- p2/5: add audit header to init/init_task.c to quiet kbuildbot
- audit_signal_info(): fetch loginuid once
- remove task_struct from audit_context() param list
- remove extra task_struct local vars
- do nothing on request to set audit context when audit is disabled
Richard Guy Briggs (5):
audit: normalize loginuid read access
audit: convert sessionid unset to a macro
audit: use inline function to get audit context
audit: use inline function to set audit context
audit: collect audit task parameters
MAINTAINERS | 2 +-
include/linux/audit.h | 28 ++++++++---
include/linux/audit_task.h | 31 ++++++++++++
include/linux/sched.h | 6 +--
include/net/xfrm.h | 4 +-
include/uapi/linux/audit.h | 1 +
init/init_task.c | 8 ++-
kernel/audit.c | 6 +--
kernel/audit_watch.c | 2 +-
kernel/auditsc.c | 97 +++++++++++++++++-------------------
kernel/fork.c | 2 +-
net/bridge/netfilter/ebtables.c | 2 +-
net/core/dev.c | 2 +-
net/netfilter/x_tables.c | 2 +-
net/netlabel/netlabel_user.c | 2 +-
security/integrity/ima/ima_api.c | 2 +-
security/integrity/integrity_audit.c | 2 +-
security/lsm_audit.c | 2 +-
security/selinux/hooks.c | 4 +-
security/selinux/selinuxfs.c | 6 +--
security/selinux/ss/services.c | 12 ++---
21 files changed, 133 insertions(+), 90 deletions(-)
create mode 100644 include/linux/audit_task.h
--
1.8.3.1
^ permalink raw reply
* [PATCH ghak81 RFC V2 1/5] audit: normalize loginuid read access
From: Richard Guy Briggs @ 2018-05-13 1:58 UTC (permalink / raw)
To: Linux-Audit Mailing List, LKML,
Linux NetDev Upstream Mailing List, Netfilter Devel List,
Linux Security Module list, Integrity Measurement Architecture,
SElinux list
Cc: Eric Paris, Paul Moore, Steve Grubb, Ingo Molnar, David Howells,
Richard Guy Briggs
In-Reply-To: <cover.1526173613.git.rgb@redhat.com>
Recognizing that the loginuid is an internal audit value, use an access
function to retrieve the audit loginuid value for the task rather than
reaching directly into the task struct to get it.
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
kernel/auditsc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 479c031..0d4e269 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -374,7 +374,7 @@ static int audit_field_compare(struct task_struct *tsk,
case AUDIT_COMPARE_EGID_TO_OBJ_GID:
return audit_compare_gid(cred->egid, name, f, ctx);
case AUDIT_COMPARE_AUID_TO_OBJ_UID:
- return audit_compare_uid(tsk->loginuid, name, f, ctx);
+ return audit_compare_uid(audit_get_loginuid(tsk), name, f, ctx);
case AUDIT_COMPARE_SUID_TO_OBJ_UID:
return audit_compare_uid(cred->suid, name, f, ctx);
case AUDIT_COMPARE_SGID_TO_OBJ_GID:
@@ -385,7 +385,7 @@ static int audit_field_compare(struct task_struct *tsk,
return audit_compare_gid(cred->fsgid, name, f, ctx);
/* uid comparisons */
case AUDIT_COMPARE_UID_TO_AUID:
- return audit_uid_comparator(cred->uid, f->op, tsk->loginuid);
+ return audit_uid_comparator(cred->uid, f->op, audit_get_loginuid(tsk));
case AUDIT_COMPARE_UID_TO_EUID:
return audit_uid_comparator(cred->uid, f->op, cred->euid);
case AUDIT_COMPARE_UID_TO_SUID:
@@ -394,11 +394,11 @@ static int audit_field_compare(struct task_struct *tsk,
return audit_uid_comparator(cred->uid, f->op, cred->fsuid);
/* auid comparisons */
case AUDIT_COMPARE_AUID_TO_EUID:
- return audit_uid_comparator(tsk->loginuid, f->op, cred->euid);
+ return audit_uid_comparator(audit_get_loginuid(tsk), f->op, cred->euid);
case AUDIT_COMPARE_AUID_TO_SUID:
- return audit_uid_comparator(tsk->loginuid, f->op, cred->suid);
+ return audit_uid_comparator(audit_get_loginuid(tsk), f->op, cred->suid);
case AUDIT_COMPARE_AUID_TO_FSUID:
- return audit_uid_comparator(tsk->loginuid, f->op, cred->fsuid);
+ return audit_uid_comparator(audit_get_loginuid(tsk), f->op, cred->fsuid);
/* euid comparisons */
case AUDIT_COMPARE_EUID_TO_SUID:
return audit_uid_comparator(cred->euid, f->op, cred->suid);
@@ -611,7 +611,7 @@ static int audit_filter_rules(struct task_struct *tsk,
result = match_tree_refs(ctx, rule->tree);
break;
case AUDIT_LOGINUID:
- result = audit_uid_comparator(tsk->loginuid, f->op, f->uid);
+ result = audit_uid_comparator(audit_get_loginuid(tsk), f->op, f->uid);
break;
case AUDIT_LOGINUID_SET:
result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val);
@@ -2281,14 +2281,14 @@ int audit_signal_info(int sig, struct task_struct *t)
struct audit_aux_data_pids *axp;
struct task_struct *tsk = current;
struct audit_context *ctx = tsk->audit_context;
- kuid_t uid = current_uid(), t_uid = task_uid(t);
+ kuid_t uid = current_uid(), auid, t_uid = task_uid(t);
if (auditd_test_task(t) &&
(sig == SIGTERM || sig == SIGHUP ||
sig == SIGUSR1 || sig == SIGUSR2)) {
audit_sig_pid = task_tgid_nr(tsk);
- if (uid_valid(tsk->loginuid))
- audit_sig_uid = tsk->loginuid;
+ if (uid_valid(auid = audit_get_loginuid(tsk)))
+ audit_sig_uid = auid;
else
audit_sig_uid = uid;
security_task_getsecid(tsk, &audit_sig_sid);
--
1.8.3.1
^ permalink raw reply related
* [PATCH ghak81 RFC V2 2/5] audit: convert sessionid unset to a macro
From: Richard Guy Briggs @ 2018-05-13 1:58 UTC (permalink / raw)
To: Linux-Audit Mailing List, LKML,
Linux NetDev Upstream Mailing List, Netfilter Devel List,
Linux Security Module list, Integrity Measurement Architecture,
SElinux list
Cc: Eric Paris, Paul Moore, Steve Grubb, Ingo Molnar, David Howells,
Richard Guy Briggs
In-Reply-To: <cover.1526173613.git.rgb@redhat.com>
Use a macro, "AUDIT_SID_UNSET", to replace each instance of
initialization and comparison to an audit session ID.
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
include/linux/audit.h | 2 +-
include/net/xfrm.h | 2 +-
include/uapi/linux/audit.h | 1 +
init/init_task.c | 3 ++-
kernel/auditsc.c | 4 ++--
5 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 75d5b03..5f86f7c 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -513,7 +513,7 @@ static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
}
static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
{
- return -1;
+ return AUDIT_SID_UNSET;
}
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{ }
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index a872379..fcce8ee 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -751,7 +751,7 @@ static inline void xfrm_audit_helper_usrinfo(bool task_valid,
audit_get_loginuid(current) :
INVALID_UID);
const unsigned int ses = task_valid ? audit_get_sessionid(current) :
- (unsigned int) -1;
+ AUDIT_SID_UNSET;
audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
audit_log_task_context(audit_buf);
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 4e61a9e..04f9bd2 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -465,6 +465,7 @@ struct audit_tty_status {
};
#define AUDIT_UID_UNSET (unsigned int)-1
+#define AUDIT_SID_UNSET ((unsigned int)-1)
/* audit_rule_data supports filter rules with both integer and string
* fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
diff --git a/init/init_task.c b/init/init_task.c
index 3ac6e75..74f60ba 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/audit.h>
#include <asm/pgtable.h>
#include <linux/uaccess.h>
@@ -119,7 +120,7 @@ struct task_struct init_task
.thread_node = LIST_HEAD_INIT(init_signals.thread_head),
#ifdef CONFIG_AUDITSYSCALL
.loginuid = INVALID_UID,
- .sessionid = (unsigned int)-1,
+ .sessionid = AUDIT_SID_UNSET,
#endif
#ifdef CONFIG_PERF_EVENTS
.perf_event_mutex = __MUTEX_INITIALIZER(init_task.perf_event_mutex),
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 0d4e269..e157595 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2050,7 +2050,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
int audit_set_loginuid(kuid_t loginuid)
{
struct task_struct *task = current;
- unsigned int oldsessionid, sessionid = (unsigned int)-1;
+ unsigned int oldsessionid, sessionid = AUDIT_SID_UNSET;
kuid_t oldloginuid;
int rc;
@@ -2064,7 +2064,7 @@ int audit_set_loginuid(kuid_t loginuid)
/* are we setting or clearing? */
if (uid_valid(loginuid)) {
sessionid = (unsigned int)atomic_inc_return(&session_id);
- if (unlikely(sessionid == (unsigned int)-1))
+ if (unlikely(sessionid == AUDIT_SID_UNSET))
sessionid = (unsigned int)atomic_inc_return(&session_id);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH ghak81 RFC V2 3/5] audit: use inline function to get audit context
From: Richard Guy Briggs @ 2018-05-13 1:58 UTC (permalink / raw)
To: Linux-Audit Mailing List, LKML,
Linux NetDev Upstream Mailing List, Netfilter Devel List,
Linux Security Module list, Integrity Measurement Architecture,
SElinux list
Cc: Richard Guy Briggs, David Howells, Ingo Molnar
In-Reply-To: <cover.1526173613.git.rgb@redhat.com>
Recognizing that the audit context is an internal audit value, use an
access function to retrieve the audit context pointer for the task
rather than reaching directly into the task struct to get it.
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
include/linux/audit.h | 14 ++++++--
include/net/xfrm.h | 2 +-
kernel/audit.c | 6 ++--
kernel/audit_watch.c | 2 +-
kernel/auditsc.c | 64 +++++++++++++++++-------------------
net/bridge/netfilter/ebtables.c | 2 +-
net/core/dev.c | 2 +-
net/netfilter/x_tables.c | 2 +-
net/netlabel/netlabel_user.c | 2 +-
security/integrity/ima/ima_api.c | 2 +-
security/integrity/integrity_audit.c | 2 +-
security/lsm_audit.c | 2 +-
security/selinux/hooks.c | 4 +--
security/selinux/selinuxfs.c | 6 ++--
security/selinux/ss/services.c | 12 +++----
15 files changed, 64 insertions(+), 60 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 5f86f7c..786aa8e 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -235,9 +235,13 @@ extern void __audit_inode_child(struct inode *parent,
extern void __audit_seccomp(unsigned long syscall, long signr, int code);
extern void __audit_ptrace(struct task_struct *t);
+static inline struct audit_context *audit_context(void)
+{
+ return current->audit_context;
+}
static inline bool audit_dummy_context(void)
{
- void *p = current->audit_context;
+ void *p = audit_context();
return !p || *(int *)p;
}
static inline void audit_free(struct task_struct *task)
@@ -249,12 +253,12 @@ static inline void audit_syscall_entry(int major, unsigned long a0,
unsigned long a1, unsigned long a2,
unsigned long a3)
{
- if (unlikely(current->audit_context))
+ if (unlikely(audit_context()))
__audit_syscall_entry(major, a0, a1, a2, a3);
}
static inline void audit_syscall_exit(void *pt_regs)
{
- if (unlikely(current->audit_context)) {
+ if (unlikely(audit_context())) {
int success = is_syscall_success(pt_regs);
long return_code = regs_return_value(pt_regs);
@@ -468,6 +472,10 @@ static inline bool audit_dummy_context(void)
{
return true;
}
+static inline struct audit_context *audit_context(void)
+{
+ return NULL;
+}
static inline struct filename *audit_reusename(const __user char *name)
{
return NULL;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index fcce8ee..7f2e31a 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -736,7 +736,7 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
if (audit_enabled == 0)
return NULL;
- audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC,
+ audit_buf = audit_log_start(audit_context(), GFP_ATOMIC,
AUDIT_MAC_IPSEC_EVENT);
if (audit_buf == NULL)
return NULL;
diff --git a/kernel/audit.c b/kernel/audit.c
index e9f9a90..e7478cb 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1099,8 +1099,7 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature
if (audit_enabled == AUDIT_OFF)
return;
- ab = audit_log_start(current->audit_context,
- GFP_KERNEL, AUDIT_FEATURE_CHANGE);
+ ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_FEATURE_CHANGE);
if (!ab)
return;
audit_log_task_info(ab, current);
@@ -2317,8 +2316,7 @@ void audit_log_link_denied(const char *operation)
return;
/* Generate AUDIT_ANOM_LINK with subject, operation, outcome. */
- ab = audit_log_start(current->audit_context, GFP_KERNEL,
- AUDIT_ANOM_LINK);
+ ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_ANOM_LINK);
if (!ab)
return;
audit_log_format(ab, "op=%s", operation);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 9eb8b35..f1ba889 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -274,7 +274,7 @@ static void audit_update_watch(struct audit_parent *parent,
/* If the update involves invalidating rules, do the inode-based
* filtering now, so we don't omit records. */
if (invalidating && !audit_dummy_context())
- audit_filter_inodes(current, current->audit_context);
+ audit_filter_inodes(current, audit_context());
/* updating ino will likely change which audit_hash_list we
* are on so we need a new watch for the new list */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e157595..ecc0c23 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1509,8 +1509,7 @@ void __audit_free(struct task_struct *tsk)
void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4)
{
- struct task_struct *tsk = current;
- struct audit_context *context = tsk->audit_context;
+ struct audit_context *context = audit_context();
enum audit_state state;
if (!audit_enabled || !context)
@@ -1525,7 +1524,7 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
context->dummy = !audit_n_rules;
if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
context->prio = 0;
- if (auditd_test_task(tsk))
+ if (auditd_test_task(current))
return;
}
@@ -1563,12 +1562,12 @@ void __audit_syscall_exit(int success, long return_code)
else
success = AUDITSC_FAILURE;
- context = audit_take_context(tsk, success, return_code);
+ context = audit_take_context(current, success, return_code);
if (!context)
return;
if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
- audit_log_exit(context, tsk);
+ audit_log_exit(context, current);
context->in_syscall = 0;
context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
@@ -1602,7 +1601,7 @@ static inline void handle_one(const struct inode *inode)
int count;
if (likely(!inode->i_fsnotify_marks))
return;
- context = current->audit_context;
+ context = audit_context();
p = context->trees;
count = context->tree_count;
rcu_read_lock();
@@ -1633,7 +1632,7 @@ static void handle_path(const struct dentry *dentry)
unsigned long seq;
int count;
- context = current->audit_context;
+ context = audit_context();
p = context->trees;
count = context->tree_count;
retry:
@@ -1715,7 +1714,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
struct filename *
__audit_reusename(const __user char *uptr)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
struct audit_names *n;
list_for_each_entry(n, &context->names_list, list) {
@@ -1738,7 +1737,7 @@ struct filename *
*/
void __audit_getname(struct filename *name)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
struct audit_names *n;
if (!context->in_syscall)
@@ -1766,7 +1765,7 @@ void __audit_getname(struct filename *name)
void __audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int flags)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
struct inode *inode = d_backing_inode(dentry);
struct audit_names *n;
bool parent = flags & AUDIT_INODE_PARENT;
@@ -1865,7 +1864,7 @@ void __audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
struct inode *inode = d_backing_inode(dentry);
const char *dname = dentry->d_name.name;
struct audit_names *n, *found_parent = NULL, *found_child = NULL;
@@ -2084,7 +2083,7 @@ int audit_set_loginuid(kuid_t loginuid)
*/
void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
if (attr)
memcpy(&context->mq_open.attr, attr, sizeof(struct mq_attr));
@@ -2108,7 +2107,7 @@ void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr)
void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
const struct timespec64 *abs_timeout)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
struct timespec64 *p = &context->mq_sendrecv.abs_timeout;
if (abs_timeout)
@@ -2132,7 +2131,7 @@ void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
if (notification)
context->mq_notify.sigev_signo = notification->sigev_signo;
@@ -2151,7 +2150,7 @@ void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification)
*/
void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->mq_getsetattr.mqdes = mqdes;
context->mq_getsetattr.mqstat = *mqstat;
context->type = AUDIT_MQ_GETSETATTR;
@@ -2164,7 +2163,7 @@ void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
*/
void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->ipc.uid = ipcp->uid;
context->ipc.gid = ipcp->gid;
context->ipc.mode = ipcp->mode;
@@ -2184,7 +2183,7 @@ void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
*/
void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->ipc.qbytes = qbytes;
context->ipc.perm_uid = uid;
@@ -2195,7 +2194,7 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mo
void __audit_bprm(struct linux_binprm *bprm)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->type = AUDIT_EXECVE;
context->execve.argc = bprm->argc;
@@ -2210,7 +2209,7 @@ void __audit_bprm(struct linux_binprm *bprm)
*/
int __audit_socketcall(int nargs, unsigned long *args)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
if (nargs <= 0 || nargs > AUDITSC_ARGS || !args)
return -EINVAL;
@@ -2228,7 +2227,7 @@ int __audit_socketcall(int nargs, unsigned long *args)
*/
void __audit_fd_pair(int fd1, int fd2)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->fds[0] = fd1;
context->fds[1] = fd2;
}
@@ -2242,7 +2241,7 @@ void __audit_fd_pair(int fd1, int fd2)
*/
int __audit_sockaddr(int len, void *a)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
if (!context->sockaddr) {
void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL);
@@ -2258,7 +2257,7 @@ int __audit_sockaddr(int len, void *a)
void __audit_ptrace(struct task_struct *t)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->target_pid = task_tgid_nr(t);
context->target_auid = audit_get_loginuid(t);
@@ -2279,19 +2278,18 @@ void __audit_ptrace(struct task_struct *t)
int audit_signal_info(int sig, struct task_struct *t)
{
struct audit_aux_data_pids *axp;
- struct task_struct *tsk = current;
- struct audit_context *ctx = tsk->audit_context;
+ struct audit_context *ctx = audit_context();
kuid_t uid = current_uid(), auid, t_uid = task_uid(t);
if (auditd_test_task(t) &&
(sig == SIGTERM || sig == SIGHUP ||
sig == SIGUSR1 || sig == SIGUSR2)) {
- audit_sig_pid = task_tgid_nr(tsk);
- if (uid_valid(auid = audit_get_loginuid(tsk)))
+ audit_sig_pid = task_tgid_nr(current);
+ if (uid_valid(auid = audit_get_loginuid(current)))
audit_sig_uid = auid;
else
audit_sig_uid = uid;
- security_task_getsecid(tsk, &audit_sig_sid);
+ security_task_getsecid(current, &audit_sig_sid);
}
if (!audit_signals || audit_dummy_context())
@@ -2347,7 +2345,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
const struct cred *new, const struct cred *old)
{
struct audit_aux_data_bprm_fcaps *ax;
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
struct cpu_vfs_cap_data vcaps;
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
@@ -2387,7 +2385,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
*/
void __audit_log_capset(const struct cred *new, const struct cred *old)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->capset.pid = task_tgid_nr(current);
context->capset.cap.effective = new->cap_effective;
context->capset.cap.inheritable = new->cap_effective;
@@ -2398,7 +2396,7 @@ void __audit_log_capset(const struct cred *new, const struct cred *old)
void __audit_mmap_fd(int fd, int flags)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->mmap.fd = fd;
context->mmap.flags = flags;
context->type = AUDIT_MMAP;
@@ -2406,7 +2404,7 @@ void __audit_mmap_fd(int fd, int flags)
void __audit_log_kern_module(char *name)
{
- struct audit_context *context = current->audit_context;
+ struct audit_context *context = audit_context();
context->module.name = kmalloc(strlen(name) + 1, GFP_KERNEL);
strcpy(context->module.name, name);
@@ -2415,7 +2413,7 @@ void __audit_log_kern_module(char *name)
void __audit_fanotify(unsigned int response)
{
- audit_log(current->audit_context, GFP_KERNEL,
+ audit_log(audit_context(), GFP_KERNEL,
AUDIT_FANOTIFY, "resp=%u", response);
}
@@ -2482,7 +2480,7 @@ void __audit_seccomp(unsigned long syscall, long signr, int code)
struct list_head *audit_killed_trees(void)
{
- struct audit_context *ctx = current->audit_context;
+ struct audit_context *ctx = audit_context();
if (likely(!ctx || !ctx->in_syscall))
return NULL;
return &ctx->killed_trees;
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 032e0fe..894c96a 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1062,7 +1062,7 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
#ifdef CONFIG_AUDIT
if (audit_enabled) {
- audit_log(current->audit_context, GFP_KERNEL,
+ audit_log(audit_context(), GFP_KERNEL,
AUDIT_NETFILTER_CFG,
"table=%s family=%u entries=%u",
repl->name, AF_BRIDGE, repl->nentries);
diff --git a/net/core/dev.c b/net/core/dev.c
index 969462e..5f38862 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6749,7 +6749,7 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify)
dev->flags & IFF_PROMISC ? "entered" : "left");
if (audit_enabled) {
current_uid_gid(&uid, &gid);
- audit_log(current->audit_context, GFP_ATOMIC,
+ audit_log(audit_context(), GFP_ATOMIC,
AUDIT_ANOM_PROMISCUOUS,
"dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
dev->name, (dev->flags & IFF_PROMISC),
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 71325fe..1540263 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1414,7 +1414,7 @@ struct xt_table_info *
#ifdef CONFIG_AUDIT
if (audit_enabled) {
- audit_log(current->audit_context, GFP_KERNEL,
+ audit_log(audit_context(), GFP_KERNEL,
AUDIT_NETFILTER_CFG,
"table=%s family=%u entries=%u",
table->name, table->af, private->number);
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 58495f4..2f328af 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -104,7 +104,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
if (audit_enabled == 0)
return NULL;
- audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, type);
+ audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, type);
if (audit_buf == NULL)
return NULL;
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index bf88236..a02c5ac 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -326,7 +326,7 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
hash[i * 2] = '\0';
- ab = audit_log_start(current->audit_context, GFP_KERNEL,
+ ab = audit_log_start(audit_context(), GFP_KERNEL,
AUDIT_INTEGRITY_RULE);
if (!ab)
goto out;
diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
index 90987d1..ab10a25 100644
--- a/security/integrity/integrity_audit.c
+++ b/security/integrity/integrity_audit.c
@@ -38,7 +38,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
if (!integrity_audit_info && audit_info == 1) /* Skip info messages */
return;
- ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
+ ab = audit_log_start(audit_context(), GFP_KERNEL, audit_msgno);
audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u",
task_pid_nr(current),
from_kuid(&init_user_ns, current_cred()->uid),
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 67703db..f840010 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -447,7 +447,7 @@ void common_lsm_audit(struct common_audit_data *a,
if (a == NULL)
return;
/* we use GFP_ATOMIC so we won't sleep */
- ab = audit_log_start(current->audit_context, GFP_ATOMIC | __GFP_NOWARN,
+ ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,
AUDIT_AVC);
if (ab == NULL)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4cafe6a..6dd582b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3294,7 +3294,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
} else {
audit_size = 0;
}
- ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
+ ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
audit_log_format(ab, "op=setxattr invalid_context=");
audit_log_n_untrustedstring(ab, value, audit_size);
audit_log_end(ab);
@@ -6431,7 +6431,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
audit_size = size - 1;
else
audit_size = size;
- ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
+ ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
audit_log_format(ab, "op=fscreate invalid_context=");
audit_log_n_untrustedstring(ab, value, audit_size);
audit_log_end(ab);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index efdc633..b4c51d1 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -167,7 +167,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
NULL);
if (length)
goto out;
- audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+ audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
"enforcing=%d old_enforcing=%d auid=%u ses=%u"
" enabled=%d old-enabled=%d lsm=selinux res=1",
new_value, old_value,
@@ -303,7 +303,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
length = selinux_disable(fsi->state);
if (length)
goto out;
- audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+ audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
"enforcing=%d old_enforcing=%d auid=%u ses=%u"
" enabled=%d old-enabled=%d lsm=selinux res=1",
enforcing, enforcing,
@@ -581,7 +581,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
length = count;
out1:
- audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
+ audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
"auid=%u ses=%u lsm=selinux res=1",
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 8057e19..0fd8ad9 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -501,7 +501,7 @@ static void security_dump_masked_av(struct policydb *policydb,
goto out;
/* audit a message */
- ab = audit_log_start(current->audit_context,
+ ab = audit_log_start(audit_context(),
GFP_ATOMIC, AUDIT_SELINUX_ERR);
if (!ab)
goto out;
@@ -743,7 +743,7 @@ static int security_validtrans_handle_fail(struct selinux_state *state,
goto out;
if (context_struct_to_string(p, tcontext, &t, &tlen))
goto out;
- audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+ audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_validate_transition seresult=denied"
" oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
@@ -929,7 +929,7 @@ int security_bounded_transition(struct selinux_state *state,
&old_name, &length) &&
!context_struct_to_string(policydb, new_context,
&new_name, &length)) {
- audit_log(current->audit_context,
+ audit_log(audit_context(),
GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_bounded_transition "
"seresult=denied "
@@ -1586,7 +1586,7 @@ static int compute_sid_handle_invalid_context(
goto out;
if (context_struct_to_string(policydb, newcontext, &n, &nlen))
goto out;
- audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+ audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_compute_sid invalid_context=%s"
" scontext=%s"
" tcontext=%s"
@@ -2882,7 +2882,7 @@ int security_set_bools(struct selinux_state *state, int len, int *values)
for (i = 0; i < len; i++) {
if (!!values[i] != policydb->bool_val_to_struct[i]->state) {
- audit_log(current->audit_context, GFP_ATOMIC,
+ audit_log(audit_context(), GFP_ATOMIC,
AUDIT_MAC_CONFIG_CHANGE,
"bool=%s val=%d old_val=%d auid=%u ses=%u",
sym_name(policydb, SYM_BOOLS, i),
@@ -3025,7 +3025,7 @@ int security_sid_mls_copy(struct selinux_state *state,
if (rc) {
if (!context_struct_to_string(policydb, &newcon, &s,
&len)) {
- audit_log(current->audit_context,
+ audit_log(audit_context(),
GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_sid_mls_copy "
"invalid_context=%s", s);
--
1.8.3.1
^ permalink raw reply related
* [PATCH ghak81 RFC V2 4/5] audit: use inline function to set audit context
From: Richard Guy Briggs @ 2018-05-13 1:58 UTC (permalink / raw)
To: Linux-Audit Mailing List, LKML,
Linux NetDev Upstream Mailing List, Netfilter Devel List,
Linux Security Module list, Integrity Measurement Architecture,
SElinux list
Cc: Eric Paris, Paul Moore, Steve Grubb, Ingo Molnar, David Howells,
Richard Guy Briggs
In-Reply-To: <cover.1526173613.git.rgb@redhat.com>
Recognizing that the audit context is an internal audit value, use an
access function to set the audit context pointer for the task
rather than reaching directly into the task struct to set it.
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
include/linux/audit.h | 6 ++++++
kernel/auditsc.c | 7 +++----
kernel/fork.c | 2 +-
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 786aa8e..f7973e4 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -235,6 +235,10 @@ extern void __audit_inode_child(struct inode *parent,
extern void __audit_seccomp(unsigned long syscall, long signr, int code);
extern void __audit_ptrace(struct task_struct *t);
+static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
+{
+ task->audit_context = ctx;
+}
static inline struct audit_context *audit_context(void)
{
return current->audit_context;
@@ -472,6 +476,8 @@ static inline bool audit_dummy_context(void)
{
return true;
}
+static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
+{ }
static inline struct audit_context *audit_context(void)
{
return NULL;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ecc0c23..d441d68 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -865,7 +865,7 @@ static inline struct audit_context *audit_take_context(struct task_struct *tsk,
audit_filter_inodes(tsk, context);
}
- tsk->audit_context = NULL;
+ audit_set_context(tsk, NULL);
return context;
}
@@ -952,7 +952,7 @@ int audit_alloc(struct task_struct *tsk)
}
context->filterkey = key;
- tsk->audit_context = context;
+ audit_set_context(tsk, context);
set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
return 0;
}
@@ -1554,7 +1554,6 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
*/
void __audit_syscall_exit(int success, long return_code)
{
- struct task_struct *tsk = current;
struct audit_context *context;
if (success)
@@ -1589,7 +1588,7 @@ void __audit_syscall_exit(int success, long return_code)
kfree(context->filterkey);
context->filterkey = NULL;
}
- tsk->audit_context = context;
+ audit_set_context(current, context);
}
static inline void handle_one(const struct inode *inode)
diff --git a/kernel/fork.c b/kernel/fork.c
index 242c8c9..cd18448 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1713,7 +1713,7 @@ static __latent_entropy struct task_struct *copy_process(
p->start_time = ktime_get_ns();
p->real_start_time = ktime_get_boot_ns();
p->io_context = NULL;
- p->audit_context = NULL;
+ audit_set_context(p, NULL);
cgroup_fork(p);
#ifdef CONFIG_NUMA
p->mempolicy = mpol_dup(p->mempolicy);
--
1.8.3.1
^ permalink raw reply related
* [PATCH ghak81 RFC V2 5/5] audit: collect audit task parameters
From: Richard Guy Briggs @ 2018-05-13 1:58 UTC (permalink / raw)
To: Linux-Audit Mailing List, LKML,
Linux NetDev Upstream Mailing List, Netfilter Devel List,
Linux Security Module list, Integrity Measurement Architecture,
SElinux list
Cc: Eric Paris, Paul Moore, Steve Grubb, Ingo Molnar, David Howells,
Richard Guy Briggs
In-Reply-To: <cover.1526173613.git.rgb@redhat.com>
The audit-related parameters in struct task_struct should ideally be
collected together and accessed through a standard audit API.
Collect the existing loginuid, sessionid and audit_context together in a
new struct audit_task_info called "audit" in struct task_struct.
See: https://github.com/linux-audit/audit-kernel/issues/81
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
MAINTAINERS | 2 +-
include/linux/audit.h | 10 +++++-----
include/linux/audit_task.h | 31 +++++++++++++++++++++++++++++++
include/linux/sched.h | 6 ++----
init/init_task.c | 7 +++++--
kernel/auditsc.c | 6 +++---
6 files changed, 47 insertions(+), 15 deletions(-)
create mode 100644 include/linux/audit_task.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 0a1410d..8c7992d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2510,7 +2510,7 @@ L: linux-audit@redhat.com (moderated for non-subscribers)
W: https://github.com/linux-audit
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git
S: Supported
-F: include/linux/audit.h
+F: include/linux/audit*.h
F: include/uapi/linux/audit.h
F: kernel/audit*
diff --git a/include/linux/audit.h b/include/linux/audit.h
index f7973e4..6d599b6 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -237,11 +237,11 @@ extern void __audit_inode_child(struct inode *parent,
static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
{
- task->audit_context = ctx;
+ task->audit.ctx = ctx;
}
static inline struct audit_context *audit_context(void)
{
- return current->audit_context;
+ return current->audit.ctx;
}
static inline bool audit_dummy_context(void)
{
@@ -250,7 +250,7 @@ static inline bool audit_dummy_context(void)
}
static inline void audit_free(struct task_struct *task)
{
- if (unlikely(task->audit_context))
+ if (unlikely(task->audit.ctx))
__audit_free(task);
}
static inline void audit_syscall_entry(int major, unsigned long a0,
@@ -330,12 +330,12 @@ extern int auditsc_get_stamp(struct audit_context *ctx,
static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
{
- return tsk->loginuid;
+ return tsk->audit.loginuid;
}
static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
{
- return tsk->sessionid;
+ return tsk->audit.sessionid;
}
extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
diff --git a/include/linux/audit_task.h b/include/linux/audit_task.h
new file mode 100644
index 0000000..d4b3a20
--- /dev/null
+++ b/include/linux/audit_task.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* audit_task.h -- definition of audit_task_info structure
+ *
+ * Copyright 2018 Red Hat Inc., Raleigh, North Carolina.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * Written by Richard Guy Briggs <rgb@redhat.com>
+ *
+ */
+
+#ifndef _LINUX_AUDIT_TASK_H_
+#define _LINUX_AUDIT_TASK_H_
+
+struct audit_context;
+struct audit_task_info {
+ kuid_t loginuid;
+ unsigned int sessionid;
+ struct audit_context *ctx;
+};
+
+#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index b3d697f..b58eca0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -27,9 +27,9 @@
#include <linux/signal_types.h>
#include <linux/mm_types_task.h>
#include <linux/task_io_accounting.h>
+#include <linux/audit_task.h>
/* task_struct member predeclarations (sorted alphabetically): */
-struct audit_context;
struct backing_dev_info;
struct bio_list;
struct blk_plug;
@@ -832,10 +832,8 @@ struct task_struct {
struct callback_head *task_works;
- struct audit_context *audit_context;
#ifdef CONFIG_AUDITSYSCALL
- kuid_t loginuid;
- unsigned int sessionid;
+ struct audit_task_info audit;
#endif
struct seccomp seccomp;
diff --git a/init/init_task.c b/init/init_task.c
index 74f60ba..d33260d 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -119,8 +119,11 @@ struct task_struct init_task
.thread_group = LIST_HEAD_INIT(init_task.thread_group),
.thread_node = LIST_HEAD_INIT(init_signals.thread_head),
#ifdef CONFIG_AUDITSYSCALL
- .loginuid = INVALID_UID,
- .sessionid = AUDIT_SID_UNSET,
+ .audit = {
+ .loginuid = INVALID_UID,
+ .sessionid = AUDIT_SID_UNSET,
+ .ctx = NULL,
+ },
#endif
#ifdef CONFIG_PERF_EVENTS
.perf_event_mutex = __MUTEX_INITIALIZER(init_task.perf_event_mutex),
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d441d68..4c1fd18 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -836,7 +836,7 @@ static inline struct audit_context *audit_take_context(struct task_struct *tsk,
int return_valid,
long return_code)
{
- struct audit_context *context = tsk->audit_context;
+ struct audit_context *context = tsk->audit.ctx;
if (!context)
return NULL;
@@ -2066,8 +2066,8 @@ int audit_set_loginuid(kuid_t loginuid)
sessionid = (unsigned int)atomic_inc_return(&session_id);
}
- task->sessionid = sessionid;
- task->loginuid = loginuid;
+ task->audit.sessionid = sessionid;
+ task->audit.loginuid = loginuid;
out:
audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
return rc;
--
1.8.3.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