Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 921581 - sys-apps/sandbox: changes in the behavior of directory operations of sys-devel/llvm
Summary: sys-apps/sandbox: changes in the behavior of directory operations of sys-deve...
Status: RESOLVED FIXED
Alias: None
Product: Portage Development
Classification: Unclassified
Component: Sandbox (show other bugs)
Hardware: All Linux
: Normal normal
Assignee: Sandbox Maintainers
URL:
Whiteboard:
Keywords: InVCS
Depends on:
Blocks:
 
Reported: 2024-01-07 17:23 UTC by Andrei Horodniceanu
Modified: 2025-01-14 04:38 UTC (History)
1 user (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrei Horodniceanu 2024-01-07 17:23:42 UTC
sys-devel/llvm offers the C++ function llvm::sys::fs::create_directories. As opposed to something like mkdir, the function handles cases such as `~/nonexistent/../directory` by creating `~/nonexistent` and `~/directory`.

When ran inside the sandbox, however, the previous operation fails.

A C++ program to demonstrate the behavior:
------
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include <iostream>

using namespace llvm;
using namespace llvm::sys::fs;
using namespace llvm::sys::path;

int main (int argc, char **argv) {
        if (argc < 2) {
                return 1;
        }

        SmallString<128> path;
        append(path, argv[1]);

        std::clog << "Trying to create: " << path.c_str() << '\n';
        const auto ec = create_directories(path);
        std::clog << "Error code: " << ec << '\n';

        return ec.value();
}
------

Without sandbox:
------
$ strace -e file ./main ~/nonexistent/../directory
execve("./main", ["./main", "/home/happy/nonexistent/../direc"...], 0x7ffd4d8674b8 /* 75 vars */) = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=133875, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/libLLVM-16.so", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=132698120, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/gcc/x86_64-pc-linux-gnu/14/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2685424, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=907376, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/gcc/x86_64-pc-linux-gnu/14/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=186296, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=1929696, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v3/libffi.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v3", 0x7ffd2a1f8ff0, 0) = -1 ENOENT (No such file or
directory)
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v2/libffi.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v2", 0x7ffd2a1f8ff0, 0) = -1 ENOENT (No such file or
directory)
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libffi.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib64/libffi.so.8", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=47104, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libz.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libz.so.1", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=104384, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libzstd.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libzstd.so.1", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=739184, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=261192, ...}, AT_EMPTY_PATH) = 0
newfstatat(2, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0xb), ...}, AT_EMPTY_PATH) = 0
Trying to create: /home/happy/nonexistent/../directory
mkdir("/home/happy/nonexistent/../directory", 0770) = -1 ENOENT (No such file or directory)
mkdir("/home/happy/nonexistent/..", 0770) = -1 ENOENT (No such file or directory)
mkdir("/home/happy/nonexistent", 0770)  = 0
mkdir("/home/happy/nonexistent/..", 0770) = -1 EEXIST (File exists)
mkdir("/home/happy/nonexistent/../directory", 0770) = 0
Error code: system:0
+++ exited with 0 +++
------

