Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIGSEGV on parsing parameters #1

Closed
ptef opened this issue Jun 14, 2023 · 6 comments
Closed

SIGSEGV on parsing parameters #1

ptef opened this issue Jun 14, 2023 · 6 comments

Comments

@ptef
Copy link

ptef commented Jun 14, 2023

Hi,

A SIGGEGV is happening in the following scenario:

$ ./cryptmount --umount research
Segmentation fault (core dumped)

I investigated a little bit and apparently the problem is happening inside parse_options() when calling libc getopts_long() . Please check below the output on gdb (I redacted some verbose output):

$ gdb ./cryptmount  -d .
gef➤  set args --umount research
gef➤  b cryptmount.c:1388
gef➤  r
[...]
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x00007fffffffd7cc  →  0x0000000000000000
$rbx   : 0x0               
$rcx   : 0x000055555556e3c0  →  0x0000555555563134  →  0x6e616863006c6c61 ("all"?)
$rdx   : 0x000055555556e380  →  "acf:g:hklmw:pre:nSsxBQuyv"
$rsp   : 0x00007fffffffd780  →  0x000055555556ccd0  →  0x00780074706b7564 ("dukpt"?)
$rbp   : 0x000055555556e380  →  "acf:g:hklmw:pre:nSsxBQuyv"
$rsi   : 0x00007fffffffde28  →  0x00007fffffffe1a9  →  "/home/dukpt/Downloads/cryptmount/cryptmount"
$rdi   : 0x3               
$rip   : 0x000055555555acc4  →  <parse_options+1284> call 0x555555557b50 <getopt_long@plt>
$r8    : 0x00007fffffffd7cc  →  0x0000000000000000
$r9    : 0x000055555556e3c0  →  0x0000555555563134  →  0x6e616863006c6c61 ("all"?)
$r10   : 0x00007ffff7dbcac0  →  0x0000000100000000
$r11   : 0x00007ffff7e17ce0  →  0x000055555556e680  →  0x0a3a3432313a783a (":x:124:\n"?)
$r12   : 0x000055555556e3c0  →  0x0000555555563134  →  0x6e616863006c6c61 ("all"?)
$r13   : 0x00005555555654b5  →  "cryptmount"
$r14   : 0x0000555555568a18  →  0x0000555555559700  →  <__do_global_dtors_aux+0> endbr64 
$r15   : 0x00007fffffffdb28  →  0x000000000000003f ("?"?)
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffd780│+0x0000: 0x000055555556ccd0  →  0x00780074706b7564 ("dukpt"?)	 ← $rsp
0x00007fffffffd788│+0x0008: 0x00007fffffffde28  →  0x00007fffffffe1a9  →  "/home/dukpt/Downloads/cryptmount/cryptmount"
0x00007fffffffd790│+0x0010: 0x00007fffffffd7cc  →  0x0000000000000000
0x00007fffffffd798│+0x0018: 0x00007fffffffd7e0  →  0x0000000000000061 ("a"?)
0x00007fffffffd7a0│+0x0020: 0x0000000000000003
0x00007fffffffd7a8│+0x0028: 0x00007ffff7e14600  →  0x0000000000000000
0x00007fffffffd7b0│+0x0030: 0x00007fffffffdbec  →  0x00000000ffffffff
0x00007fffffffd7b8│+0x0038: 0x00007fffffffdbe8  →  0xffffffffffffffff
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x55555555acb9 <parse_options+1273> mov    rdx, rbp
   0x55555555acbc <parse_options+1276> mov    rcx, r12
   0x55555555acbf <parse_options+1279> mov    rsi, QWORD PTR [rsp+0x8]
 → 0x55555555acc4 <parse_options+1284> call   0x555555557b50 <getopt_long@plt>
   ↳  0x555555557b50 <getopt_long@plt+0> endbr64 
      0x555555557b54 <getopt_long@plt+4> bnd    jmp QWORD PTR [rip+0x1133d]        # 0x555555568e98 <getopt_long@got.plt>
      0x555555557b5b <getopt_long@plt+11> nop    DWORD PTR [rax+rax*1+0x0]
      0x555555557b60 <fread@plt+0>    endbr64 
      0x555555557b64 <fread@plt+4>    bnd    jmp QWORD PTR [rip+0x11335]        # 0x555555568ea0 <fread@got.plt>
      0x555555557b6b <fread@plt+11>   nop    DWORD PTR [rax+rax*1+0x0]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── arguments (guessed) ────
getopt_long@plt (
   $rdi = 0x0000000000000003,
   $rsi = 0x00007fffffffde28 → 0x00007fffffffe1a9 → "/home/dukpt/Downloads/cryptmount/cryptmount",
   $rdx = 0x000055555556e380 → "acf:g:hklmw:pre:nSsxBQuyv",
   $rcx = 0x000055555556e3c0 → 0x0000555555563134 → 0x6e616863006c6c61 ("all"?),
   $r8 = 0x00007fffffffd7cc → 0x0000000000000000
)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:cryptmount.c+1388 ────
   1383	 #endif  /* _GNU_SOURCE */
   1384	 
   1385	     for (;;) {
   1386	         struct cm_option *selected;
   1387	 #ifdef _GNU_SOURCE
●→ 1388	         optchar = getopt_long(argc, argv, shortopts, longopts, &idx);
   1389	 #else
   1390	         optchar = getopt(argc, argv, shortopts);
   1391	 #endif
   1392	         if (optchar < 0 || optchar == '?') break;
   1393	         idx = 0;
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "cryptmount", stopped 0x55555555acc4 in parse_options (), reason: SINGLE STEP
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x55555555acc4 → parse_options(argc=0x3, argv=0x7fffffffde28, mode_params=0x7fffffffdbf8, passwd_fd=0x7fffffffdbec, config_fd=0x7fffffffdbe8, pw_ctxt=0x7fffffffdc30)
[#1] 0x555555557ea9 → main(argc=0x3, argv=0x7fffffffde28)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

After that, if you continue a SIGSEGV will happen:

$rax   : 0x1ff             
$rbx   : 0x000055555556e660  →  0x6b75643a3232313a (":122:duk"?)
$rcx   : 0x15              
$rdx   : 0x0               
$rsp   : 0x00007fffffffd5d8  →  0x00007ffff7d05ea1  →  <process_long_option+209> test eax, eax
$rbp   : 0x00007fffffffd6a0  →  0x0000000000000003
$rsi   : 0x00007fffffffe1d7  →  0x7200746e756f6d75 ("umount"?)
$rdi   : 0x6b75643a3232313a (":122:duk"?)
$rip   : 0x00007ffff7d96f31  →  <__strncmp_avx2+49> vmovdqu ymm1, YMMWORD PTR [rdi]
$r8    : 0x00007fffffffd7cc  →  0x0000000000000000
$r9    : 0x0               
$r10   : 0x00007ffff7dbcac0  →  0x0000000100000000
$r11   : 0x6               
$r12   : 0x6b75643a3232313a (":122:duk"?)
$r13   : 0x15              
$r14   : 0x6               
$r15   : 0x00007fffffffe1d7  →  0x7200746e756f6d75 ("umount"?)
$eflags: [zero CARRY parity adjust SIGN trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffd5d8│+0x0000: 0x00007ffff7d05ea1  →  <process_long_option+209> test eax, eax	 ← $rsp
0x00007fffffffd5e0│+0x0008: 0x0000000000000000
0x00007fffffffd5e8│+0x0010: 0x0000000000000000
0x00007fffffffd5f0│+0x0018: 0x00000000000004c2
0x00007fffffffd5f8│+0x0020: 0x0000000000000600
0x00007fffffffd600│+0x0028: 0x000000000000000a ("\n"?)
0x00007fffffffd608│+0x0030: 0x00007ffff7dd7ee1  →  0x69203a7325002d2d ("--"?)
0x00007fffffffd610│+0x0038: 0x7500000000000003
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x7ffff7d96f21 <__strncmp_avx2+33> and    eax, 0xfff
   0x7ffff7d96f26 <__strncmp_avx2+38> cmp    eax, 0xf80
   0x7ffff7d96f2b <__strncmp_avx2+43> jg     0x7ffff7d97330 <__strncmp_avx2+1072>
 → 0x7ffff7d96f31 <__strncmp_avx2+49> vmovdqu ymm1, YMMWORD PTR [rdi]
   0x7ffff7d96f35 <__strncmp_avx2+53> vpcmpeqb ymm0, ymm1, YMMWORD PTR [rsi]
   0x7ffff7d96f39 <__strncmp_avx2+57> vpminub ymm0, ymm0, ymm1
   0x7ffff7d96f3d <__strncmp_avx2+61> vpcmpeqb ymm0, ymm0, ymm7
   0x7ffff7d96f41 <__strncmp_avx2+65> vpmovmskb ecx, ymm0
   0x7ffff7d96f45 <__strncmp_avx2+69> test   ecx, ecx
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "cryptmount", stopped 0x7ffff7d96f31 in __strncmp_avx2 (), reason: SIGSEGV
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7ffff7d96f31 → __strncmp_avx2()
[#1] 0x7ffff7d05ea1 → process_long_option(argc=0x3, argv=0x7fffffffde28, optstring=0x55555556e380 "acf:g:hklmw:pre:nSsxBQuyv", longopts=0x55555556e3c0, longind=0x7fffffffd7cc, long_only=0x0, d=0x7ffff7e1f180 <getopt_data>, print_errors=0x1, prefix=0x7ffff7dd7ee1 "--")
[#2] 0x7ffff7d0688f → _getopt_internal_r(argc=0x3, argv=0x7fffffffde28, optstring=0x55555556e380 "acf:g:hklmw:pre:nSsxBQuyv", longopts=0x55555556e3c0, longind=0x7fffffffd7cc, long_only=0x0, d=0x7ffff7e1f180 <getopt_data>, posixly_correct=0x0)
[#3] 0x7ffff7d06aeb → _getopt_internal(argc=0x3, argv=0x7fffffffde28, optstring=0x55555556e380 "acf:g:hklmw:pre:nSsxBQuyv", longopts=0x55555556e3c0, longind=0x7fffffffd7cc, long_only=0x0, posixly_correct=0x0)
[#4] 0x7ffff7d06b72 → getopt_long(argc=0x3, argv=0x7fffffffde28, options=0x55555556e380 "acf:g:hklmw:pre:nSsxBQuyv", long_options=0x55555556e3c0, opt_index=0x7fffffffd7cc)
[#5] 0x55555555acc9 → parse_options(argc=0x3, argv=0x7fffffffde28, mode_params=0x7fffffffdbf8, passwd_fd=0x7fffffffdbec, config_fd=0x7fffffffdbe8, pw_ctxt=0x7fffffffdc30)
[#6] 0x555555557ea9 → main(argc=0x3, argv=0x7fffffffde28)
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  

Maybe there some issue with the structure size.
The same bug happens within distro version of cryptmount.

I compiled the last code from master and I'm running Ubuntu 22.04.2 (jammy).

Thanks

@rwpenney
Copy link
Owner

rwpenney commented Jun 15, 2023

Thanks for the stack traces.
I may well need more information about exactly how you're getting this error. Firstly, there's plenty of evidence that the --unmount or -u options do work both when a target has already mounted, or when an unknown or unmounted target is requested for unmounting. Your test scenario uses --umount rather than --unmount (missing an "n") - I'm not sure if that's significant, or a minor typo rather than a copy-paste of your actual test? I've just run some basic tests on a fresh Ubuntu-22.04.2 system, and haven't found any obvious problems.
Can you share a bit more detail about how you've configured and compiled cryptmount, and whether there's anything unusual in your cmtab about the setup of your encrypted filesystem?

@ptef
Copy link
Author

ptef commented Jun 16, 2023

Hi,

In a typical scenario it works fine:

$ cryptmount research
Enter password for target "research": 
e2fsck 1.46.5 (30-Dec-2021)
/dev/mapper/research: clean, 66641/1281120 files, 930608/5120000 blocks
$ ls -la /research | wc -l
15
$ cryptmount -u research
$ ls -la /research | wc -l
3
$ ls -la /research 
total 18
dr-x------  2 dukpt root  2 Mai 29 17:52 .
drwxr-xr-x 22 root  root 28 Jun  4 17:12 ..
$

Tbh I haven't noticed that it was a typo until you tell me now (old habits from traditional Linux umount).
Then I tested other "typos":

$ cryptmount -u research
Target "research" does not appear to be mounted
$ cryptmount --unmount research # indeed it doesn't crash
Target "research" does not appear to be mounted
$ cryptmount --nmount research # typo number 1
Segmentation fault (core dumped)
$ cryptmount --umount research # typo number 2
Segmentation fault (core dumped)
$ cryptmount --lalalla research # whatever not recognized option
Segmentation fault (core dumped)
$ 

Initially, I thought this could be an error on getopt_long from libc, but after some tests I think it's just the way the parameters are being parsed in the structure.

I'm using cryptmount from distro repo.

$ dpkg-query -L cryptmount 
/.
/etc
/etc/cryptmount
/etc/cryptmount/cmtab
/etc/modules-load.d
/etc/modules-load.d/cryptmount.conf
/lib
/lib/systemd
/lib/systemd/system
/lib/systemd/system/cryptmount.service
/usr
/usr/bin
/usr/bin/cryptmount
/usr/sbin
/usr/sbin/cryptmount-setup
/usr/share
/usr/share/doc
/usr/share/doc/cryptmount
/usr/share/doc/cryptmount/NEWS.gz
/usr/share/doc/cryptmount/README.gz
/usr/share/doc/cryptmount/README.sshfs
/usr/share/doc/cryptmount/RELNOTES.gz
/usr/share/doc/cryptmount/ToDo
/usr/share/doc/cryptmount/changelog.Debian.gz
/usr/share/doc/cryptmount/copyright
/usr/share/doc/cryptmount/examples
/usr/share/doc/cryptmount/examples/cmtab
/usr/share/lintian
/usr/share/lintian/overrides
/usr/share/lintian/overrides/cryptmount
/usr/share/locale
/usr/share/locale/de
/usr/share/locale/de/LC_MESSAGES
/usr/share/locale/de/LC_MESSAGES/cryptmount.mo
/usr/share/locale/fr
/usr/share/locale/fr/LC_MESSAGES
/usr/share/locale/fr/LC_MESSAGES/cryptmount.mo
/usr/share/man
/usr/share/man/fr
/usr/share/man/fr/man5
/usr/share/man/fr/man5/cmtab.5.gz
/usr/share/man/fr/man8
/usr/share/man/fr/man8/cryptmount.8.gz
/usr/share/man/man5
/usr/share/man/man5/cmtab.5.gz
/usr/share/man/man8
/usr/share/man/man8/cryptmount-setup.8.gz
/usr/share/man/man8/cryptmount.8.gz

@rwpenney
Copy link
Owner

rwpenney commented Jun 17, 2023

Thanks - I think you're right that the initialization of the longopts array wasn't right, and didn't correctly pad this with zeros. I've now replaced (in c2aa81d) a call to malloc() with calloc() which should fix this issue. I suspect that the bug was most likely to trigger when passing an invalid command-line argument, as that is likely to require getopt_long() to visit all entries in the longopts array rather than stopping whenever it finds a matching entry.
Could you try the latest version on master and let me know if it behaves better on your Ubuntu-22.04 system?

@ptef
Copy link
Author

ptef commented Jun 17, 2023

Hi Richard.
Yes, apparently it's fixed, I couldn't reproduced the bug anymore. Thanks for the quick fix!
Could you please raise a CVE for that? Maybe negotiating with Canonical since they're Root CNA as well and cryptmount is available from their repo as well.

Thank you.

@rwpenney
Copy link
Owner

Thanks - I've submitted a bug report covering the Ubuntu package linking to this page and supplying a patch.

@ptef
Copy link
Author

ptef commented Jun 20, 2023

Could you provide access to user dukpt?
Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants