lsds / sgx-lkl

SGX-LKL Library OS for running Linux applications inside of Intel SGX enclaves

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

writev() system call causing segmentation fault with invalid vector

shaikshavali1 opened this issue · comments

Original Test case writev02:
The file is created and write() is called with valid buffer to write
at some 8k th offset. After that writev() will be called with invalid
vector. This should return EFAULT. And at the same time, try looking at
the 8kth offset whether the file is intact or not.

Link: https://github.com/lsds/ltp/blob/ab1e56249de46e5ca09c9d8f80bf34b86ae40101/testcases/kernel/syscalls/writev/writev02.c#L149

Problem: if invalid vector is passed to the writev syscall expected to return EFAULT. But it is causing segmentation fault.

[[  SGX-LKL ]] libc_start_main_stage2(): Calling app main: /ltp/testcases/kernel/syscalls/writev/writev02
writev02    0  TINFO  :  Enter block 1
[[  SIGNAL  ]] Exception SIGSEGV (page fault) received (code=5 address=0x7fb000218fb8 opcode=0xb60f)
[[  SGX-LKL ]]     #0: 7fb0000e1bb2 in generic_perform_write(...)
[[  SGX-LKL ]]     #1: 7fb0000e1e08 in __generic_file_write_iter(...)
[[  SGX-LKL ]]     #2: 7fb0000e1fd3 in generic_file_write_iter(...)
[[  SGX-LKL ]]     #3: 7fb000107c5a in do_iter_readv_writev(...)
[[  SGX-LKL ]]     #4: 7fb000108446 in do_iter_write(...)
[[  SGX-LKL ]]     #5: 7fb0001084f0 in vfs_writev(...)
[[  SGX-LKL ]]     #6: 7fb0001085f6 in do_writev(...)
[[  SGX-LKL ]]     #7: 7fb00010936b in __se_sys_writev(...)
[[  SGX-LKL ]]     #8: 7fb00008b86f in lkl_syscall(...)
[[  SGX-LKL ]]     #9: 7fb0005a5179 in __filter_syscall3(...)
[[  SGX-LKL ]]     #10: 7fb0005a51b1 in writev(...)
[[  SGX-LKL ]]     #11: 7fb03da5b782 in <unknown>(...)
writev02    1  TBROK  :  writev02.c:218: sighandler received invalid signal : 11
bad count while changing owner
[[  SGX-LKL ]] FAIL: Kernel panic! Aborting...

GDB logs:

