Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 348763 - sys-apps/sandbox-2.4: utimensat(AT_SYMLINK_NOFOLLOW) changes link atime
Summary: sys-apps/sandbox-2.4: utimensat(AT_SYMLINK_NOFOLLOW) changes link atime
Status: RESOLVED WONTFIX
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: [OLD] Core system (show other bugs)
Hardware: All Linux
: High normal
Assignee: Sandbox Maintainers
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-15 03:35 UTC by T Chan
Modified: 2011-01-02 04:37 UTC (History)
0 users

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


Attachments
Test case. (tc-utimensat.c,1.41 KB, text/plain)
2010-12-15 04:49 UTC, T Chan
Details
sandbox-2.4/libsandbox/libsandbox.c patch (libsandbox.c.patch,787 bytes, patch)
2010-12-15 05:07 UTC, T Chan
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description T Chan 2010-12-15 03:35:10 UTC
Causes test breakage in sys-apps/coreutils-8.7:
  gnulib-tests/test-utimensat
  gnulib-tests/test-fdutimensat

Pseudocode is something like this ("path" is the path to a symlink):
  lstat(path,&st1);
  sleep(1);
  utimensat(AT_FDCWD, path, (struct timespec const[]){
      {946684800, UTIME_OMIT},
      {946684800, 0}
    }, AT_SYMLINK_NOFOLLOW);
  sleep(1);
  lstat(path,&st2);
  assert(st1.st_atim.tv_sec == st2.st_atim.tv_sec &&
    st1.st_atim.tv_nsec == st2.st_atim.tv_nsec);

The symlink is never followed, so its atime should not change. When running in sandbox, it *does* change (strace suggests that this is due to a call to readlink()).

I *think* it happens when check_syscall() calls resolve_path() (which calls erealpath()/realpath()). Unfortunately, it is not as simple as changing
        resolved_path = resolve_path(file, 1);
to
        resolved_path = resolve_path(file,
                          !(flags & AT_SYMLINK_NOFOLLOW));
because (AIUI) "a/b/c",AT_SYMLINK_NOFOLLOW still potentially resolves symlinks a and b.


Additionally, Linux (or glibc) appears to check the validity of timespecs before resolving the symlink. That is,
  utimensat(AT_FDCWD, path, (struct timespec const[]){
      {946684800, -1},
      {946684800, 1000000000}
    }, 0);
does not read the link because -1 and 1000000000 are not valid in tv_nsec. (This assumes UTIME_NOW and UTIME_OMIT are not -1 or 10**9; /usr/include/bits/stat.h says they're 2**30-1 and 2**30-2 respectively.)

However, checking for the validity of timespecs does not fit into the autogenerated syscall-wrapper structure as easily. It also is conceptually a less reliable assumption to make (timespec-checking could conceptually happen in an a kernel-internal function that operates on an inode).

Patch coming up...
Comment 1 Jeremy Olexa (darkside) (RETIRED) archtester gentoo-dev Security 2010-12-15 03:36:35 UTC
dupe of bug 348640 ?
Comment 2 T Chan 2010-12-15 04:02:23 UTC
Nope, utimensat() correctly returns EINVAL (in bug 348640 it returns ENOSYS "unimplemented system call" or so).
Comment 3 T Chan 2010-12-15 04:49:44 UTC
Created attachment 257208 [details]
Test case.

It goes something like this
# cc -o tc-utimensat tc-utimensat.c
# sandbox ./tc-utimensat
1292387703.2773884 1292387703.102770037
tc-utimensat: tc-utimensat.c:36: main: Assertion `t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec' failed.
Sandboxed process killed by signal: Aborted

# ./tc-utimensat
1292387713.572769865 1292387713.572769865

Caveats:
- The FS needs to update atimes (i.e. not be mounted with relatime/noatime).
- The dir needs to be writable in the sandbox

The easiest way is to stick it in /dev/shm (I use /var/tmp/portage because it's a tempfs for me).
Comment 4 T Chan 2010-12-15 05:07:11 UTC
Created attachment 257210 [details, diff]
sandbox-2.4/libsandbox/libsandbox.c patch

Bugs:
- It doesn't special-case the empty string (does it need to?).
- It doesn't apply only to the syscalls which accept AT_SYMLINK_NOFOLLOW (e.g. it might be possible to bypass the sandbox with openat(AT_SYMLINK_NOFOLLOW)). I'm not sure what the kernel does here (curiously, there's also AT_SYMLINK_FOLLOW though I can't find the syscall where it's used).
- Everything else I forgot, because it's 5 AM (oops).
Comment 5 SpanKY gentoo-dev 2010-12-15 11:25:15 UTC
so let me see if i have this right ... the issue is that dereferencing a symlink updates its atime, and using utimensat(AT_SYMLINK_NOFOLLOW) will implicitly dereference the symlink by sandbox internals and thus update the atime ?
Comment 6 SpanKY gentoo-dev 2011-01-02 02:12:10 UTC
assuming my comment #5 is what you mean, i dont see this worth fixing.  atime is almost universally useless.
Comment 7 T Chan 2011-01-02 04:37:27 UTC
It's just that it happens to check atime - it (presumably) also checks permissions against the destination of the link despite being a system call that shouldn't follow the link.