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

Allow disabling character set filtering #113

Merged
merged 15 commits into from
Jun 16, 2024

Conversation

DemiMarie
Copy link
Contributor

This allows copying paths with names that would otherwise be forbidden.
This requires adding new APIs, so take the opportunity to provide more
useful information about why a path was rejected.

To ensure that internal invariants are not violated, this uses a new
COMPILETIME_UNREACHABLE macro to validate that a statement can be proven
unreachable by the compiler. This is superior to abort() because it is
checked at compile-time by the optimizer: if the compiler cannot prove
that the code is unreachable, the build will fail. This technique is
also used by BUILD_BUG_ON() in the Linux kernel. Since compilers do not
promise to always be able to prove a piece of code unreachable, static
checking is disabled by default. It can be enabled by including
CHECK_UNREACHABLE=1 in the build environment.

This is part of QubesOS/qubes-issues#8332 (less restricted qfile-copy),
but that issue also requires changes to qfile-unpacker (part of
qubes-core-agent-linux) to fix. The code is both backwards and forwards
compatible: Old qfile-unpacker versions will work fine with the new
library, and new qfile-unpacker versions will work fine with the old
library. However, qubes.UnsafeFileCopy will behave like qubes.Filecopy
unless the library has been updated.

Initially, I decided to unconditionally disallow ASCII control
characters in filenames, even if other character set filtering is
disabled. This is because they are very useful for exploits and not
very useful for other purposes. However, they can still arise in
practice for completely legitimate reasons. These include copying and
pasting into a file name in a GUI file manager and deliberately creating
strangely-named files for test purposes. Therefore, disabling filtering
now disables all character set filtering. Restrictions to prevent
directory traversal are still enforced, though, because violations of
these are much more likely to be exploitable. While symlinks that point
outside of the directory being copied might arise legitimately, they
will not be meaningful after being copied and do allow an attacker to
cause mischief. For instance, if a symlink points to
/home/user/.bashrc, "cp a b" in a directory copied by qvm-copy could
overwrite ~/.bashrc with attacker-controlled data. The checks on
symlink paths prevent this.

DemiMarie added a commit to DemiMarie/qubes-core-agent-linux that referenced this pull request May 9, 2024
This uses QREXEC_SERVICE_FULL_NAME to detect what the service was
invoked as.  Non-empty arguments are reserved for future use.

This requires QubesOS/qubes-linux-utils#113.

Fixes: QubesOS/qubes-issues#8332
@marmarek
Copy link
Member

While symlinks that point
outside of the directory being copied might arise legitimately, they
will not be meaningful after being copied and do allow an attacker to
cause mischief

See task description - please add a flag to disable this part too (do expose it as an option for qfile-unpacker but do not enable it for qubes.UnsafeFilecopy).

@DemiMarie
Copy link
Contributor Author

While symlinks that point
outside of the directory being copied might arise legitimately, they
will not be meaningful after being copied and do allow an attacker to
cause mischief

See task description - please add a flag to disable this part too (do expose it as an option for qfile-unpacker but do not enable it for qubes.UnsafeFilecopy).

Will do. I’ll keep validating the paths from the source VM, though. These are produced by qfile-agent, so they will be well-formed no matter what is being copied.

@codecov-commenter
Copy link

codecov-commenter commented May 10, 2024

Codecov Report

Attention: Patch coverage is 91.04478% with 6 lines in your changes missing coverage. Please review.

Project coverage is 79.45%. Comparing base (5582539) to head (044c4d4).
Report is 3 commits behind head on main.

Files Patch % Lines
qrexec-lib/unicode.c 91.11% 4 Missing ⚠️
qrexec-lib/validator-test.c 90.90% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #113      +/-   ##
==========================================
+ Coverage   77.35%   79.45%   +2.09%     
==========================================
  Files           5        5              
  Lines         424      477      +53     