With sandbox:
------
$ LD_PRELOAD=/usr/lib64/libsandbox.so strace -e file ./main ~/nonexistent/../directory
execve("./main", ["./main", "/home/happy/nonexistent/../direc"...], 0x7fff25401ba8 /* 76 vars */) = 0
openat(AT_FDCWD, "/usr/lib64/libsandbox.so", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=96248, ...}, AT_EMPTY_PATH) = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=133875, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/libLLVM-16.so", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=132698120, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/gcc/x86_64-pc-linux-gnu/14/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2685424, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=907376, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/gcc/x86_64-pc-linux-gnu/14/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=186296, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=1929696, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v3/libffi.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v3", 0x7ffe1a5699c0, 0) = -1 ENOENT (No such file or
directory)
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v2/libffi.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/glibc-hwcaps/x86-64-v2", 0x7ffe1a5699c0, 0) = -1 ENOENT (No such file or
directory)
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libffi.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib64/libffi.so.8", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=47104, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libz.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libz.so.1", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=104384, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libzstd.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libzstd.so.1", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=739184, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/llvm/16/lib64/../lib64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=261192, ...}, AT_EMPTY_PATH) = 0
newfstatat(2, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0xb), ...}, AT_EMPTY_PATH) = 0
Trying to create: /home/happy/nonexistent/../directory
newfstatat(AT_FDCWD, "/home/happy/directory", 0x7ffe1a5664c0, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
mkdir("/home/happy/nonexistent/../directory", 0770) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/happy", {st_mode=S_IFDIR|0755, st_size=20480, ...}, AT_SYMLINK_NOFOLLOW) = 0
newfstatat(AT_FDCWD, "/home/happy/directory", 0x7ffe1a5664c0, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
mkdir("/home/happy/nonexistent/../directory", 0770) = -1 ENOENT (No such file or directory)
Error code: generic:2
+++ exited with 2 +++
-------
Comment 1 Andrei Horodniceanu 2024-01-07 18:33:58 UTC
mkdir -p is a better comparison to create_directories with the exception that it works inside the sandbox.
Comment 2 Mike Gilbert gentoo-dev 2024-01-07 18:49:24 UTC
It's not clear to me how the sandbox code is interfering at all here. You will need to debug this a bit more to identify the problem.
Comment 3 Andrei Horodniceanu 2024-01-07 20:50:48 UTC
I'm all for helping and debugging some more, it's just that the sandbox is pretty low level and I don't know anything about all of this. All I know is that 1 function works outside the sandbox while inside the sandbox it fails.
Comment 4 Mike Gilbert gentoo-dev 2024-01-07 23:24:53 UTC
(In reply to Horodniceanu Andrei from comment #3)

Someone needs to debug the llvm create_directories function to determine where the behavior differs exactly.
Comment 5 Mike Gilbert gentoo-dev 2024-01-07 23:30:57 UTC
My best guess is that sandbox is returning ENOENT or EEXIST in a context where the LLVM code expects to see the opposite.
Comment 6 Mike Gilbert gentoo-dev 2024-01-08 00:00:09 UTC
Ah, I think I may see what is happening.

I think problem is the difference in behavior between these commands:

% strace -e mkdir mkdir /tmp/foo/..
mkdir("/tmp/foo/..", 0777)              = -1 ENOENT (No such file or directory)
mkdir: cannot create directory ‘/tmp/foo/..’: No such file or directory
+++ exited with 1 +++

% sandbox strace -e mkdir mkdir /tmp/foo/..
mkdir: cannot create directory ‘/tmp/foo/..’: File exists
+++ exited with 1 +++

Without sandbox, /tmp/foo/ does not exist, so we get ENOENT from the kernel.

With sandbox, /tmp/foo/.. gets canonicalized to /tmp, and sandbox returns EEXIST.
Comment 7 Mike Gilbert gentoo-dev 2024-01-08 20:05:37 UTC
Please give the PR a try.
Comment 8 Andrei Horodniceanu 2024-01-08 21:06:53 UTC
(In reply to Mike Gilbert from comment #7)
> Please give the PR a try.

Fixed the issue. Thanks Mike
Comment 9 Larry the Git Cow gentoo-dev 2024-01-22 21:41:32 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=ef9208bea4e0f0dff5abf358002565f36e4d7a8d

commit ef9208bea4e0f0dff5abf358002565f36e4d7a8d
Author:     Mike Gilbert <floppym@gentoo.org>
AuthorDate: 2024-01-08 19:59:35 +0000
Commit:     Mike Gilbert <floppym@gentoo.org>
CommitDate: 2024-01-08 20:04:09 +0000

    libsandbox: stat the original path for EEXIST hackaround
    
    Resolves an issue that can occur with paths that contain parent
    directory references (/../).
    
    If part of the path does not exist, the sandboxed program should get ENOENT,
    not EEXIST. If we use the canonicalized path, intermediate paths will be
    eliminated and we produce the wrong result.
    
    Bug: https://bugs.gentoo.org/921581
    Signed-off-by: Mike Gilbert <floppym@gentoo.org>

 libsandbox/pre_check_mkdirat.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Comment 10 Aliaksei Urbanski 2024-06-27 03:00:02 UTC
Hello everyone,

As you know, sandboxed mkdirat fails with EEXIST while ENOENT is expected.

Due to this bug, the 'fs.test.test.makepath relative walks' test of dev-lang/zig-0.13.0 (not in the main tree yet, see https://github.com/gentoo/gentoo/pull/37257) fails in case it tries to create a directory using the libc (there are other implementations that are not affected).
I submitted a patch for Zig (https://github.com/ziglang/zig/pull/20397), but now I've figured out that the root cause is this sandbox issue.

I see that Mike Gilbert already fixed it in the sandbox repository, but that fix itself causes sandbox violations where there were no violations since EEXIST was expected instead. So I'm going to submit a PR with an alternative fix.
Comment 11 Aliaksei Urbanski 2024-06-27 03:33:39 UTC
There is a mistake in the last paragraph of my previous message: there must be ENOENT, not EEXIST.
Comment 12 Larry the Git Cow gentoo-dev 2024-06-27 15:25:06 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=de4f57761821e3d97e841a99af38768ee9605633

commit de4f57761821e3d97e841a99af38768ee9605633
Author:     Aliaksei Urbanski <aliaksei.urbanski@gmail.com>
AuthorDate: 2024-06-27 03:51:47 +0000
Commit:     Mike Gilbert <floppym@gentoo.org>
CommitDate: 2024-06-27 15:23:48 +0000

    libsandbox: fix violations where ENOENT is expected
    
    These changes revert f7d02c04 that aimed to resolve 921581 and
    fix it in a way that doesn't cause unwanted sandbox violations.
    
    Bug: https://bugs.gentoo.org/921581
    Signed-off-by: Aliaksei Urbanski <aliaksei.urbanski@gmail.com>
    Signed-off-by: Mike Gilbert <floppym@gentoo.org>

 libsandbox/pre_check_mkdirat.c | 8 +++++---
 tests/mkdirat-3.sh             | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)
Comment 13 Larry the Git Cow gentoo-dev 2024-06-27 18:39:34 UTC
The bug has been closed via the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=23af26a6cc7fa2537e7f7d5ea4a65c7ad68c5eee

commit 23af26a6cc7fa2537e7f7d5ea4a65c7ad68c5eee
Author:     Mike Gilbert <floppym@gentoo.org>
AuthorDate: 2024-06-27 18:38:15 +0000
Commit:     Mike Gilbert <floppym@gentoo.org>
CommitDate: 2024-06-27 18:39:32 +0000

    sys-apps/sandbox: add 2.39
    
    Closes: https://bugs.gentoo.org/923013
    Closes: https://bugs.gentoo.org/921581
    Signed-off-by: Mike Gilbert <floppym@gentoo.org>

 sys-apps/sandbox/Manifest            |  1 +
 sys-apps/sandbox/sandbox-2.39.ebuild | 64 ++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)
Comment 14 Larry the Git Cow gentoo-dev 2025-01-14 04:38:17 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=4b40e4489a7793d888ae55ecbb3ca560889a5a14

commit 4b40e4489a7793d888ae55ecbb3ca560889a5a14
Author:     Aliaksei Urbanski <aliaksei.urbanski@gmail.com>
AuthorDate: 2024-06-27 03:51:47 +0000
Commit:     Mike Gilbert <floppym@gentoo.org>
CommitDate: 2024-06-27 15:24:50 +0000

    libsandbox: fix violations where ENOENT is expected
    
    These changes revert f7d02c04 that aimed to resolve 921581 and
    fix it in a way that doesn't cause unwanted sandbox violations.
    
    Bug: https://bugs.gentoo.org/921581
    Signed-off-by: Aliaksei Urbanski <aliaksei.urbanski@gmail.com>
    Signed-off-by: Mike Gilbert <floppym@gentoo.org>
    (cherry picked from commit de4f57761821e3d97e841a99af38768ee9605633)

 libsandbox/pre_check_mkdirat.c | 8 +++++---
 tests/mkdirat-3.sh             | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)

https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=f7d02c04b2a8e395f478bda03306fb68fb44ba4c

commit f7d02c04b2a8e395f478bda03306fb68fb44ba4c
Author:     Mike Gilbert <floppym@gentoo.org>
AuthorDate: 2024-01-08 19:59:35 +0000
Commit:     Mike Gilbert <floppym@gentoo.org>
CommitDate: 2024-01-22 21:41:13 +0000

    libsandbox: stat the original path for EEXIST hackaround
    
    Resolves an issue that can occur with paths that contain parent
    directory references (/../).
    
    If part of the path does not exist, the sandboxed program should get ENOENT,
    not EEXIST. If we use the canonicalized path, intermediate paths will be
    eliminated and we produce the wrong result.
    
    Bug: https://bugs.gentoo.org/921581
    Signed-off-by: Mike Gilbert <floppym@gentoo.org>
    (cherry picked from commit ef9208bea4e0f0dff5abf358002565f36e4d7a8d)

 libsandbox/pre_check_mkdirat.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)