Thread 6 "ENCLAVE" hit Breakpoint 2, do_writev (fd=<optimized out>, vec=0x7fe03dc75040 <wr_iovec>, vlen=2, flags=0) at fs/read_write.c:1052
1052            if (f.file) {
(gdb) bt
#0  do_writev (fd=<optimized out>, vec=0x7fe03dc75040 <wr_iovec>, vlen=2, flags=0) at fs/read_write.c:1052
#1  0x00007fe00010936b in __do_sys_writev (vlen=<optimized out>, vec=<optimized out>, fd=<optimized out>) at fs/read_write.c:1131
#2  __se_sys_writev (fd=<optimized out>, vec=<optimized out>, vlen=<optimized out>) at fs/read_write.c:1128
#3  0x00007fe00008b86f in run_syscall (params=<optimized out>, no=<optimized out>) at arch/lkl/kernel/syscalls.c:44
#4  lkl_syscall (no=2, params=0x7fe040b02e30) at arch/lkl/kernel/syscalls.c:192
#5  0x00007fe0005a5179 in __filter_syscall3 (n=66, a1=4, a2=140601085874240, a3=2) at ./src/internal/syscall.h:81
#6  0x00007fe0005a51b1 in writev (fd=4, iov=0x7fe03dc75040 <wr_iovec>, count=2) at src/unistd/writev.c:6
#7  0x00007fe03da5b782 in main (argc=<optimized out>, argv=<optimized out>) at writev02.c:149
#8  0x00007fe000532904 in libc_start_main_stage2 (main=0x7fe03da5b590 <main>, argc=1, argv=0x7fe040b02f70) at src/env/__libc_start_main.c:168
#9  0x00007fe00053285e in __libc_start_main (main=0x7fe03da5b590 <main>, argc=1, argv=0x7fe040b02f70) at src/env/__libc_start_main.c:153
#10 0x00007fe03da5b9eb in _start_c (p=<optimized out>) at crt/crt1.c:17
#11 0x00007fe03da5b9c3 in _start ()
#12 0x00007fe040b03120 in ?? ()
#13 0x0000000000000001 in ?? ()
#14 0x00007fe000b04860 in ?? ()
#15 0x0000000000000000 in ?? ()
(gdb) s
1053                    loff_t pos, *ppos = file_ppos(f.file);
(gdb) s
file_ppos (file=<optimized out>) at fs/read_write.c:573
573             return file->f_mode & FMODE_STREAM ? NULL : &file->f_pos;
(gdb) s
do_writev (fd=<optimized out>, vec=0x7fe03dc75040 <wr_iovec>, vlen=2, flags=0) at fs/read_write.c:1055
1055                            pos = *ppos;
(gdb) s
1058                    ret = vfs_writev(f.file, vec, vlen, ppos, flags);
(gdb) s
1055                            pos = *ppos;
(gdb) s
1058                    ret = vfs_writev(f.file, vec, vlen, ppos, flags);
(gdb) s
vfs_writev (file=0x7fe03e88be00, vec=0x7fe03dc75040 <wr_iovec>, vlen=2, pos=0x7fe040b02d68, flags=0) at fs/read_write.c:1012
1012            ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
(gdb) s
1006    {
(gdb) s
1008            struct iovec *iov = iovstack;
(gdb) s
1006    {
(gdb) s
1012            ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
(gdb) s
1006    {
(gdb) s
1012            ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
(gdb) s
1008            struct iovec *iov = iovstack;
(gdb) s
1012            ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
(gdb) s
import_iovec (type=1, uvector=0x7fe03dc75040 <wr_iovec>, nr_segs=2, fast_segs=8, iov=0x7fe040b02c68, i=0x7fe040b02c70) at lib/iov_iter.c:1642
1642    {
(gdb) s
1645            n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
(gdb) s
1642    {
(gdb) s
import_iovec (type=1, uvector=0x7fe03dc75040 <wr_iovec>, nr_segs=2, fast_segs=8, iov=0x7fe040b02c68, i=0x7fe040b02c70) at lib/iov_iter.c:1645
1645            n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
(gdb) s
1642    {
(gdb) s
import_iovec (type=1, uvector=0x7fe03dc75040 <wr_iovec>, nr_segs=<optimized out>, fast_segs=8, iov=0x7fe040b02c68, i=0x7fe040b02c70)
    at lib/iov_iter.c:1645
1645            n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
(gdb) s
rw_copy_check_uvector (type=1, uvector=0x7fe03dc75040 <wr_iovec>, nr_segs=2, fast_segs=8, fast_pointer=0x7fe040b02ca0, ret_pointer=0x7fe040b02c08)
    at fs/read_write.c:779
779                     ret = 0;
(gdb) s
768     {
(gdb) s
778             if (nr_segs == 0) {
(gdb) s
768     {
(gdb) s
778             if (nr_segs == 0) {
(gdb) s
787             if (nr_segs > UIO_MAXIOV) {
(gdb) s
791             if (nr_segs > fast_segs) {
(gdb) s
798             if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
(gdb) s
copy_from_user (n=<optimized out>, from=<optimized out>, to=<optimized out>) at ./include/linux/uaccess.h:144
144                     n = _copy_from_user(to, from, n);
(gdb) s
_copy_from_user (to=0x7fe040b02ca0, from=0x7fe03dc75040 <wr_iovec>, n=32) at lib/usercopy.c:11
11              if (likely(access_ok(from, n))) {
(gdb) s
__lkl_access_ok (size=<optimized out>, addr=<optimized out>) at ./arch/lkl/include/asm/uaccess.h:14
14          if ( lkl_access_ok ) ret = lkl_access_ok(addr, size);
(gdb) s
lkl_access_ok (addr=140601085874240, size=32) at lkl/setup.c:1548
1548        int ret = 1;
(gdb) s
1551        if (!size)
(gdb) s
1554        ret = oe_is_within_enclave((void*)addr, size);
(gdb) s
oe_is_within_enclave (p=0x7fe03dc75040 <wr_iovec>, n=32) at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/memory.c:9
9           uint64_t range_start = (uint64_t)p;
(gdb) s
10          uint64_t range_end = range_start + (n == 0 ? 1 : n);
(gdb) s
11          uint64_t enclave_start = (uint64_t)__oe_get_enclave_base();
(gdb) s
__oe_get_enclave_base () at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/globals.c:145
145         return (uint8_t*)&_enclave_rva - _enclave_rva;
(gdb) s
oe_is_within_enclave (p=0x7fe03dc75040 <wr_iovec>, n=32) at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/memory.c:12
12          uint64_t enclave_end = enclave_start + __oe_get_enclave_size();
(gdb) s
__oe_get_enclave_size () at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/globals.c:150
150         return oe_enclave_properties_sgx.image_info.enclave_size;
(gdb) s
oe_is_within_enclave (p=0x7fe03dc75040 <wr_iovec>, n=32) at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/memory.c:16
16          if ((range_start > 0) && (range_end > range_start) &&
(gdb) s
17              (enclave_end > enclave_start) &&
(gdb) s
18              ((range_start >= enclave_start) && (range_end <= enclave_end)))
(gdb) s
16          if ((range_start > 0) && (range_end > range_start) &&
(gdb) s
20              return true;
(gdb) s
24      }
(gdb) s
lkl_access_ok (addr=140601085874240, size=32) at lkl/setup.c:1555
1555        if (!ret)
(gdb) s
1559        return ret;
(gdb) s
1560    }
(gdb) s
_copy_from_user (to=0xffffffffff558b88, from=0x0, n=32) at lib/usercopy.c:11
11              if (likely(access_ok(from, n))) {
(gdb) s
13                      res = raw_copy_from_user(to, from, n);
(gdb) s
raw_copy_from_user (n=<optimized out>, from=<optimized out>, to=<optimized out>) at ./arch/lkl/include/asm/uaccess.h:43
43              memcpy(to, (const void __force *)from, n);
(gdb) s
memcpy (dest=0x7fe040b02ca0, src=0x7fe03dc75040 <wr_iovec>, count=32) at lib/string.c:847
847     {
(gdb) s
851             while (count--)
(gdb) s
847     {
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb) s
851             while (count--)
(gdb) s
852                     *tmp++ = *s++;
(gdb)
851             while (count--)
(gdb)
852                     *tmp++ = *s++;
(gdb)
851             while (count--)
(gdb)
852                     *tmp++ = *s++;
(gdb)
851             while (count--)
(gdb)
852                     *tmp++ = *s++;
(gdb)
(gdb)
851             while (count--)
(gdb)
854     }
(gdb)
_copy_from_user (to=0x7fe040b02ca0, from=0x7fe03dc75040 <wr_iovec>, n=32) at lib/usercopy.c:18
18      }
(gdb)
13                      res = raw_copy_from_user(to, from, n);
(gdb)
18      }
(gdb)
rw_copy_check_uvector (type=1, uvector=0x7fe03dc75040 <wr_iovec>, nr_segs=<optimized out>, fast_segs=<optimized out>, fast_pointer=<optimized out>,
    ret_pointer=<optimized out>) at fs/read_write.c:798
798             if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
(gdb)
812             ret = 0;
(gdb)
828                     if (len > MAX_RW_COUNT - ret) {
(gdb)
815                     ssize_t len = (ssize_t)iov[seg].iov_len;
(gdb)
819                     if (len < 0) {
(gdb)
815                     ssize_t len = (ssize_t)iov[seg].iov_len;
(gdb)
819                     if (len < 0) {
(gdb)
823                     if (type >= 0
(gdb)
824                         && unlikely(!access_ok(buf, len))) {
(gdb)
__lkl_access_ok (size=<optimized out>, addr=<optimized out>) at ./arch/lkl/include/asm/uaccess.h:14
14          if ( lkl_access_ok ) ret = lkl_access_ok(addr, size);
(gdb)
lkl_access_ok (addr=140601083650048, size=8192) at lkl/setup.c:1548
1548        int ret = 1;
(gdb)
1551        if (!size)
(gdb)
1554        ret = oe_is_within_enclave((void*)addr, size);
(gdb)
oe_is_within_enclave (p=0x7fe03da56000, n=8192) at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/memory.c:9
9           uint64_t range_start = (uint64_t)p;
(gdb)
10          uint64_t range_end = range_start + (n == 0 ? 1 : n);
(gdb)
11          uint64_t enclave_start = (uint64_t)__oe_get_enclave_base();
(gdb)
__oe_get_enclave_base () at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/globals.c:145
145         return (uint8_t*)&_enclave_rva - _enclave_rva;
(gdb)
oe_is_within_enclave (p=0x7fe03da56000, n=8192) at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/memory.c:12
12          uint64_t enclave_end = enclave_start + __oe_get_enclave_size();
(gdb)
__oe_get_enclave_size () at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/globals.c:150
150         return oe_enclave_properties_sgx.image_info.enclave_size;
(gdb)
oe_is_within_enclave (p=0x7fe03da56000, n=8192) at /mnt/shaik/1108/sgx-lkl/openenclave/enclave/core/sgx/memory.c:16
16          if ((range_start > 0) && (range_end > range_start) &&
(gdb)
17              (enclave_end > enclave_start) &&
(gdb)
18              ((range_start >= enclave_start) && (range_end <= enclave_end)))
(gdb)
16          if ((range_start > 0) && (range_end > range_start) &&
(gdb)
20              return true;
(gdb)
24      }
(gdb)
lkl_access_ok (addr=140601083650048, size=8192) at lkl/setup.c:1555
1555        if (!ret)
(gdb)
1559        return ret;
(gdb)
1560    }
(gdb)
rw_copy_check_uvector (type=1, uvector=<optimized out>, nr_segs=<optimized out>, fast_segs=<optimized out>, fast_pointer=<optimized out>,
    ret_pointer=<optimized out>) at fs/read_write.c:824
824                         && unlikely(!access_ok(buf, len))) {
(gdb)
832                     ret += len;
(gdb)
813             for (seg = 0; seg < nr_segs; seg++) {
(gdb)
815                     ssize_t len = (ssize_t)iov[seg].iov_len;
(gdb)
819                     if (len < 0) {
(gdb)
815                     ssize_t len = (ssize_t)iov[seg].iov_len;
(gdb)
819                     if (len < 0) {
(gdb)
823                     if (type >= 0
(gdb)
824                         && unlikely(!access_ok(buf, len))) {
(gdb)
__lkl_access_ok (size=<optimized out>, addr=<optimized out>) at ./arch/lkl/include/asm/uaccess.h:14
14          if ( lkl_access_ok ) ret = lkl_access_ok(addr, size);
(gdb)
lkl_access_ok (addr=0, size=0) at lkl/setup.c:1548
1548        int ret = 1;
(gdb)
1551        if (!size)
(gdb)
1552            return ret;
(gdb)
1560    }
(gdb)
rw_copy_check_uvector (type=1, uvector=<optimized out>, nr_segs=<optimized out>, fast_segs=<optimized out>, fast_pointer=<optimized out>,
    ret_pointer=<optimized out>) at fs/read_write.c:824
824                         && unlikely(!access_ok(buf, len))) {
(gdb)
832                     ret += len;
(gdb)
813             for (seg = 0; seg < nr_segs; seg++) {
(gdb)
835             *ret_pointer = iov;
(gdb)
837     }
(gdb)
import_iovec (type=1, uvector=<optimized out>, nr_segs=<optimized out>, fast_segs=<optimized out>, iov=0x7fe040b02c68, i=0x7fe040b02c70)
    at lib/iov_iter.c:1647
1647            if (n < 0) {
(gdb)
1645            n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
(gdb)
1647            if (n < 0) {
(gdb)
1653            iov_iter_init(i, type, p, nr_segs, n);
(gdb)
iov_iter_init (i=0x7fe040b02c70, direction=1, iov=0x7fe040b02ca0, nr_segs=2, count=8192) at lib/iov_iter.c:440
440             WARN_ON(direction & ~(READ | WRITE));
(gdb)
444             if (uaccess_kernel()) {
(gdb)
441             direction &= READ | WRITE;
(gdb)
444             if (uaccess_kernel()) {
(gdb)
448                     i->type = ITER_IOVEC | direction;
(gdb)
449                     i->iov = iov;
(gdb)
448                     i->type = ITER_IOVEC | direction;
(gdb)
451             i->nr_segs = nr_segs;
(gdb)
452             i->iov_offset = 0;
(gdb)
453             i->count = count;
(gdb)
454     }
(gdb)
import_iovec (type=1, uvector=<optimized out>, nr_segs=<optimized out>, fast_segs=<optimized out>, iov=0x7fe040b02c68, i=0x7fe040b02c70)
    at lib/iov_iter.c:1654
1654            *iov = p == *iov ? NULL : p;
(gdb)
1655            return n;
(gdb)
1656    }
(gdb)
vfs_writev (file=0x7fe03e88be00, vec=<optimized out>, vlen=<optimized out>, pos=0x7fe040b02d68, flags=0) at fs/read_write.c:1013
1013            if (ret >= 0) {
(gdb)
1014                    file_start_write(file);
(gdb)
file_start_write (file=<optimized out>) at fs/read_write.c:1014
1014                    file_start_write(file);
(gdb)
file_inode (f=<optimized out>) at ./include/linux/fs.h:1300
1300            return f->f_inode;
(gdb)
file_start_write (file=<optimized out>) at ./include/linux/fs.h:2826
2826            if (!S_ISREG(file_inode(file)->i_mode))
(gdb)
vfs_writev (file=0x7fe03e88be00, vec=<optimized out>, vlen=<optimized out>, pos=0x7fe040b02d68, flags=0) at fs/read_write.c:1014
1014                    file_start_write(file);
(gdb)
file_start_write (file=<optimized out>) at ./include/linux/fs.h:2828
2828            __sb_start_write(file_inode(file)->i_sb, SB_FREEZE_WRITE, true);
(gdb)
__sb_start_write (sb=0x7fe03fec7000, level=1, wait=true) at fs/super.c:1520
1520    {
(gdb)
__sb_start_write (sb=0x7fe03fec7000, level=1, wait=true) at fs/super.c:1544
1544            if (wait && !force_trylock)
(gdb)
1545                    percpu_down_read(sb->s_writers.rw_sem + level-1);
(gdb)
percpu_down_read (sem=<optimized out>) at ./include/linux/percpu-rwsem.h:51
51              __this_cpu_inc(*sem->read_count);
(gdb)
52              if (unlikely(!rcu_sync_is_idle(&sem->rss)))
(gdb)
rcu_sync_is_idle (rsp=<optimized out>) at ./include/linux/percpu-rwsem.h:52
52              if (unlikely(!rcu_sync_is_idle(&sem->rss)))
(gdb)
__read_once_size (size=<optimized out>, res=<optimized out>, p=<optimized out>) at ./include/linux/compiler.h:199
199             __READ_ONCE_SIZE;
(gdb)
percpu_down_read (sem=<optimized out>) at ./include/linux/percpu-rwsem.h:52
52              if (unlikely(!rcu_sync_is_idle(&sem->rss)))
(gdb)
__sb_start_write (sb=<optimized out>, level=1, wait=true) at fs/super.c:1522
1522            int ret = 1;
(gdb)
1551    }
(gdb)
vfs_writev (file=0x7fe03e88be00, vec=<optimized out>, vlen=<optimized out>, pos=0x7fe040b02d68, flags=0) at fs/read_write.c:1015
1015                    ret = do_iter_write(file, &iter, pos, flags);
(gdb)
(gdb)
do_iter_write (file=0x7fe03e88be00, iter=0x7fe040b02c70, pos=0x7fe040b02d68, flags=0) at fs/read_write.c:957
957             if (!(file->f_mode & FMODE_WRITE))
(gdb)
959             if (!(file->f_mode & FMODE_CAN_WRITE))
(gdb)
962             tot_len = iov_iter_count(iter);
(gdb)
iov_iter_count (i=<optimized out>) at ./include/linux/uio.h:235
235             return i->count;
(gdb)
do_iter_write (file=0x7fe03e88be00, iter=0x7fe040b02c70, pos=0x7fe040b02d68, flags=0) at fs/read_write.c:963
963             if (!tot_len)
(gdb)
965             ret = rw_verify_area(WRITE, file, pos, tot_len);
(gdb)
rw_verify_area (read_write=1, file=0x7fe03e88be00, ppos=0x7fe040b02d68, count=8192) at fs/read_write.c:372
372                     return retval;
(gdb)
366     {
(gdb)
371             if (unlikely((ssize_t) count < 0))
(gdb)
399             return security_file_permission(file,
(gdb)
378             if (ppos) {
(gdb)
379                     loff_t pos = *ppos;
(gdb)
381                     if (unlikely(pos < 0)) {
(gdb)
386                     } else if (unlikely((loff_t) (pos + count) < 0)) {
(gdb)
370             inode = file_inode(file);
(gdb)
file_inode (f=<optimized out>) at ./include/linux/fs.h:1300
1300            return f->f_inode;
(gdb)
rw_verify_area (read_write=1, file=0x7fe03e88be00, ppos=<optimized out>, count=8192) at fs/read_write.c:399
399             return security_file_permission(file,
(gdb)
391                     if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
(gdb)
(gdb)
401     }
(gdb)
do_iter_write (file=0x7fe03e88be00, iter=0x7fe040b02c70, pos=0x7fe040b02d68, flags=0) at fs/read_write.c:966
966             if (ret < 0)
(gdb)
969             if (file->f_op->write_iter)
(gdb)
970                     ret = do_iter_readv_writev(file, iter, pos, WRITE, flags);
(gdb)
do_iter_readv_writev (filp=0x7fe03e88be00, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:680
680     {
(gdb)
684             init_sync_kiocb(&kiocb, filp);
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at fs/read_write.c:684
684             init_sync_kiocb(&kiocb, filp);
(gdb)
iocb_flags (file=<optimized out>) at ./include/linux/fs.h:3330
3330            int res = 0;
(gdb)
do_iter_readv_writev (filp=0x7fe03e88be00, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:680
680     {
(gdb)
do_iter_readv_writev (filp=0x7fe03e88be00, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:684
684             init_sync_kiocb(&kiocb, filp);
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at fs/read_write.c:684
684             init_sync_kiocb(&kiocb, filp);
(gdb)
iocb_flags (file=<optimized out>) at ./include/linux/fs.h:3331
3331            if (file->f_flags & O_APPEND)
(gdb)
3330            int res = 0;
(gdb)
3334                    res |= IOCB_DIRECT;
(gdb)
3335            if ((file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host))
(gdb)
iocb_flags (file=<optimized out>) at ./include/linux/fs.h:3338
3338                    res |= IOCB_SYNC;
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at ./include/linux/fs.h:2042
2042                    .ki_hint = ki_hint_validate(file_write_hint(filp)),
(gdb)
file_write_hint (file=<optimized out>) at ./include/linux/fs.h:2020
2020            if (file->f_write_hint != WRITE_LIFE_NOT_SET)
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at ./include/linux/fs.h:2041
2041                    .ki_flags = iocb_flags(filp),
(gdb)
iocb_flags (file=<optimized out>) at ./include/linux/fs.h:3338
3338                    res |= IOCB_SYNC;
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at ./include/linux/fs.h:2042
2042                    .ki_hint = ki_hint_validate(file_write_hint(filp)),
(gdb)
file_write_hint (file=<optimized out>) at ./include/linux/fs.h:2020
2020            if (file->f_write_hint != WRITE_LIFE_NOT_SET)
(gdb)
2023            return file_inode(file)->i_write_hint;
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at ./include/linux/fs.h:2043
2043                    .ki_ioprio = get_current_ioprio(),
(gdb)
get_current_ioprio () at ./include/linux/ioprio.h:79
79              struct io_context *ioc = current->io_context;
(gdb)
81              if (ioc)
(gdb)
82                      return ioc->ioprio;
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at ./include/linux/fs.h:2039
2039            *kiocb = (struct kiocb) {
(gdb)
do_iter_readv_writev (filp=0x7fe03e88be00, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:685
685             ret = kiocb_set_rw_flags(&kiocb, flags);
(gdb)
kiocb_set_rw_flags (flags=<optimized out>, ki=<optimized out>) at ./include/linux/fs.h:3344
3344            if (unlikely(flags & ~RWF_SUPPORTED))
(gdb)
do_iter_readv_writev (filp=0x7fe03e88be00, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:684
684             init_sync_kiocb(&kiocb, filp);
(gdb)
init_sync_kiocb (filp=<optimized out>, kiocb=<optimized out>) at ./include/linux/fs.h:2039
2039            *kiocb = (struct kiocb) {
(gdb)
do_iter_readv_writev (filp=0x7fe03e88be00, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:685
685             ret = kiocb_set_rw_flags(&kiocb, flags);
(gdb)
kiocb_set_rw_flags (flags=<optimized out>, ki=<optimized out>) at ./include/linux/fs.h:3344
3344            if (unlikely(flags & ~RWF_SUPPORTED))
(gdb)
3347            if (flags & RWF_NOWAIT) {
(gdb)
3352            if (flags & RWF_HIPRI)
(gdb)
3354            if (flags & RWF_DSYNC)
(gdb)
3356            if (flags & RWF_SYNC)
(gdb)
3358            if (flags & RWF_APPEND)
(gdb)
do_iter_readv_writev (filp=0x7fe03e88be00, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:688
688             kiocb.ki_pos = (ppos ? *ppos : 0);
(gdb)
690             if (type == READ)
(gdb)
688             kiocb.ki_pos = (ppos ? *ppos : 0);
(gdb)
691                     ret = call_read_iter(filp, &kiocb, iter);
(gdb)
call_read_iter (iter=<optimized out>, kio=<optimized out>, file=<optimized out>) at ./include/linux/fs.h:1864
1864            return file->f_op->read_iter(kio, iter);
(gdb)
do_iter_readv_writev (filp=<optimized out>, iter=0x7fe040b02c70, ppos=0x7fe040b02d68, type=1, flags=0) at fs/read_write.c:690
690             if (type == READ)
(gdb)
693                     ret = call_write_iter(filp, &kiocb, iter);
(gdb)
call_write_iter (iter=<optimized out>, kio=<optimized out>, file=<optimized out>) at ./include/linux/fs.h:1870
1870            return file->f_op->write_iter(kio, iter);
(gdb)
generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3482
3482            struct inode *inode = file->f_mapping->host;
(gdb)
3485            inode_lock(inode);
(gdb)
inode_lock (inode=<optimized out>) at ./include/linux/fs.h:778
778             down_write(&inode->i_rwsem);
(gdb)
down_write (sem=0x7fe04009a6e0) at kernel/locking/rwsem.c:1498
1498    {
(gdb)
1501            LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
(gdb)
__down_write (sem=<optimized out>) at kernel/locking/rwsem.c:1501
1501            LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
(gdb)
atomic_long_try_cmpxchg_acquire (new=<optimized out>, old=<optimized out>, v=<optimized out>) at kernel/locking/rwsem.c:1501
1501            LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
(gdb)
atomic64_try_cmpxchg_acquire (new=<optimized out>, old=<optimized out>, v=<optimized out>) at ./include/linux/atomic-fallback.h:2041
2041            r = atomic64_cmpxchg_acquire(v, o, new);
(gdb)
down_write (sem=0x7fe04009a6e0) at kernel/locking/rwsem.c:1498
1498    {
(gdb)
down_write (sem=0x7fe04009a6e0) at kernel/locking/rwsem.c:1501
1501            LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
(gdb)
__down_write (sem=<optimized out>) at kernel/locking/rwsem.c:1501
1501            LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
(gdb)
atomic_long_try_cmpxchg_acquire (new=<optimized out>, old=<optimized out>, v=<optimized out>) at kernel/locking/rwsem.c:1501
1501            LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
(gdb)
atomic64_try_cmpxchg_acquire (new=<optimized out>, old=<optimized out>, v=<optimized out>) at ./include/linux/atomic-fallback.h:2041
2041            r = atomic64_cmpxchg_acquire(v, o, new);
(gdb)
atomic64_cmpxchg (v=0x7fe04009a6e0, o=0, n=1) at lib/atomic64.c:154
154             raw_spin_lock_irqsave(lock, flags);
(gdb)
arch_local_irq_save () at ./include/asm-generic/irqflags.h:29
29              flags = arch_local_save_flags();
(gdb)
arch_local_save_flags () at arch/lkl/kernel/irq.c:166
166     {
(gdb)
167             return irqs_enabled;
(gdb)
166     {
(gdb)
168     }
(gdb)
arch_local_irq_save () at ./include/asm-generic/irqflags.h:30
30              arch_local_irq_restore(ARCH_IRQ_DISABLED);
(gdb) bt
#0  arch_local_irq_save () at ./include/asm-generic/irqflags.h:30
#1  atomic64_cmpxchg (v=0x7fe04009a6e0, o=0, n=1) at lib/atomic64.c:154
#2  0x00007fe0004170b8 in atomic64_try_cmpxchg_acquire (new=<optimized out>, old=<optimized out>, v=<optimized out>)
    at ./include/linux/atomic-fallback.h:2041
#3  atomic_long_try_cmpxchg_acquire (new=<optimized out>, old=<optimized out>, v=<optimized out>) at ./include/asm-generic/atomic-long.h:442
#4  __down_write (sem=<optimized out>) at kernel/locking/rwsem.c:1363
#5  down_write (sem=0x7fe04009a6e0) at kernel/locking/rwsem.c:1501
#6  0x00007fe04009a6e0 in ?? ()
#7  0x00007fe040b02bb0 in ?? ()
#8  0x00007fe0000e1ef1 in inode_lock (inode=<optimized out>) at ./include/linux/fs.h:778
#9  generic_file_write_iter (iocb=0x7fe04009a6e0, from=0x0) at mm/filemap.c:3485
#10 0x00007fe040b02c70 in ?? ()
#11 0x00007fe03e88be00 in ?? ()
#12 0x00007fe040b02d68 in ?? ()
#13 0x00007fe040b02c00 in ?? ()
#14 0x00007fe000107c5a in call_write_iter (iter=<optimized out>, kio=<optimized out>, file=<optimized out>) at ./include/linux/fs.h:1870
#15 do_iter_readv_writev (filp=<optimized out>, iter=<optimized out>, ppos=0x1, type=<optimized out>, flags=<optimized out>) at fs/read_write.c:693
#16 0x0000000000000000 in ?? ()
(gdb) s
29              flags = arch_local_save_flags();
(gdb)
30              arch_local_irq_restore(ARCH_IRQ_DISABLED);
(gdb)
arch_local_irq_restore (flags=0) at arch/lkl/kernel/irq.c:172
172             if (flags == ARCH_IRQ_ENABLED && irqs_enabled == ARCH_IRQ_DISABLED &&
(gdb)
175             irqs_enabled = flags;
(gdb)
atomic64_cmpxchg (v=0x7fe04009a6e0, o=0, n=1) at lib/atomic64.c:155
155             val = v->counter;
(gdb)
156             if (val == o)
(gdb)
157                     v->counter = n;
(gdb)
158             raw_spin_unlock_irqrestore(lock, flags);
(gdb)
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:172
172             if (flags == ARCH_IRQ_ENABLED && irqs_enabled == ARCH_IRQ_DISABLED &&
(gdb)
173                 !in_interrupt())
(gdb)
preempt_count () at arch/lkl/kernel/irq.c:173
173                 !in_interrupt())
(gdb)
current_thread_info () at ./arch/lkl/include/asm/thread_info.h:46
46              return _current_thread_info;
(gdb)
preempt_count () at ./include/asm-generic/preempt.h:11
11              return READ_ONCE(current_thread_info()->preempt_count);
(gdb)
__read_once_size (size=<optimized out>, res=<optimized out>, p=<optimized out>) at ./include/linux/compiler.h:199
199             __READ_ONCE_SIZE;
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:172
172             if (flags == ARCH_IRQ_ENABLED && irqs_enabled == ARCH_IRQ_DISABLED &&
(gdb)
171     {
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:174
174                     run_irqs();
(gdb)
run_irqs () at arch/lkl/kernel/irq.c:129
129             for_each_bit(test_and_clear_irq_index_status(), check_irq_status, 0);
(gdb)
test_and_clear_irq_index_status () at arch/lkl/kernel/irq.c:128
128     {
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:175
175             irqs_enabled = flags;
(gdb)
176     }
(gdb)
atomic64_cmpxchg (v=0x7fe04009a6e0, o=0, n=1) at lib/atomic64.c:160
160     }
(gdb)
__down_write (sem=<optimized out>) at kernel/locking/rwsem.c:1363
1363            if (unlikely(!atomic_long_try_cmpxchg_acquire(&sem->count, &tmp,
(gdb)
1367                    rwsem_set_owner(sem);
(gdb)
rwsem_set_owner (sem=<optimized out>) at kernel/locking/rwsem.c:1367
1367                    rwsem_set_owner(sem);
(gdb)
atomic_long_set (i=<optimized out>, v=<optimized out>) at ./include/asm-generic/atomic-long.h:40
40              atomic64_set(v, i);
(gdb)
rwsem_set_owner (sem=<optimized out>) at kernel/locking/rwsem.c:176
176             atomic_long_set(&sem->owner, (long)current);
(gdb)
atomic_long_set (i=<optimized out>, v=<optimized out>) at ./include/asm-generic/atomic-long.h:40
40              atomic64_set(v, i);
(gdb)
atomic64_set (v=0x7fe04009a6e8, i=140601100807168) at lib/atomic64.c:63
63              raw_spin_lock_irqsave(lock, flags);
(gdb)
arch_local_irq_save () at ./include/asm-generic/irqflags.h:29
29              flags = arch_local_save_flags();
(gdb)
arch_local_save_flags () at arch/lkl/kernel/irq.c:166
166     {
(gdb)
167             return irqs_enabled;
(gdb)
166     {
(gdb)
168     }
(gdb)
arch_local_irq_save () at ./include/asm-generic/irqflags.h:30
30              arch_local_irq_restore(ARCH_IRQ_DISABLED);
(gdb)
29              flags = arch_local_save_flags();
(gdb)
30              arch_local_irq_restore(ARCH_IRQ_DISABLED);
(gdb)
arch_local_irq_restore (flags=0) at arch/lkl/kernel/irq.c:172
172             if (flags == ARCH_IRQ_ENABLED && irqs_enabled == ARCH_IRQ_DISABLED &&
(gdb)
175             irqs_enabled = flags;
(gdb)
atomic64_set (v=0x7fe04009a6e8, i=140601100807168) at lib/atomic64.c:64
64              v->counter = i;
(gdb)
65              raw_spin_unlock_irqrestore(lock, flags);
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:172
172             if (flags == ARCH_IRQ_ENABLED && irqs_enabled == ARCH_IRQ_DISABLED &&
(gdb)
173                 !in_interrupt())
(gdb)
preempt_count () at arch/lkl/kernel/irq.c:173
173                 !in_interrupt())
(gdb)
current_thread_info () at ./arch/lkl/include/asm/thread_info.h:46
46              return _current_thread_info;
(gdb)
preempt_count () at ./include/asm-generic/preempt.h:11
11              return READ_ONCE(current_thread_info()->preempt_count);
(gdb)
__read_once_size (size=<optimized out>, res=<optimized out>, p=<optimized out>) at ./include/linux/compiler.h:199
199             __READ_ONCE_SIZE;
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:172
172             if (flags == ARCH_IRQ_ENABLED && irqs_enabled == ARCH_IRQ_DISABLED &&
(gdb)
171     {
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:174
174                     run_irqs();
(gdb)
run_irqs () at arch/lkl/kernel/irq.c:129
129             for_each_bit(test_and_clear_irq_index_status(), check_irq_status, 0);
(gdb)
test_and_clear_irq_index_status () at arch/lkl/kernel/irq.c:128
128     {
(gdb)
arch_local_irq_restore (flags=1) at arch/lkl/kernel/irq.c:175
175             irqs_enabled = flags;
(gdb)
176     }
(gdb)
atomic64_set (v=0x7fe04009a6e8, i=140601100807168) at lib/atomic64.c:66
66      }
(gdb)
down_write (sem=0x7fe04009a6e0) at kernel/locking/rwsem.c:1502
1502    }
(gdb)
generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3486
3486            ret = generic_write_checks(iocb, from);
(gdb)
generic_write_checks (from=<optimized out>, iocb=<optimized out>) at mm/filemap.c:2991
2991            if (!iov_iter_count(from))
(gdb)
generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3486
3486            ret = generic_write_checks(iocb, from);
(gdb)
generic_write_checks (from=<optimized out>, iocb=<optimized out>) at mm/filemap.c:2995
2995            if (iocb->ki_flags & IOCB_APPEND)
(gdb)
2986            struct file *file = iocb->ki_filp;
(gdb)
2995            if (iocb->ki_flags & IOCB_APPEND)
(gdb)
2998            if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
(gdb)
generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3486
3486            ret = generic_write_checks(iocb, from);
(gdb)
generic_write_checks (from=<optimized out>, iocb=<optimized out>) at mm/filemap.c:3002
3002            ret = generic_write_check_limits(file, iocb->ki_pos, &count);
(gdb)
3001            count = iov_iter_count(from);
(gdb)
3002            ret = generic_write_check_limits(file, iocb->ki_pos, &count);
(gdb)
3001            count = iov_iter_count(from);
(gdb)
3002            ret = generic_write_check_limits(file, iocb->ki_pos, &count);
(gdb)
generic_write_check_limits (pos=0, count=0x7fe040b02b88, file=<optimized out>, file=<optimized out>) at mm/filemap.c:2955
2955            loff_t max_size = inode->i_sb->s_maxbytes;
(gdb)
2956            loff_t limit = rlimit(RLIMIT_FSIZE);
(gdb)
rlimit (limit=<optimized out>) at ./include/linux/sched/signal.h:706
706             return task_rlimit(current, limit);
(gdb)
task_rlimit (limit=<optimized out>, task=<optimized out>) at ./include/linux/sched/signal.h:695
695             return READ_ONCE(task->signal->rlim[limit].rlim_cur);
(gdb)
__read_once_size (size=<optimized out>, res=<optimized out>, p=<optimized out>) at ./include/linux/compiler.h:199
199             __READ_ONCE_SIZE;
(gdb)
generic_write_check_limits (pos=0, count=0x7fe040b02b88, file=<optimized out>, file=<optimized out>) at mm/filemap.c:2958
2958            if (limit != RLIM_INFINITY) {
(gdb)
2966            if (!(file->f_flags & O_LARGEFILE))
(gdb)
2967                    max_size = MAX_NON_LFS;
(gdb)
2970                    return -EFBIG;
(gdb)
2969            if (unlikely(pos >= max_size))
(gdb)
2972            *count = min(*count, max_size - pos);
(gdb)
2974            return 0;
(gdb)
2972            *count = min(*count, max_size - pos);
(gdb)
generic_write_checks (from=<optimized out>, iocb=<optimized out>) at mm/filemap.c:3003
3003            if (ret)
(gdb)
3004                    return ret;
(gdb)
3003            if (ret)
(gdb)
3006            iov_iter_truncate(from, count);
(gdb)
iov_iter_truncate (count=<optimized out>, i=<optimized out>) at ./include/linux/uio.h:252
252             if (i->count > count)
(gdb)
generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3487
3487            if (ret > 0)
(gdb)
3488                    ret = __generic_file_write_iter(iocb, from);
(gdb)
__generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3393
3393            struct file *file = iocb->ki_filp;
(gdb)
3401            current->backing_dev_info = inode_to_bdi(inode);
(gdb)
3394            struct address_space * mapping = file->f_mapping;
(gdb)
3401            current->backing_dev_info = inode_to_bdi(inode);
(gdb)
inode_to_bdi (inode=<optimized out>) at ./include/linux/backing-dev.h:160
160                     return &noop_backing_dev_info;
(gdb)
__generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3395
3395            struct inode    *inode = mapping->host;
(gdb)
3401            current->backing_dev_info = inode_to_bdi(inode);
(gdb)
inode_to_bdi (inode=<optimized out>) at ./include/linux/backing-dev.h:159
159             if (!inode)
(gdb)
162             sb = inode->i_sb;
(gdb)
164             if (sb_is_blkdev_sb(sb))
(gdb)
167             return sb->s_bdi;
(gdb)
__generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3401
3401            current->backing_dev_info = inode_to_bdi(inode);
(gdb)
3402            err = file_remove_privs(file);
(gdb)
file_remove_privs (file=0x7fe03e88be00) at fs/inode.c:1828
1828            struct dentry *dentry = file_dentry(file);
(gdb)
file_dentry (file=<optimized out>) at ./include/linux/fs.h:1305
1305            return d_real(file->f_path.dentry, file_inode(file));
(gdb)
file_inode (f=<optimized out>) at ./include/linux/fs.h:1300
1300            return f->f_inode;
(gdb)
file_dentry (file=<optimized out>) at ./include/linux/fs.h:1305
1305            return d_real(file->f_path.dentry, file_inode(file));
(gdb)
d_real (inode=<optimized out>, dentry=<optimized out>) at ./include/linux/dcache.h:575
575             if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
(gdb)
file_remove_privs (file=0x7fe03e88be00) at fs/inode.c:1839
1839            if (IS_NOSEC(inode) || !S_ISREG(inode->i_mode))
(gdb)
1842            kill = dentry_needs_remove_privs(dentry);
(gdb)
dentry_needs_remove_privs (dentry=<optimized out>) at fs/inode.c:1798
1798            if (IS_NOSEC(inode))
(gdb)
dentry_needs_remove_privs (dentry=0x7fe040099900) at fs/inode.c:1792
1792    int dentry_needs_remove_privs(struct dentry *dentry)
(gdb)
1801            mask = should_remove_suid(dentry);
(gdb)
should_remove_suid (dentry=0x7fe040099900) at fs/inode.c:1766
1766            umode_t mode = d_inode(dentry)->i_mode;
(gdb)
1770            if (unlikely(mode & S_ISUID))
(gdb)
1777            if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
(gdb)
1783            return 0;
(gdb)
1784    }
(gdb)
dentry_needs_remove_privs (dentry=0x7fe040099900) at fs/inode.c:1802
1802            ret = security_inode_need_killpriv(dentry);
(gdb)
security_inode_need_killpriv (dentry=<optimized out>) at ./include/linux/security.h:781
781             return cap_inode_need_killpriv(dentry);
(gdb)
dentry_needs_remove_privs (dentry=0x7fe040099900) at fs/inode.c:1801
1801            mask = should_remove_suid(dentry);
(gdb)
1802            ret = security_inode_need_killpriv(dentry);
(gdb)
security_inode_need_killpriv (dentry=<optimized out>) at ./include/linux/security.h:781
781             return cap_inode_need_killpriv(dentry);
(gdb)
cap_inode_need_killpriv (dentry=0x7fe040099900) at security/commoncap.c:296
296     {
(gdb)
300             error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
(gdb)
296     {
(gdb)
300             error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
(gdb)
__vfs_getxattr (dentry=0x7fe040099900, inode=0x7fe04009a648, name=0x7fe0006bce98 "security.capability", value=0x0, size=0) at fs/xattr.c:306
306             handler = xattr_resolve_name(inode, &name);
(gdb)
303     {
(gdb)
306             handler = xattr_resolve_name(inode, &name);
(gdb)
303     {
(gdb)
306             handler = xattr_resolve_name(inode, &name);
(gdb)
xattr_resolve_name (inode=0x7fe04009a648, name=0x7fe040b02a38) at fs/xattr.c:59
59              if (!(inode->i_opflags & IOP_XATTR)) {
(gdb)
55      {
(gdb)
xattr_resolve_name (inode=0x7fe04009a648, name=0x7fe040b02a38) at fs/xattr.c:60
60                      if (unlikely(is_bad_inode(inode)))
(gdb)
is_bad_inode (inode=0x7fe04009a648) at fs/bad_inode.c:226
226             return (inode->i_op == &bad_inode_ops);
(gdb)
225     {
(gdb)
is_bad_inode (inode=0x7fe04009a648) at fs/bad_inode.c:227
227     }
(gdb)
is_bad_inode (inode=0x7fe04009a648) at fs/bad_inode.c:226
226             return (inode->i_op == &bad_inode_ops);
(gdb)
227     }
(gdb)
xattr_resolve_name (inode=<optimized out>, name=<optimized out>) at fs/xattr.c:61
61                              return ERR_PTR(-EIO);
(gdb)
60                      if (unlikely(is_bad_inode(inode)))
(gdb)
62                      return ERR_PTR(-EOPNOTSUPP);
(gdb)
79      }
(gdb)
__vfs_getxattr (dentry=0x7fe040099900, inode=0x7fe04009a648, name=0x7fe0006bce98 "security.capability", value=0x0, size=0) at fs/xattr.c:307
307             if (IS_ERR(handler))
(gdb)
312     }
(gdb)
cap_inode_need_killpriv (dentry=<optimized out>) at security/commoncap.c:301
301             return error > 0;
(gdb)
302     }
(gdb)
dentry_needs_remove_privs (dentry=0x7fe040099900) at fs/inode.c:1803
1803            if (ret < 0)
(gdb)
1806                    mask |= ATTR_KILL_PRIV;
(gdb)
1808    }
(gdb)
file_remove_privs (file=0x7fe03eab2c00) at fs/inode.c:1843
1843            if (kill < 0)
(gdb)
1845            if (kill)
(gdb)
1848                    inode_has_no_xattr(inode);
(gdb)
inode_has_no_xattr (inode=<optimized out>) at fs/inode.c:1848
1848                    inode_has_no_xattr(inode);
(gdb)
is_sxid (mode=<optimized out>) at ./include/linux/fs.h:3462
3462            return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP));
(gdb)
inode_has_no_xattr (inode=<optimized out>) at ./include/linux/fs.h:3475
3475            if (!is_sxid(inode->i_mode) && (inode->i_sb->s_flags & SB_NOSEC))
(gdb)
file_remove_privs (file=0x7fe04009a648) at fs/inode.c:1848
1848                    inode_has_no_xattr(inode);
(gdb)
inode_has_no_xattr (inode=<optimized out>) at ./include/linux/fs.h:3476
3476                    inode->i_flags |= S_NOSEC;
(gdb)
file_remove_privs (file=0x7fe04009a648) at fs/inode.c:1851
1851    }
(gdb)
(gdb)
__generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02a38) at mm/filemap.c:3403
3403            if (err)
(gdb)
3406            err = file_update_time(file);
(gdb)
file_update_time (file=0x7fe03e88be00) at fs/inode.c:1869
1869            struct inode *inode = file_inode(file);
(gdb)
file_inode (f=<optimized out>) at ./include/linux/fs.h:1300
1300            return f->f_inode;
(gdb)
file_update_time (file=0x7fe03e88be00) at fs/inode.c:1875
1875            if (IS_NOCMTIME(inode))
(gdb)
1878            now = current_time(inode);
(gdb)
1880                    sync_it = S_MTIME;
(gdb)
1878            now = current_time(inode);
(gdb)
current_time (inode=0x7fe04009a648) at fs/inode.c:2183
2183            ktime_get_coarse_real_ts64(&now);
(gdb)
2180    {
(gdb)
2183            ktime_get_coarse_real_ts64(&now);
(gdb)
ktime_get_coarse_real_ts64 (ts=0x7fe040b02aa0) at kernel/time/timekeeping.c:2166
2166                    seq = read_seqcount_begin(&tk_core.seq);
(gdb)
read_seqcount_begin (s=<optimized out>) at kernel/time/timekeeping.c:2166
2166                    seq = read_seqcount_begin(&tk_core.seq);
(gdb)
raw_read_seqcount_begin (s=<optimized out>) at kernel/time/timekeeping.c:2166
2166                    seq = read_seqcount_begin(&tk_core.seq);
(gdb)
__read_seqcount_begin (s=<optimized out>) at kernel/time/timekeeping.c:2166
2166                    seq = read_seqcount_begin(&tk_core.seq);
(gdb)
__read_once_size (size=<optimized out>, res=<optimized out>, p=<optimized out>) at ./include/linux/compiler.h:199
199             __READ_ONCE_SIZE;
(gdb)
(gdb)
__read_seqcount_begin (s=<optimized out>) at ./include/linux/seqlock.h:114
114             if (unlikely(ret & 1)) {
(gdb)
ktime_get_coarse_real_ts64 (ts=0x7fe040b02aa0) at kernel/time/timekeeping.c:2168
2168                    *ts = tk_xtime(tk);
(gdb)
tk_xtime (tk=<optimized out>) at kernel/time/timekeeping.c:112
112             ts.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
(gdb)
ktime_get_coarse_real_ts64 (ts=0x7fe040b02aa0) at kernel/time/timekeeping.c:2168
2168                    *ts = tk_xtime(tk);
(gdb)
2169            } while (read_seqcount_retry(&tk_core.seq, seq));
(gdb)
2170    }
(gdb)
current_time (inode=0x7fe04009a648) at fs/inode.c:2185
2185            if (unlikely(!inode->i_sb)) {
(gdb)
2190            return timespec64_trunc(now, inode->i_sb->s_time_gran);
(gdb)
timespec64_trunc (t=..., gran=1) at fs/inode.c:2154
2154    {
(gdb)
2156            if (gran == 1) {
(gdb)
2154    {
(gdb)
timespec64_trunc (t=..., gran=1) at fs/inode.c:2156
2156            if (gran == 1) {
(gdb)
2166    }
(gdb)
current_time (inode=0x7fe04009a648) at fs/inode.c:2191
2191    }
(gdb)
file_update_time (file=0x7fe03e88be00) at fs/inode.c:1879
1879            if (!timespec64_equal(&inode->i_mtime, &now))
(gdb)
timespec64_equal (b=<optimized out>, a=<optimized out>) at ./include/linux/time64.h:50
50              return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
(gdb)
(gdb)
file_update_time (file=0x7fe03e88be00) at fs/inode.c:1871
1871            int sync_it = 0;
(gdb)
1882            if (!timespec64_equal(&inode->i_ctime, &now))
(gdb)
timespec64_equal (b=<optimized out>, a=<optimized out>) at ./include/linux/time64.h:50
50              return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
(gdb)
1885            if (IS_I_VERSION(inode) && inode_iversion_need_inc(inode))
(gdb)
1888            if (!sync_it)
(gdb)
1876                    return 0;
(gdb)
1899    }
(gdb)
__generic_file_write_iter (iocb=0x7fe040b02bc0, from=0x7fe040b02c70) at mm/filemap.c:3407
3407            if (err)
(gdb)
3410            if (iocb->ki_flags & IOCB_DIRECT) {
(gdb)
3456                    written = generic_perform_write(file, from, iocb->ki_pos);
(gdb)
generic_perform_write (file=0x7fe03e88be00, i=0x7fe040b02c70, pos=0) at mm/filemap.c:3289
3289            struct address_space *mapping = file->f_mapping;
(gdb)
3288    {
(gdb)
3292            ssize_t written = 0;
(gdb)
3290            const struct address_space_operations *a_ops = mapping->a_ops;
(gdb)
3327                    status = a_ops->write_begin(file, mapping, pos, bytes, flags,
(gdb)
3290            const struct address_space_operations *a_ops = mapping->a_ops;
(gdb)
3327                    status = a_ops->write_begin(file, mapping, pos, bytes, flags,
(gdb)
3302                    offset = (pos & (PAGE_SIZE - 1));
(gdb)
3303                    bytes = min_t(unsigned long, PAGE_SIZE - offset,
(gdb)
3302                    offset = (pos & (PAGE_SIZE - 1));
(gdb)
3303                    bytes = min_t(unsigned long, PAGE_SIZE - offset,
(gdb)
3317                    if (unlikely(iov_iter_fault_in_readable(i, bytes))) {
(gdb)
iov_iter_fault_in_readable (i=0x7fe040b02c70, bytes=4096) at lib/iov_iter.c:425
425             if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
(gdb)
419     {
(gdb)
iov_iter_fault_in_readable (i=0x7fe040b02c70, bytes=4096) at lib/iov_iter.c:426
426                     iterate_iovec(i, bytes, v, iov, skip, ({
(gdb)
420             size_t skip = i->iov_offset;
(gdb)
419     {
(gdb)
426                     iterate_iovec(i, bytes, v, iov, skip, ({
(gdb)
fault_in_pages_readable (size=<optimized out>, uaddr=<optimized out>) at ./include/linux/pagemap.h:573
573             const char __user *end = uaddr + size - 1;
(gdb)
575             if (unlikely(size == 0))
(gdb)
iov_iter_fault_in_readable (i=0x7fe040b02c70, bytes=4096) at lib/iov_iter.c:426
426                     iterate_iovec(i, bytes, v, iov, skip, ({
(gdb)
fault_in_pages_readable (size=<optimized out>, uaddr=<optimized out>) at ./include/linux/pagemap.h:573
573             const char __user *end = uaddr + size - 1;
(gdb)
575             if (unlikely(size == 0))
(gdb)
578             if (unlikely(uaddr > end))
(gdb)
582                     if (unlikely(__get_user(c, uaddr) != 0))
(gdb)

Thread 6 "ENCLAVE" received signal SIGSEGV, Segmentation fault.
fault_in_pages_readable (size=<optimized out>, uaddr=<optimized out>) at ./include/linux/pagemap.h:582
582                     if (unlikely(__get_user(c, uaddr) != 0))
(gdb)
_host_signal_handler (sig_num=0, sig_info=0x0, sig_data=0x0) at /mnt/shaik/1108/sgx-lkl/openenclave/host/sgx/linux/exception.c:34

What is the invalid address? Is it inside the enclave? Until we are using LKL’s mmap, we have a very conservative response to access ok and will allow any access inside the enclave, even to kernel memory.

Okay, looking at the code, I understand this a bit better:

  • The test allocates a page with PROT_NONE
  • The writev call is called with a pointer to this page.
  • LKL tries to read from it and receives a trap.

This is precisely expected with the current code. The enclave_mmap implementation does not track page permissions (which causes some other issues as well) and so we can't usefully return failure in lkl_access_ok.

I think this will Just Work(tm) once #597 is fixed, so I think this it is low priority to make it work with the existing enclave_mem code.

To add on, I think that fixing anything "largish" that isn't horribly broken in enclave_mmap would be time better spent on making #597 happen.