==========================================
+ Hits          328      379      +51     
- Misses         96       98       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@DemiMarie DemiMarie force-pushed the allow-less-secure branch from f40aeb8 to 75dc93d Compare May 12, 2024 17:05
DemiMarie added a commit to DemiMarie/qubes-core-agent-linux that referenced this pull request May 14, 2024
qrexec-lib/validator-test.c Show resolved Hide resolved
qrexec-lib/validator-test.c Outdated Show resolved Hide resolved
DemiMarie added a commit to DemiMarie/qubes-core-agent-linux that referenced this pull request May 15, 2024
This requires QubesOS/qubes-linux-utils#113.  It also adds a new
argument parser based on getopt_long(), which is used instead of the old
hand-rolled code unless there are at least two arguments and the first
one starts with an ASCII digit.

Part of QubesOS/qubes-issues#8332
@DemiMarie DemiMarie force-pushed the allow-less-secure branch from 75dc93d to a4369a0 Compare May 15, 2024 19:32
@marmarek marmarek added the openqa-pending PR to be tested in the next OpenQA run label May 17, 2024
@qubesos-bot
Copy link

qubesos-bot commented May 17, 2024

OpenQA test summary

Complete test suite and dependencies: https://openqa.qubes-os.org/tests/overview?distri=qubesos&version=4.3&build=2024061510-4.3&flavor=pull-requests

Test run included the following:

New failures, excluding unstable

Compared to: https://openqa.qubes-os.org/tests/overview?distri=qubesos&version=4.3&build=2024052808-4.3&flavor=update

  • system_tests_usbproxy

  • system_tests_basic_vm_qrexec_gui_ext4

  • system_tests_guivm_vnc_gui_interactive

    • simple_gui_apps: unnamed test (unknown)

    • simple_gui_apps: Failed (test died)
      # Test died: no candidate needle with tag(s) 'menu-vm-evince, work-...

    • simple_gui_apps: unnamed test (unknown)

Failed tests

13 failures
  • system_tests_basic_vm_qrexec_gui

    • [unstable] TC_20_AudioVM_Pulse_whonix-workstation-17: test_220_audio_play_pulseaudio (failure)
      AssertionError: too short audio, expected 10s, got 8.86233560090702...

    • [unstable] TC_20_AudioVM_Pulse_whonix-workstation-17: test_222_audio_rec_unmuted_pulseaudio (failure)
      AssertionError: too short audio, expected 10s, got 9.36342403628118...

  • system_tests_pvgrub_salt_storage

    • TC_41_HVMGrub_fedora-40-xfce: test_000_standalone_vm (error)
      qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...

    • TC_41_HVMGrub_fedora-40-xfce: test_010_template_based_vm (error)
      qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...

  • system_tests_splitgpg

  • system_tests_extra

    • [unstable] TC_00_QVCTest_debian-12-xfce: test_020_webcam (failure)
      AssertionError: 'qubes-video-companion webcam' exited early (0): b'...

    • [unstable] TC_00_QVCTest_fedora-40-xfce: test_020_webcam (failure)
      AssertionError: 'qubes-video-companion webcam' exited early (0): b'...

    • [unstable] TC_00_QVCTest_whonix-workstation-17: test_020_webcam (failure)
      AssertionError: 'qubes-video-companion webcam' exited early (0): b'...

  • system_tests_usbproxy

  • system_tests_basic_vm_qrexec_gui_ext4

  • system_tests_guivm_vnc_gui_interactive

    • simple_gui_apps: unnamed test (unknown)

    • simple_gui_apps: Failed (test died)
      # Test died: no candidate needle with tag(s) 'menu-vm-evince, work-...

    • simple_gui_apps: unnamed test (unknown)

Fixed failures

Compared to: https://openqa.qubes-os.org/tests/101100#dependencies

37 fixed
  • system_tests_basic_vm_qrexec_gui

  • system_tests_pvgrub_salt_storage

    • StorageFile: test_001_non_volatile (error)
      subprocess.CalledProcessError: Command '/usr/lib/qubes/destroy-snap...
  • system_tests_extra

    • TC_00_QVCTest_whonix-workstation-17: test_010_screenshare (failure)
      self.assertNotEqual(vm.run('test -e /dev/vid... AssertionError: 0 == 0
  • system_tests_usbproxy

  • system_tests_network_updates

    • TC_00_Dom0Upgrade_whonix-gateway-17: test_006_update_flag_clear (failure)
      Error: Failed to download metadata for repo 'test': Cannot download...

    • TC_10_QvmTemplate_debian-12-xfce: test_010_template_install (failure)
      AssertionError: qvm-template failed: Downloading 'qubes-template-de...

    • TC_10_QvmTemplate_fedora-40-xfce: test_010_template_install (failure)
      AssertionError: qvm-template failed: Downloading 'qubes-template-de...

    • TC_10_QvmTemplate_whonix-gateway-17: test_010_template_install (failure)
      AssertionError: qvm-template failed: Downloading 'qubes-template-de...

    • TC_11_QvmTemplateMgmtVM_debian-12-xfce: test_010_template_install (failure)
      AssertionError: qvm-template failed: Downloading 'qubes-template-de...

    • TC_11_QvmTemplateMgmtVM_fedora-40-xfce: test_010_template_install (failure)
      AssertionError: qvm-template failed: Downloading 'qubes-template-de...

    • TC_11_QvmTemplateMgmtVM_whonix-gateway-17: test_010_template_install (failure)
      AssertionError: qvm-template failed: Downloading 'qubes-template-de...

  • system_tests_basic_vm_qrexec_gui_zfs

  • system_tests_basic_vm_qrexec_gui_btrfs

  • system_tests_basic_vm_qrexec_gui_ext4

  • system_tests_basic_vm_qrexec_gui_xfs

  • system_tests_basic_vm_qrexec_gui@hw1

  • system_tests_guivm_gui_interactive

    • update_guivm: Failed (test died)
      # Test died: command '(set -o pipefail; qubesctl --all --show-outpu...

Unstable tests

  • system_tests_suspend

    suspend/ (2/4 times with errors)
    suspend/Failed (2/4 times with errors)
    • job 102431 # Test died: no candidate needle with tag(s) 'xscreensaver-prompt' ...
    • job 102443 # Test died: no candidate needle with tag(s) 'xscreensaver-prompt' ...
    suspend/wait_serial (2/4 times with errors)
    • job 102431 # wait_serial expected: qr/2E8vz-\d+-/...
    • job 102443 # wait_serial expected: qr/2E8vz-\d+-/...
  • system_tests_basic_vm_qrexec_gui

    TC_20_AudioVM_Pulse_whonix-workstation-17/test_220_audio_play_pulseaudio (2/2 times with errors)
    • job 101109 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    • job 101758 AssertionError: too short audio, expected 10s, got 8.73532879818594...
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_222_audio_rec_unmuted_pulseaudio (2/2 times with errors)
    • job 101109 AssertionError: only silence detected, no useful audio data
    • job 101758 AssertionError: too short audio, expected 10s, got 9.36446712018140...
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_223_audio_play_hvm (1/2 times with errors)
    • job 101109 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_252_audio_playback_audiovm_switch_hvm (1/2 times with errors)
    • job 101109 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
  • system_tests_pvgrub_salt_storage

    TC_41_HVMGrub_debian-12-xfce/test_000_standalone_vm (1/2 times with errors)
    • job 101773 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
    StorageFile/test_001_non_volatile (1/2 times with errors)
    • job 101124 subprocess.CalledProcessError: Command '/usr/lib/qubes/destroy-snap...
    TC_41_HVMGrub_debian-12-xfce/test_010_template_based_vm (1/2 times with errors)
    • job 101773 qubes.exc.QubesVMError: Cannot connect to qrexec agent for 120 seco...
  • system_tests_extra

    TC_00_QVCTest_whonix-workstation-17/test_010_screenshare (1/2 times with errors)
    • job 101116 self.assertNotEqual(vm.run('test -e /dev/vid... AssertionError: 0 == 0
    TC_00_QVCTest_debian-12-xfce/test_020_webcam (1/2 times with errors)
    • job 101116 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    TC_00_QVCTest_fedora-40-xfce/test_020_webcam (1/2 times with errors)
    • job 101765 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
    TC_00_QVCTest_whonix-workstation-17/test_020_webcam (1/2 times with errors)
    • job 101116 AssertionError: 'qubes-video-companion webcam' exited early (0): b'...
  • system_tests_usbproxy

    TC_20_USBProxy_core3_whonix-gateway-17/test_070_attach_not_installed_front (1/2 times with errors)
    • job 101101 qubesusbproxy.core3ext.QubesUSBException: Device attach failed: 202...
  • system_tests_network_updates

    TC_00_Dom0Upgrade_whonix-gateway-17/test_006_update_flag_clear (1/2 times with errors)
    • job 101123 Error: Failed to download metadata for repo 'test': Cannot download...
    TC_10_QvmTemplate_debian-12-xfce/test_010_template_install (1/2 times with errors)
    • job 101123 AssertionError: qvm-template failed: Downloading 'qubes-template-de...
    TC_10_QvmTemplate_fedora-40-xfce/test_010_template_install (1/2 times with errors)
    • job 101123 AssertionError: qvm-template failed: Downloading 'qubes-template-de...
    TC_10_QvmTemplate_whonix-gateway-17/test_010_template_install (1/2 times with errors)
    • job 101123 AssertionError: qvm-template failed: Downloading 'qubes-template-de...
    TC_11_QvmTemplateMgmtVM_debian-12-xfce/test_010_template_install (1/2 times with errors)
    • job 101123 AssertionError: qvm-template failed: Downloading 'qubes-template-de...
    TC_11_QvmTemplateMgmtVM_fedora-40-xfce/test_010_template_install (1/2 times with errors)
    • job 101123 AssertionError: qvm-template failed: Downloading 'qubes-template-de...
    TC_11_QvmTemplateMgmtVM_whonix-gateway-17/test_010_template_install (1/2 times with errors)
    • job 101123 AssertionError: qvm-template failed: Downloading 'qubes-template-de...
  • system_tests_dispvm

    TC_20_DispVM_fedora-40-xfce/test_100_open_in_dispvm (1/2 times with errors)
    • job 101764 AssertionError: './open-file test.txt' failed with ./open-file test...
  • system_tests_basic_vm_qrexec_gui_btrfs

    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_220_audio_play_pulseaudio (1/2 times with errors)
    • job 101110 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_222_audio_rec_unmuted_pulseaudio (1/2 times with errors)
    • job 101110 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_223_audio_play_hvm (1/2 times with errors)
    • job 101110 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    TC_20_AudioVM_Pulse_fedora-40-xfce-pool/test_225_audio_rec_unmuted_hvm (1/2 times with errors)
    • job 101782 AssertionError: too short audio, expected 10s, got 6.28875283446712...
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_252_audio_playback_audiovm_switch_hvm (2/2 times with errors)
    • job 101110 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    • job 101782 AssertionError: pacat for test-inst-vm1 (xid 90) running(False) in ...
  • system_tests_basic_vm_qrexec_gui_ext4

    TC_00_Basic/test_141_libvirt_objects_reconnect (1/2 times with errors)
    • job 101111 AssertionError: libvirt event impl drain timeout
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_220_audio_play_pulseaudio (1/2 times with errors)
    • job 101111 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_222_audio_rec_unmuted_pulseaudio (1/2 times with errors)
    • job 101111 AssertionError: only silence detected, no useful audio data
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_223_audio_play_hvm (1/2 times with errors)
    • job 101111 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_252_audio_playback_audiovm_switch_hvm (1/2 times with errors)
    • job 101111 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
  • system_tests_basic_vm_qrexec_gui_xfs

    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_220_audio_play_pulseaudio (2/2 times with errors)
    • job 101112 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    • job 101781 AssertionError: too short audio, expected 10s, got 8.33947845804988...
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_222_audio_rec_unmuted_pulseaudio (2/2 times with errors)
    • job 101112 AssertionError: only silence detected, no useful audio data
    • job 101781 AssertionError: too short audio, expected 10s, got 8.17784580498866...
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_223_audio_play_hvm (2/2 times with errors)
    • job 101112 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    • job 101781 AssertionError: too short audio, expected 10s, got 7.71551020408163...
    TC_20_AudioVM_Pulse_whonix-workstation-17-pool/test_252_audio_playback_audiovm_switch_hvm (1/2 times with errors)
    • job 101112 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
  • system_tests_basic_vm_qrexec_gui@hw1

    TC_20_AudioVM_Pulse_whonix-workstation-17/test_220_audio_play_pulseaudio (2/2 times with errors)
    • job 101109 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    • job 101758 AssertionError: too short audio, expected 10s, got 8.73532879818594...
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_222_audio_rec_unmuted_pulseaudio (2/2 times with errors)
    • job 101109 AssertionError: only silence detected, no useful audio data
    • job 101758 AssertionError: too short audio, expected 10s, got 9.36446712018140...
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_223_audio_play_hvm (1/2 times with errors)
    • job 101109 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
    TC_20_AudioVM_Pulse_whonix-workstation-17/test_252_audio_playback_audiovm_switch_hvm (1/2 times with errors)
    • job 101109 AssertionError: Command 'timeout 20s paplay --format=float32le --ra...
  • system_tests_suspend@hw1

    suspend/ (2/4 times with errors)
    suspend/Failed (2/4 times with errors)
    • job 102431 # Test died: no candidate needle with tag(s) 'xscreensaver-prompt' ...
    • job 102443 # Test died: no candidate needle with tag(s) 'xscreensaver-prompt' ...
    suspend/wait_serial (2/4 times with errors)
    • job 102431 # wait_serial expected: qr/2E8vz-\d+-/...
    • job 102443 # wait_serial expected: qr/2E8vz-\d+-/...

@marmarek
Copy link
Member

Installing updates failed, skipping the report!

qfile-agent: Fatal error: File copy: "Invalid or incomplete multibyte or wide character; Last file: adobe-mappings-cmap-20230622-1.fc37.noarch.rpm" (error type: Invalid or incomplete multibyte or wide character)

Doesn't look like a name that should be rejected in any mode,,,

@marmarek
Copy link
Member

And while at it, can you change the error message for EILSEQ to something clearer for mere mortals? Maybe "File name contains disallowed characters"?

@marmarek marmarek removed the openqa-pending PR to be tested in the next OpenQA run label May 17, 2024
@DemiMarie
Copy link
Contributor Author

Installing updates failed, skipping the report!

qfile-agent: Fatal error: File copy: "Invalid or incomplete multibyte or wide character; Last file: adobe-mappings-cmap-20230622-1.fc37.noarch.rpm" (error type: Invalid or incomplete multibyte or wide character)

Doesn't look like a name that should be rejected in any mode,,,

It is accepted by qubes_pure_validate_file_name(). I will need to do an integration test to see what happens.

@DemiMarie
Copy link
Contributor Author

And while at it, can you change the error message for EILSEQ to something clearer for mere mortals? Maybe "File name contains disallowed characters"?

Already done in afade05, but EILSEQ is also used for non-canonical symbolic links.

@marmarek
Copy link
Member

Another line from logs (but doesn't really add here):

Command '['/usr/libexec/qubes/qfile-dom0-unpacker', '1000', '/var/tmp/qubes-updates-tmp3tzhg9ms.UNTRUSTED', '--only-regular-files']' returned non-zero exit status 84.

@DemiMarie DemiMarie force-pushed the allow-less-secure branch from a4369a0 to 21d88b9 Compare May 19, 2024 02:07
@DemiMarie
Copy link
Contributor Author

Installing updates failed, skipping the report!

qfile-agent: Fatal error: File copy: "Invalid or incomplete multibyte or wide character; Last file: adobe-mappings-cmap-20230622-1.fc37.noarch.rpm" (error type: Invalid or incomplete multibyte or wide character)

Doesn't look like a name that should be rejected in any mode,,,

Oops, I switched to the *_v2 functions in acc900a, but forgot to change the return value checks. The new functions return an int (0 on success, negative on failure), while the old functions returned a bool (true on success, false on failure), so the result was that a file was accepted if it should be rejected and visa versa. Fixed in 8c17abd.

@DemiMarie DemiMarie requested a review from marmarek May 19, 2024 02:09
@marmarek marmarek added the openqa-pending PR to be tested in the next OpenQA run label May 20, 2024
@marmarek
Copy link
Member

This (or the other PR) broke salt, specifically the step when files from dom0 are copied into dispvm:

[2024-05-20 01:09:52] [   18.208751] qrexec-agent[625]: 2024-05-20 01:09:52.950 qrexec-agent[625]: qrexec-agent-data.c:288:handle_new_process_common: pid 627 exited with 95

I don't have stderr logged to see what file it complained about, but I'll try to save it next time.

@marmarek
Copy link
Member

I got the stderr, and I'm more confused:

File copy: "Operation not supported; Last file:  srv/formulas/test/update-formula/update"

The path here is a normal directory.

@marmarek
Copy link
Member

And relevant part of strace on the unpacker:

738   read(0, "srv/formulas/test/update-formula"..., 40) = 40
738   fcntl(0, F_GETFL)                 = 0x2 (flags O_RDWR)
738   openat(AT_FDCWD, "srv", O_RDONLY|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = 4
738   openat(4, "formulas", O_RDONLY|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = 5
738   close(4)                          = 0
738   openat(5, "test", O_RDONLY|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = 4
738   close(5)                          = 0
738   openat(4, "update-formula", O_RDONLY|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = 5
738   close(4)                          = 0
738   mkdirat(5, "update", 0700)        = -1 EEXIST (File exists)
738   newfstatat(AT_FDCWD, "srv/formulas/test/update-formula/update", {st_mode=S_IFDIR|0700, st_size=4096, ...}, 0) = 0
738   openat(5, "update", O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH) = 4
738   newfstatat(4, "", {st_mode=S_IFDIR|0700, st_size=4096, ...}, AT_EMPTY_PATH) = 0
738   chmod("/proc/self/fd/4", 0755)    = -1 ENOENT (No such file or directory)
738   close(4)                          = 0
738   close(0)                          = 0
738   write(1, "_\0\0\0\0\0\0\0\\m\26v\0\0\0\0", 16) = 16
738   write(1, "'\0\0\0", 4)            = 4
738   write(1, "srv/formulas/test/update-formula"..., 39) = 39
738   exit_group(95)                    = ?
738   +++ exited with 95 +++

@marmarek
Copy link
Member

738 chmod("/proc/self/fd/4", 0755) = -1 ENOENT (No such file or directory)

This is most likely due to chroot. There is saved open procfd_fd, but this particular call is likely done by glibc (fchmodat with AT_SYMLINK_NOFOLLOW?) so it doesn't know how to use it.

qrexec-lib/unpack.c Outdated Show resolved Hide resolved
DemiMarie added 3 commits May 20, 2024 16:36
It is highly critical and is not obvious.
They were rejected without a good reason.  They pose no danger not
already posed by symlinks of the form "../a".
This is obscure, but it is harmless.  It simply means that the target of
the symlink must be a directory (or symlink to a directory), otherwise
opening the symlink will fail with ENOTDIR.  Allowing non-symlink paths
to end in '/' is also harmless: opendir_safe() will set the last path
component to the empty string, and attempting to create a file, symlink,
or directory with the empty string as a name will fail with ENOENT.
DemiMarie added 2 commits May 20, 2024 16:36
This is a theoretical ABI change, but hopefully no third-party app is
linking against undocumented functions not part of any header file.
Also remove an unused function.
qubes_pure_validate_symbolic_link() validates both the symlink path and
target, so validating the path with a separate
qubes_pure_validate_file_name() call is unnecessary.
@DemiMarie DemiMarie requested a review from marmarek May 20, 2024 21:09
@DemiMarie DemiMarie force-pushed the allow-less-secure branch from 21d88b9 to abea7f0 Compare May 20, 2024 21:15
DemiMarie added a commit to DemiMarie/qubes-core-agent-linux that referenced this pull request May 21, 2024
This requires QubesOS/qubes-linux-utils#113.  It also adds a new
argument parser based on getopt_long(), which is used instead of the old
hand-rolled code unless there are at least two arguments and the first
one starts with an ASCII digit.

Part of QubesOS/qubes-issues#8332
DemiMarie added a commit to DemiMarie/qubes-core-agent-linux that referenced this pull request May 27, 2024
This requires QubesOS/qubes-linux-utils#113.  It also adds a new
argument parser based on getopt_long(), which is used instead of the old
hand-rolled code unless there are at least two arguments and the first
one starts with an ASCII digit.

Part of QubesOS/qubes-issues#8332
qrexec-lib/unicode.c Outdated Show resolved Hide resolved
qrexec-lib/pack.c Outdated Show resolved Hide resolved
The error message is not great, but at least it is not actively
misleading anymore.

Will fix QubesOS/qubes-issues#8581 once this is used by qfile-unpacker
and qfile-agent.
This allows copying paths with names that would otherwise be forbidden.
This requires adding new APIs, so take the opportunity to provide more
useful information about why a path was rejected.

To ensure that internal invariants are not violated, this uses a new
COMPILETIME_UNREACHABLE macro to validate that a statement can be proven
unreachable by the compiler.  This is superior to abort() because it is
checked at compile-time by the optimizer: if the compiler cannot prove
that the code is unreachable, the build will fail.  This technique is
also used by BUILD_BUG_ON() in the Linux kernel.  Since compilers do not
promise to always be able to prove a piece of code unreachable, static
checking is disabled by default.  It can be enabled by including
CHECK_UNREACHABLE=1 in the build environment.

This is part of QubesOS/qubes-issues#8332 (less restricted qfile-copy),
but that issue also requires changes to qfile-unpacker (part of
qubes-core-agent-linux) to fix.  The code is both backwards and forwards
compatible: Old qfile-unpacker versions will work fine with the new
library, and new qfile-unpacker versions will work fine with the old
library.  However, qubes.UnsafeFileCopy will behave like qubes.Filecopy
unless the library has been updated.

Initially, I decided to unconditionally disallow ASCII control
characters in filenames, even if other character set filtering is
disabled.  This is because they are very useful for exploits and not
very useful for other purposes.  However, they can still arise in
practice for completely legitimate reasons.  These include copying and
pasting into a file name in a GUI file manager and deliberately creating
strangely-named files for test purposes.  Therefore, disabling filtering
now disables _all_ character set filtering.  Restrictions to prevent
directory traversal are still enforced, though, because violations of
these are much more likely to be exploitable.  While symlinks that point
outside of the directory being copied might arise legitimately, they
will not be meaningful after being copied and _do_ allow an attacker to
cause mischief.  For instance, if a symlink points to
/home/user/.bashrc, "cp a b" in a directory copied by qvm-copy could
overwrite ~/.bashrc with attacker-controlled data.  The checks on
symlink paths prevent this.
Instead of crashing on the first failed test, log an error message for
each failed test that points to the location of the error.
This will make subsequent changes easier.

No functional change intended.
This will later be exposed by qfile-unpacker, and is a safer alternative
to disabling all symbolic link checking.
This turns off all checks for symbolic links, returning to the R4.1
behavior.  This is unsafe, but it might be necessary in some cases.
However, it will not be included by either qubes.Filecopy or
qubes.UnsafeFileCopy.
They would result in a misleading ENOENT error due to passing an empty
path to openat().  Instead, reject the path with EILSEQ to indicate a
malformed pathname.
@DemiMarie DemiMarie force-pushed the allow-less-secure branch from abea7f0 to 044c4d4 Compare June 15, 2024 20:01
@marmarek marmarek merged commit b689810 into QubesOS:main Jun 16, 2024
2 checks passed
@DemiMarie DemiMarie deleted the allow-less-secure branch June 16, 2024 15:51
marmarek pushed a commit to QubesOS/qubes-core-agent-linux that referenced this pull request Jun 22, 2024
This requires QubesOS/qubes-linux-utils#113.  It also adds a new
argument parser based on getopt_long(), which is used instead of the old
hand-rolled code unless there are at least two arguments and the first
one starts with an ASCII digit.

Part of QubesOS/qubes-issues#8332

(cherry picked from commit 3a0778b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
openqa-pending PR to be tested in the next OpenQA run
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants