Hello,
On commit f2d10565b9bdbb722bd43e6e1a759eeddb9645c8 (Nov 20).
The following program triggers use-after-free:
// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <syscall.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>
void *thread(void *p)
{
syscall(SYS_write, (long)p, 0x2000278ful, 0x1ul, 0, 0, 0);
return 0;
}
int main()
{
long r0 = syscall(SYS_mmap, 0x20000000ul, 0x10000ul, 0x2ul,
0x32ul, 0xfffffffffffffffful, 0x0ul);
long r1 = syscall(SYS_socketpair, 0x1ul, 0x3ul, 0x0ul,
0x20001000ul, 0, 0);
long r2 = -1;
if (r1 != -1)
r2 = *(uint32_t*)0x20001000;
long r3 = -1;
if (r1 != -1)
r3 = *(uint32_t*)0x20001004;
//long r4 = syscall(SYS_getuid, 0, 0, 0, 0, 0, 0);
long r5 = syscall(SYS_close, r2, 0, 0, 0, 0, 0);
pthread_t th;
pthread_create(&th, 0, thread, (void*)(long)r3);
long r6 = syscall(SYS_clock_gettime, 0x0ul, 0x20000ff0ul, 0, 0, 0, 0);
long r7 = -1;
if (r6 != -1)
r7 = *(uint64_t*)0x20000ff0;
long r8 = -1;
if (r6 != -1)
r8 = *(uint64_t*)0x20000ff8;
*(uint32_t*)0x20000fff = r3;
*(uint16_t*)0x20001003 = 0x8;
*(uint16_t*)0x20001005 = 0x9;
*(uint32_t*)0x20001007 = r3;
*(uint16_t*)0x2000100b = 0x6;
*(uint16_t*)0x2000100d = 0x22b;
*(uint32_t*)0x2000100f = r3;
*(uint16_t*)0x20001013 = 0xe7838d7e9fc50196;
*(uint16_t*)0x20001015 = 0x9c2;
*(uint64_t*)0x20000ffc = 0;//r7;
*(uint64_t*)0x20001004 = /*r8+*/10000000;
*(uint64_t*)0x20000ffd = 0x3;
long r21 = syscall(SYS_ppoll, 0x20000ffful, 0x3ul,
0x20000ffcul, 0x20000ffdul, 0x8ul, 0);
return 0;
}
[ 2672.994366] BUG: KASAN: use-after-free in
do_raw_spin_lock+0x22/0x220 at addr ffff88003d8829c4
[ 2672.994366] Read of size 4 by task syzkaller_execu/6653
[ 2672.994366] =============================================================================
[ 2672.994366] BUG UNIX (Not tainted): kasan: bad access detected
[ 2672.994366] -----------------------------------------------------------------------------
[ 2672.994366]
[ 2672.994366] INFO: Allocated in sk_prot_alloc+0x53/0x220 age=11 cpu=1 pid=6653
[ 2672.994366] __slab_alloc+0x235/0x570
[ 2672.994366] kmem_cache_alloc+0x131/0x170
[ 2672.994366] sk_prot_alloc+0x53/0x220
[ 2672.994366] sk_alloc+0x38/0x1c0
[ 2672.994366] unix_create1+0x5a/0x260
[ 2672.994366] unix_create+0xc4/0x110
[ 2672.994366] __sock_create+0x31c/0x490
[ 2672.994366] SyS_socketpair+0x14c/0x3c0
[ 2672.994366] entry_SYSCALL_64_fastpath+0x31/0x9a
[ 2672.994366] INFO: Freed in sk_destruct+0x1b5/0x260 age=12 cpu=1 pid=6653
[ 2672.994366] __slab_free+0x1ec/0x350
[ 2672.994366] kmem_cache_free+0x1ed/0x200
[ 2672.994366] sk_destruct+0x1b5/0x260
[ 2672.994366] __sk_free+0x61/0x110
[ 2672.994366] sk_free+0x30/0x40
[ 2672.994366] unix_dgram_poll+0x352/0x390
[ 2672.994366] sock_poll+0x13b/0x340
[ 2672.994366] do_sys_poll+0x405/0x860
[ 2672.994366] SyS_ppoll+0x1a9/0x310
[ 2672.994366] entry_SYSCALL_64_fastpath+0x31/0x9a
[ 2672.994366] INFO: Slab 0xffffea0000f62000 objects=17 used=5
fp=0xffff88003d882440 flags=0x100000000004080
[ 2672.994366] INFO: Object 0xffff88003d882440 @offset=9280
fp=0xffff88003d880e80
[ 2672.994366]
[ 2672.994366] CPU: 1 PID: 6653 Comm: syzkaller_execu Tainted: G B
4.4.0-rc1+ #66
[ 2672.994366] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS Bochs 01/01/2011
[ 2672.994366] ffffea0000f62000 ffff88004cee76f0 ffffffff8165b3b7
ffff88003e28fa80
[ 2672.994366] ffff88003d882440 ffff88003d880000 ffff88004cee7720
ffffffff812c32c4
[ 2672.994366] ffff88003e28fa80 ffffea0000f62000 ffff88003d882440
ffff88003d8829c0
[ 2672.994366] Call Trace:
[ 2672.994366] [<ffffffff812ca0fa>] __asan_load4+0x6a/0x70
[ 2672.994366] [<ffffffff81126832>] do_raw_spin_lock+0x22/0x220
[ 2672.994366] [<ffffffff821d6061>] _raw_spin_lock_irqsave+0x51/0x60
[ 2672.994366] [<ffffffff8110d748>] remove_wait_queue+0x18/0x80
[ 2672.994366] [<ffffffff812fddab>] poll_freewait+0x7b/0x130
[ 2672.994366] [<ffffffff8130063c>] do_sys_poll+0x4dc/0x860
[ 2672.994366] [<ffffffff81300eb9>] SyS_ppoll+0x1a9/0x310
[ 2672.994366] ==================================================================
[ 40.882065] BUG: KASAN: use-after-free in
__lock_acquire+0x7ea/0x2600 at addr ffff88006d145f98
[ 40.882065] Read of size 8 by task a.out/13880
[ 40.882065] =============================================================================
[ 40.887431] BUG UNIX (Not tainted): kasan: bad access detected
[ 40.887431] -----------------------------------------------------------------------------
[ 40.887431]
[ 40.887431] INFO: Allocated in sk_prot_alloc+0x53/0x220 age=0 cpu=3 pid=13885
[ 40.887431] ___slab_alloc+0x489/0x4e0
[ 40.896414] __slab_alloc+0x4c/0x90
[ 40.896786] kmem_cache_alloc+0x131/0x170
[ 40.896786] sk_prot_alloc+0x53/0x220
[ 40.896786] sk_alloc+0x38/0x1c0
[ 40.896786] unix_create1+0x5a/0x260
[ 40.896786] unix_create+0xc4/0x110
[ 40.896786] __sock_create+0x31c/0x490
[ 40.896786] SyS_socketpair+0x101/0x3c0
[ 40.896786] entry_SYSCALL_64_fastpath+0x31/0x9a
[ 40.896786] INFO: Freed in sk_destruct+0x1b5/0x260 age=0 cpu=1 pid=13888
[ 40.896786] __slab_free+0x1ec/0x350
[ 40.896786] kmem_cache_free+0x1ed/0x200
[ 40.896786] sk_destruct+0x1b5/0x260
[ 40.896786] __sk_free+0x61/0x110
[ 40.896786] sk_free+0x30/0x40
[ 40.896786] unix_release_sock+0x320/0x4e0
[ 40.896786] unix_release+0x35/0x60
[ 40.896786] sock_release+0x4e/0x100
[ 40.896786] sock_close+0x16/0x20
[ 40.896786] __fput+0x173/0x360
[ 40.896786] ____fput+0x15/0x20
[ 40.896786] task_work_run+0xe1/0x110
[ 40.896786] do_exit+0x55f/0x1690
[ 40.896786] do_group_exit+0xa7/0x190
[ 40.896786] get_signal+0x3d7/0xd80
[ 40.896786] do_signal+0x8c/0xa60
[ 40.896786] INFO: Slab 0xffffea0001b45000 objects=17 used=1
fp=0xffff88006d140000 flags=0x500000000004080
[ 40.896786] INFO: Object 0xffff88006d145a00 @offset=23040
fp=0xffff88006d144380
[ 40.896786]
[ 40.896786] Call Trace:
[ 40.896786] [<ffffffff812ca2b4>] __asan_load8+0x64/0x70
[ 40.896786] [<ffffffff8111db0a>] __lock_acquire+0x7ea/0x2600
[ 40.896786] [<ffffffff81120d51>] lock_acquire+0x101/0x1d0
[ 40.896786] [<ffffffff821d6e49>] _raw_spin_lock_irqsave+0x49/0x60
[ 40.896786] [<ffffffff8110d748>] remove_wait_queue+0x18/0x80
[ 40.896786] [<ffffffff812fde8b>] poll_freewait+0x7b/0x130
[ 40.896786] [<ffffffff8130071c>] do_sys_poll+0x4dc/0x860
[ 40.896786] [<ffffffff81300f99>] SyS_ppoll+0x1a9/0x310
[ 40.896786] ==================================================================
[ 198.125032] BUG: KASAN: use-after-free in
__lock_acquire+0x7ea/0x2600 at addr ffff88006d271c18
[ 198.125032] Read of size 8 by task executor/12267
[ 198.125032] =============================================================================
[ 198.125032] BUG UNIX (Not tainted): kasan: bad access detected
[ 198.125032] -----------------------------------------------------------------------------
[ 198.125032]
[ 198.136373] INFO: Allocated in sk_prot_alloc+0x53/0x220 age=27
cpu=3 pid=12267
[ 198.136373] __slab_alloc+0x235/0x570
[ 198.136373] kmem_cache_alloc+0x131/0x170
[ 198.136373] sk_prot_alloc+0x53/0x220
[ 198.136373] sk_alloc+0x38/0x1c0
[ 198.136373] unix_create1+0x5a/0x260
[ 198.136373] unix_create+0xc4/0x110
[ 198.136373] __sock_create+0x31c/0x490
[ 198.136373] SyS_socketpair+0x14c/0x3c0
[ 198.136373] entry_SYSCALL_64_fastpath+0x31/0x9a
[ 198.136373] INFO: Freed in sk_destruct+0x1b5/0x260 age=25 cpu=1 pid=12268
[ 198.136373] __slab_free+0x1ec/0x350
[ 198.136373] kmem_cache_free+0x1ed/0x200
[ 198.136373] sk_destruct+0x1b5/0x260
[ 198.136373] __sk_free+0x61/0x110
[ 198.136373] sk_free+0x30/0x40
[ 198.136373] unix_dgram_sendmsg+0x9f4/0xa50
[ 198.136373] sock_sendmsg+0x84/0xa0
[ 198.136373] sock_write_iter+0x142/0x1f0
[ 198.136373] __vfs_write+0x249/0x2a0
[ 198.136373] vfs_write+0x113/0x290
[ 198.136373] SyS_write+0xbb/0x170
[ 198.136373] entry_SYSCALL_64_fastpath+0x31/0x9a
[ 198.136373] INFO: Slab 0xffffea0001b49c00 objects=17 used=6
fp=0xffff88006d272580 flags=0x500000000004080
[ 198.136373] INFO: Object 0xffff88006d271680 @offset=5760
fp=0xffff88006d275280
[ 198.136373] CPU: 3 PID: 12267 Comm: executor Tainted: G B
4.4.0-rc1+ #66
[ 198.136373] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS Bochs 01/01/2011
[ 198.247087] ffffea0001b49c00 ffff88006cb9f540 ffffffff8165b3b7
ffff88003d98aac0
[ 198.247087] ffff88006d271680 ffff88006d270000 ffff88006cb9f570
ffffffff812c32c4
[ 198.247087] ffff88003d98aac0 ffffea0001b49c00 ffff88006d271680
0000000000000000
[ 198.247087] Call Trace:
[ 198.247087] [<ffffffff812ca1d4>] __asan_load8+0x64/0x70
[ 198.247087] [<ffffffff8111db0a>] __lock_acquire+0x7ea/0x2600
[ 198.247087] [<ffffffff81120d51>] lock_acquire+0x101/0x1d0
[ 198.247087] [<ffffffff821d6059>] _raw_spin_lock_irqsave+0x49/0x60
[ 198.247087] [<ffffffff8110d748>] remove_wait_queue+0x18/0x80
[ 198.247087] [<ffffffff812fddab>] poll_freewait+0x7b/0x130
[ 198.247087] [<ffffffff8130063c>] do_sys_poll+0x4dc/0x860
[ 198.247087] [<ffffffff81300eb9>] SyS_ppoll+0x1a9/0x310
[ 198.247087] ==================================================================
This can be related to "Use-after-free in ep_remove_wait_queue":
https://groups.google.com/d/msg/syzkaller/3twDUI4Cpm8/EY6qWbrjCAAJ
However, stacks are somewhat different, so maybe it is a different
issue (or at least another test case).
Thank you
Dmitry Vyukov <[email protected]> writes:
> Hello,
>
> On commit f2d10565b9bdbb722bd43e6e1a759eeddb9645c8 (Nov 20).
>
> The following program triggers use-after-free:
>
> // autogenerated by syzkaller (http://github.com/google/syzkaller)
> #include <syscall.h>
> #include <string.h>
> #include <stdint.h>
> #include <pthread.h>
>
> void *thread(void *p)
> {
> syscall(SYS_write, (long)p, 0x2000278ful, 0x1ul, 0, 0, 0);
> return 0;
> }
[...]
> long r1 = syscall(SYS_socketpair, 0x1ul, 0x3ul, 0x0ul,
[...]
> long r5 = syscall(SYS_close, r2, 0, 0, 0, 0, 0);
> pthread_t th;
> pthread_create(&th, 0, thread, (void*)(long)r3);
[...]
> long r21 = syscall(SYS_ppoll, 0x20000ffful, 0x3ul, 0x20000ffcul, 0x20000ffdul, 0x8ul, 0);
> return 0;
> }
That's one of the already known sequences for triggering this issue: The
close will clear the peer pointer of the closed socket, hence, the 2nd
sock_poll_wait will be called by unix_dgram_poll. The write will
execute unix_dgram_sendmsg which detects that the peer is dead and
disconnects from it, causing the corresponding structures to be freed
despite they're still used.
NB: I didn't execute this but I spend a fair amount of time with the
af_unix.c code during the last couple of weeks and consider myself
"reasonably familiar" with it and that's IMO what should happen here.
On Sun, Nov 22, 2015 at 3:32 PM, Rainer Weikusat
<[email protected]> wrote:
> Dmitry Vyukov <[email protected]> writes:
>> Hello,
>>
>> On commit f2d10565b9bdbb722bd43e6e1a759eeddb9645c8 (Nov 20).
>>
>> The following program triggers use-after-free:
>>
>> // autogenerated by syzkaller (http://github.com/google/syzkaller)
>> #include <syscall.h>
>> #include <string.h>
>> #include <stdint.h>
>> #include <pthread.h>
>>
>> void *thread(void *p)
>> {
>> syscall(SYS_write, (long)p, 0x2000278ful, 0x1ul, 0, 0, 0);
>> return 0;
>> }
>
> [...]
>
>
>> long r1 = syscall(SYS_socketpair, 0x1ul, 0x3ul, 0x0ul,
>
> [...]
>
>> long r5 = syscall(SYS_close, r2, 0, 0, 0, 0, 0);
>> pthread_t th;
>> pthread_create(&th, 0, thread, (void*)(long)r3);
>
> [...]
>
>> long r21 = syscall(SYS_ppoll, 0x20000ffful, 0x3ul, 0x20000ffcul, 0x20000ffdul, 0x8ul, 0);
>> return 0;
>> }
>
> That's one of the already known sequences for triggering this issue: The
> close will clear the peer pointer of the closed socket, hence, the 2nd
> sock_poll_wait will be called by unix_dgram_poll. The write will
> execute unix_dgram_sendmsg which detects that the peer is dead and
> disconnects from it, causing the corresponding structures to be freed
> despite they're still used.
>
> NB: I didn't execute this but I spend a fair amount of time with the
> af_unix.c code during the last couple of weeks and consider myself
> "reasonably familiar" with it and that's IMO what should happen here.
I have not read the code. But I just want to point out that all 3
reports are different. For example, in the first one, ppoll both frees
the object and then accesses it. That is, it is not write that frees
the object.
Dmitry Vyukov <[email protected]> writes:
> On Sun, Nov 22, 2015 at 3:32 PM, Rainer Weikusat
> <[email protected]> wrote:
>> Dmitry Vyukov <[email protected]> writes:
>>> Hello,
>>>
>>> On commit f2d10565b9bdbb722bd43e6e1a759eeddb9645c8 (Nov 20).
>>>
>>> The following program triggers use-after-free:
>>>
>>> // autogenerated by syzkaller (http://github.com/google/syzkaller)
>>> #include <syscall.h>
>>> #include <string.h>
>>> #include <stdint.h>
>>> #include <pthread.h>
>>>
>>> void *thread(void *p)
>>> {
>>> syscall(SYS_write, (long)p, 0x2000278ful, 0x1ul, 0, 0, 0);
>>> return 0;
>>> }
>>
>> [...]
>>
>>
>>> long r1 = syscall(SYS_socketpair, 0x1ul, 0x3ul, 0x0ul,
>>
>> [...]
>>
>>> long r5 = syscall(SYS_close, r2, 0, 0, 0, 0, 0);
>>> pthread_t th;
>>> pthread_create(&th, 0, thread, (void*)(long)r3);
>>
>> [...]
>>
>>> long r21 = syscall(SYS_ppoll, 0x20000ffful, 0x3ul, 0x20000ffcul, 0x20000ffdul, 0x8ul, 0);
>>> return 0;
>>> }
>>
>> That's one of the already known sequences for triggering this issue:
[...]
> I have not read the code. But I just want to point out that all 3
> reports are different. For example, in the first one, ppoll both frees
> the object and then accesses it. That is, it is not write that frees
> the object.
The call trace is always the same:
[ 2672.994366] [<ffffffff812ca0fa>] __asan_load4+0x6a/0x70
[ 2672.994366] [<ffffffff81126832>] do_raw_spin_lock+0x22/0x220
[ 2672.994366] [<ffffffff821d6061>] _raw_spin_lock_irqsave+0x51/0x60
[ 2672.994366] [<ffffffff8110d748>] remove_wait_queue+0x18/0x80
[ 2672.994366] [<ffffffff812fddab>] poll_freewait+0x7b/0x130
[ 2672.994366] [<ffffffff8130063c>] do_sys_poll+0x4dc/0x860
[ 2672.994366] [<ffffffff81300eb9>] SyS_ppoll+0x1a9/0x310
And if you look at the poll implementation, the important part is this
(fs/ select.c, do_sys_poll)
fdcount = do_poll(nfds, head, &table, end_time);
poll_freewait(&table);
do_poll calls the poll routine of the file descriptors which cause
"enqueuing of something" via poll wait callback. For poll, that's the
__pollwait routine in select.c:
static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
poll_table *p)
{
struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
struct poll_table_entry *entry = poll_get_entry(pwq);
if (!entry)
return;
entry->filp = get_file(filp);
entry->wait_address = wait_address;
entry->key = p->_key;
init_waitqueue_func_entry(&entry->wait, pollwake);
entry->wait.private = pwq;
add_wait_queue(wait_address, &entry->wait);
}
because of the close, this routine will be called with the peer_wait
wait_queue_head of the non-closed socket of the socket pair as
wait_address argument. And poll_freewait calls free_poll_entry for all
entries on the poll table which is
static void free_poll_entry(struct poll_table_entry *entry)
{
remove_wait_queue(entry->wait_address, &entry->wait);
fput(entry->filp);
}
but by this time, the wait_address points to freed memory because the
only thing which kept the socket it belonged to alive after the
corresponding file descriptor was closed was the reference the other
socket held. But that was dropped by unix_dgram_sendmsg upon detecting a
dead peer.
Rainer Weikusat <[email protected]> writes:
[...]
> because of the close, this routine will be called with the peer_wait
> wait_queue_head of the non-closed socket of the socket pair as
> wait_address argument.
This should have been "peer_wait wait_queue_head of the peer of the
non-closed socket, ie, that of the closed socket"...
On Sun, Nov 22, 2015 at 7:46 PM, Rainer Weikusat
<[email protected]> wrote:
> Dmitry Vyukov <[email protected]> writes:
>> On Sun, Nov 22, 2015 at 3:32 PM, Rainer Weikusat
>> <[email protected]> wrote:
>>> Dmitry Vyukov <[email protected]> writes:
>>>> Hello,
>>>>
>>>> On commit f2d10565b9bdbb722bd43e6e1a759eeddb9645c8 (Nov 20).
>>>>
>>>> The following program triggers use-after-free:
>>>>
>>>> // autogenerated by syzkaller (http://github.com/google/syzkaller)
>>>> #include <syscall.h>
>>>> #include <string.h>
>>>> #include <stdint.h>
>>>> #include <pthread.h>
>>>>
>>>> void *thread(void *p)
>>>> {
>>>> syscall(SYS_write, (long)p, 0x2000278ful, 0x1ul, 0, 0, 0);
>>>> return 0;
>>>> }
>>>
>>> [...]
>>>
>>>
>>>> long r1 = syscall(SYS_socketpair, 0x1ul, 0x3ul, 0x0ul,
>>>
>>> [...]
>>>
>>>> long r5 = syscall(SYS_close, r2, 0, 0, 0, 0, 0);
>>>> pthread_t th;
>>>> pthread_create(&th, 0, thread, (void*)(long)r3);
>>>
>>> [...]
>>>
>>>> long r21 = syscall(SYS_ppoll, 0x20000ffful, 0x3ul, 0x20000ffcul, 0x20000ffdul, 0x8ul, 0);
>>>> return 0;
>>>> }
>>>
>>> That's one of the already known sequences for triggering this issue:
>
> [...]
>
>> I have not read the code. But I just want to point out that all 3
>> reports are different. For example, in the first one, ppoll both frees
>> the object and then accesses it. That is, it is not write that frees
>> the object.
>
> The call trace is always the same:
>
> [ 2672.994366] [<ffffffff812ca0fa>] __asan_load4+0x6a/0x70
> [ 2672.994366] [<ffffffff81126832>] do_raw_spin_lock+0x22/0x220
> [ 2672.994366] [<ffffffff821d6061>] _raw_spin_lock_irqsave+0x51/0x60
> [ 2672.994366] [<ffffffff8110d748>] remove_wait_queue+0x18/0x80
> [ 2672.994366] [<ffffffff812fddab>] poll_freewait+0x7b/0x130
> [ 2672.994366] [<ffffffff8130063c>] do_sys_poll+0x4dc/0x860
> [ 2672.994366] [<ffffffff81300eb9>] SyS_ppoll+0x1a9/0x310
>
> And if you look at the poll implementation, the important part is this
> (fs/ select.c, do_sys_poll)
>
> fdcount = do_poll(nfds, head, &table, end_time);
> poll_freewait(&table);
>
> do_poll calls the poll routine of the file descriptors which cause
> "enqueuing of something" via poll wait callback. For poll, that's the
> __pollwait routine in select.c:
>
> static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
> poll_table *p)
> {
> struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
> struct poll_table_entry *entry = poll_get_entry(pwq);
> if (!entry)
> return;
> entry->filp = get_file(filp);
> entry->wait_address = wait_address;
> entry->key = p->_key;
> init_waitqueue_func_entry(&entry->wait, pollwake);
> entry->wait.private = pwq;
> add_wait_queue(wait_address, &entry->wait);
> }
>
> because of the close, this routine will be called with the peer_wait
> wait_queue_head of the non-closed socket of the socket pair as
> wait_address argument. And poll_freewait calls free_poll_entry for all
> entries on the poll table which is
>
> static void free_poll_entry(struct poll_table_entry *entry)
> {
> remove_wait_queue(entry->wait_address, &entry->wait);
> fput(entry->filp);
> }
>
> but by this time, the wait_address points to freed memory because the
> only thing which kept the socket it belonged to alive after the
> corresponding file descriptor was closed was the reference the other
> socket held. But that was dropped by unix_dgram_sendmsg upon detecting a
> dead peer.
Hi Rainer,
I am not questioning your conclusions. You definitely know better.
Btw, how close are you to a fix that everybody is happy with? I hit
this use-after-free very frequently.