SRU request submitted:
https://lists.ubuntu.com/archives/kernel-team/2018-September/095580.html

** Changed in: linux (Ubuntu Cosmic)
       Status: In Progress => Fix Committed

** Description changed:

  Hey everyone,
  
  When running in a container with a user namespace, if you call getxattr
  with name = "system.posix_acl_access" and size % 8 != 4, then getxattr
  silently skips the user namespace fixup that it normally does resulting in
  un-fixed-up data being returned.
  This is caused by posix_acl_fix_xattr_to_user() being passed the total
  buffer size and not the actual size of the xattr as returned by
  vfs_getxattr().
  
  I have pushed a commit upstream that fixes this bug:
  
  
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=82c9a927bc5df6e06b72d206d24a9d10cced4eb5
  
- 
  This commit passes the actual length of the xattr as returned by
  vfs_getxattr() down.
  
  A reproducer for the issue is:
  
-   touch acl_posix
+   touch acl_posix
  
-   setfacl -m user:0:rwx acl_posix
+   setfacl -m user:0:rwx acl_posix
  
  and the compile:
  
-   #define _GNU_SOURCE
-   #include <errno.h>
-   #include <stdio.h>
-   #include <stdlib.h>
-   #include <string.h>
-   #include <sys/types.h>
-   #include <unistd.h>
-   #include <attr/xattr.h>
+   #define _GNU_SOURCE
+   #include <errno.h>
+   #include <stdio.h>
+   #include <stdlib.h>
+   #include <string.h>
+   #include <sys/types.h>
+   #include <unistd.h>
+   #include <attr/xattr.h>
  
-   /* Run in user namespace with nsuid 0 mapped to uid != 0 on the host. */
-   int main(int argc, void **argv)
-   {
-           ssize_t ret1, ret2;
-           char buf1[128], buf2[132];
-           int fret = EXIT_SUCCESS;
-           char *file;
+   /* Run in user namespace with nsuid 0 mapped to uid != 0 on the host. */
+   int main(int argc, void **argv)
+   {
+           ssize_t ret1, ret2;
+           char buf1[128], buf2[132];
+           int fret = EXIT_SUCCESS;
+           char *file;
  
-           if (argc < 2) {
-                   fprintf(stderr,
-                           "Please specify a file with "
-                           "\"system.posix_acl_access\" permissions set\n");
-                   _exit(EXIT_FAILURE);
-           }
-           file = argv[1];
+           if (argc < 2) {
+                   fprintf(stderr,
+                           "Please specify a file with "
+                           "\"system.posix_acl_access\" permissions set\n");
+                   _exit(EXIT_FAILURE);
+           }
+           file = argv[1];
  
-           ret1 = getxattr(file, "system.posix_acl_access",
-                           buf1, sizeof(buf1));
-           if (ret1 < 0) {
-                   fprintf(stderr, "%s - Failed to retrieve "
-                                   "\"system.posix_acl_access\" "
-                                   "from \"%s\"\n", strerror(errno), file);
-                   _exit(EXIT_FAILURE);
-           }
+           ret1 = getxattr(file, "system.posix_acl_access",
+                           buf1, sizeof(buf1));
+           if (ret1 < 0) {
+                   fprintf(stderr, "%s - Failed to retrieve "
+                                   "\"system.posix_acl_access\" "
+                                   "from \"%s\"\n", strerror(errno), file);
+                   _exit(EXIT_FAILURE);
+           }
  
-           ret2 = getxattr(file, "system.posix_acl_access",
-                           buf2, sizeof(buf2));
-           if (ret2 < 0) {
-                   fprintf(stderr, "%s - Failed to retrieve "
-                                   "\"system.posix_acl_access\" "
-                                   "from \"%s\"\n", strerror(errno), file);
-                   _exit(EXIT_FAILURE);
-           }
+           ret2 = getxattr(file, "system.posix_acl_access",
+                           buf2, sizeof(buf2));
+           if (ret2 < 0) {
+                   fprintf(stderr, "%s - Failed to retrieve "
+                                   "\"system.posix_acl_access\" "
+                                   "from \"%s\"\n", strerror(errno), file);
+                   _exit(EXIT_FAILURE);
+           }
  
-           if (ret1 != ret2) {
-                   fprintf(stderr, "The value of \"system.posix_acl_"
-                                   "access\" for file \"%s\" changed "
-                                   "between two successive calls\n", file);
-                   _exit(EXIT_FAILURE);
-           }
+           if (ret1 != ret2) {
+                   fprintf(stderr, "The value of \"system.posix_acl_"
+                                   "access\" for file \"%s\" changed "
+                                   "between two successive calls\n", file);
+                   _exit(EXIT_FAILURE);
+           }
  
-           for (ssize_t i = 0; i < ret2; i++) {
-                   if (buf1[i] == buf2[i])
-                           continue;
+           for (ssize_t i = 0; i < ret2; i++) {
+                   if (buf1[i] == buf2[i])
+                           continue;
  
-                   fprintf(stderr,
-                           "Unexpected different in byte %zd: "
-                           "%02x != %02x\n", i, buf1[i], buf2[i]);
-                   fret = EXIT_FAILURE;
-           }
+                   fprintf(stderr,
+                           "Unexpected different in byte %zd: "
+                           "%02x != %02x\n", i, buf1[i], buf2[i]);
+                   fret = EXIT_FAILURE;
+           }
  
-           if (fret == EXIT_SUCCESS)
-                   fprintf(stderr, "Test passed\n");
-           else
-                   fprintf(stderr, "Test failed\n");
+           if (fret == EXIT_SUCCESS)
+                   fprintf(stderr, "Test passed\n");
+           else
+                   fprintf(stderr, "Test failed\n");
  
-           _exit(fret);
-   }
+           _exit(fret);
+   }
  and run:
  
-   ./tester acl_posix
+   ./tester acl_posix
  
  On a non-fixed up kernel this should return something like:
  
-   root@c1:/# ./t
-   Unexpected different in byte 16: ffffffa0 != 00
-   Unexpected different in byte 17: ffffff86 != 00
-   Unexpected different in byte 18: 01 != 00
+   root@c1:/# ./t
+   Unexpected different in byte 16: ffffffa0 != 00
+   Unexpected different in byte 17: ffffff86 != 00
+   Unexpected different in byte 18: 01 != 00
  
  and on a fixed kernel:
  
-   root@c1:~# ./t
-   Test passed
- 
+   root@c1:~# ./t
+   Test passed
  
  Please backport this to the 4.15 (bionic) and 4.4 (xenial) kernels. :)
  
  Thanks!
  Christian

** Description changed:

- Hey everyone,
  
+ == SRU Justification ==
  When running in a container with a user namespace, if you call getxattr
  with name = "system.posix_acl_access" and size % 8 != 4, then getxattr
  silently skips the user namespace fixup that it normally does resulting in
  un-fixed-up data being returned.
  This is caused by posix_acl_fix_xattr_to_user() being passed the total
  buffer size and not the actual size of the xattr as returned by
  vfs_getxattr().
  
  I have pushed a commit upstream that fixes this bug:
  
  
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=82c9a927bc5df6e06b72d206d24a9d10cced4eb5
  
  This commit passes the actual length of the xattr as returned by
  vfs_getxattr() down.
  
  A reproducer for the issue is:
  
    touch acl_posix
  
    setfacl -m user:0:rwx acl_posix
  
  and the compile:
  
    #define _GNU_SOURCE
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <attr/xattr.h>
  
    /* Run in user namespace with nsuid 0 mapped to uid != 0 on the host. */
    int main(int argc, void **argv)
    {
            ssize_t ret1, ret2;
            char buf1[128], buf2[132];
            int fret = EXIT_SUCCESS;
            char *file;
  
            if (argc < 2) {
                    fprintf(stderr,
                            "Please specify a file with "
                            "\"system.posix_acl_access\" permissions set\n");
                    _exit(EXIT_FAILURE);
            }
            file = argv[1];
  
            ret1 = getxattr(file, "system.posix_acl_access",
                            buf1, sizeof(buf1));
            if (ret1 < 0) {
                    fprintf(stderr, "%s - Failed to retrieve "
                                    "\"system.posix_acl_access\" "
                                    "from \"%s\"\n", strerror(errno), file);
                    _exit(EXIT_FAILURE);
            }
  
            ret2 = getxattr(file, "system.posix_acl_access",
                            buf2, sizeof(buf2));
            if (ret2 < 0) {
                    fprintf(stderr, "%s - Failed to retrieve "
                                    "\"system.posix_acl_access\" "
                                    "from \"%s\"\n", strerror(errno), file);
                    _exit(EXIT_FAILURE);
            }
  
            if (ret1 != ret2) {
                    fprintf(stderr, "The value of \"system.posix_acl_"
                                    "access\" for file \"%s\" changed "
                                    "between two successive calls\n", file);
                    _exit(EXIT_FAILURE);
            }
  
            for (ssize_t i = 0; i < ret2; i++) {
                    if (buf1[i] == buf2[i])
                            continue;
  
                    fprintf(stderr,
                            "Unexpected different in byte %zd: "
                            "%02x != %02x\n", i, buf1[i], buf2[i]);
                    fret = EXIT_FAILURE;
            }
  
            if (fret == EXIT_SUCCESS)
                    fprintf(stderr, "Test passed\n");
            else
                    fprintf(stderr, "Test failed\n");
  
            _exit(fret);
    }
  and run:
  
    ./tester acl_posix
  
  On a non-fixed up kernel this should return something like:
  
    root@c1:/# ./t
    Unexpected different in byte 16: ffffffa0 != 00
    Unexpected different in byte 17: ffffff86 != 00
    Unexpected different in byte 18: 01 != 00
  
  and on a fixed kernel:
  
    root@c1:~# ./t
    Test passed
  
- Please backport this to the 4.15 (bionic) and 4.4 (xenial) kernels. :)
  
- Thanks!
- Christian
+ == Fix ==
+ 82c9a927bc5d ("getxattr: use correct xattr length")
+ 
+ == Regression Potential ==
+ Low.  One liner that passes the actual length of the xattr as returned by
+ vfs_getxattr() down.
+ 
+ == Test Case ==
+ A test kernel was built with this patch and tested by the original bug 
reporter.
+ The bug reporter states the test kernel resolved the bug.

-- 
You received this bug notification because you are a member of Kernel
Packages, which is subscribed to linux in Ubuntu.
https://bugs.launchpad.net/bugs/1789746

Title:
  getxattr: always handle namespaced attributes

Status in linux package in Ubuntu:
  Fix Committed
Status in linux source package in Xenial:
  In Progress
Status in linux source package in Bionic:
  In Progress
Status in linux source package in Cosmic:
  Fix Committed

Bug description:
  
  == SRU Justification ==
  When running in a container with a user namespace, if you call getxattr
  with name = "system.posix_acl_access" and size % 8 != 4, then getxattr
  silently skips the user namespace fixup that it normally does resulting in
  un-fixed-up data being returned.
  This is caused by posix_acl_fix_xattr_to_user() being passed the total
  buffer size and not the actual size of the xattr as returned by
  vfs_getxattr().

  I have pushed a commit upstream that fixes this bug:

  
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=82c9a927bc5df6e06b72d206d24a9d10cced4eb5

  This commit passes the actual length of the xattr as returned by
  vfs_getxattr() down.

  A reproducer for the issue is:

    touch acl_posix

    setfacl -m user:0:rwx acl_posix

  and the compile:

    #define _GNU_SOURCE
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <attr/xattr.h>

    /* Run in user namespace with nsuid 0 mapped to uid != 0 on the host. */
    int main(int argc, void **argv)
    {
            ssize_t ret1, ret2;
            char buf1[128], buf2[132];
            int fret = EXIT_SUCCESS;
            char *file;

            if (argc < 2) {
                    fprintf(stderr,
                            "Please specify a file with "
                            "\"system.posix_acl_access\" permissions set\n");
                    _exit(EXIT_FAILURE);
            }
            file = argv[1];

            ret1 = getxattr(file, "system.posix_acl_access",
                            buf1, sizeof(buf1));
            if (ret1 < 0) {
                    fprintf(stderr, "%s - Failed to retrieve "
                                    "\"system.posix_acl_access\" "
                                    "from \"%s\"\n", strerror(errno), file);
                    _exit(EXIT_FAILURE);
            }

            ret2 = getxattr(file, "system.posix_acl_access",
                            buf2, sizeof(buf2));
            if (ret2 < 0) {
                    fprintf(stderr, "%s - Failed to retrieve "
                                    "\"system.posix_acl_access\" "
                                    "from \"%s\"\n", strerror(errno), file);
                    _exit(EXIT_FAILURE);
            }

            if (ret1 != ret2) {
                    fprintf(stderr, "The value of \"system.posix_acl_"
                                    "access\" for file \"%s\" changed "
                                    "between two successive calls\n", file);
                    _exit(EXIT_FAILURE);
            }

            for (ssize_t i = 0; i < ret2; i++) {
                    if (buf1[i] == buf2[i])
                            continue;

                    fprintf(stderr,
                            "Unexpected different in byte %zd: "
                            "%02x != %02x\n", i, buf1[i], buf2[i]);
                    fret = EXIT_FAILURE;
            }

            if (fret == EXIT_SUCCESS)
                    fprintf(stderr, "Test passed\n");
            else
                    fprintf(stderr, "Test failed\n");

            _exit(fret);
    }
  and run:

    ./tester acl_posix

  On a non-fixed up kernel this should return something like:

    root@c1:/# ./t
    Unexpected different in byte 16: ffffffa0 != 00
    Unexpected different in byte 17: ffffff86 != 00
    Unexpected different in byte 18: 01 != 00

  and on a fixed kernel:

    root@c1:~# ./t
    Test passed

  
  == Fix ==
  82c9a927bc5d ("getxattr: use correct xattr length")

  == Regression Potential ==
  Low.  One liner that passes the actual length of the xattr as returned by
  vfs_getxattr() down.

  == Test Case ==
  A test kernel was built with this patch and tested by the original bug 
reporter.
  The bug reporter states the test kernel resolved the bug.

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1789746/+subscriptions

-- 
Mailing list: https://launchpad.net/~kernel-packages
Post to     : kernel-packages@lists.launchpad.net
Unsubscribe : https://launchpad.net/~kernel-packages
More help   : https://help.launchpad.net/ListHelp

Reply via email to