Re: Filesystem extended attributes and Capsicum

From: Alan Somers <asomers_at_freebsd.org>
Date: Sat, 23 Mar 2024 00:20:48 UTC
On Fri, Mar 22, 2024 at 5:38 PM Shawn Webb <shawn.webb@hardenedbsd.org> wrote:
>
> Hey all,
>
> I'm writing an application in which I hope to enable Capsicum. I'm
> experiencing an issue whereby extattr_get_fd fails with a file
> descriptor that has all the extended attribute capabilities enabled
> (CAP_EXTATTR_DELETE, CAP_EXTATTR_GET, CAP_EXTATTR_LIST, and
> CAP_EXTATTR_SET).
>
> Looking at the kernel source (sys/kern/vfs_extattr.c) tells me that
> kern_extattr_get_fd only requires CAP_EXTATTR_GET.
>
> So I'm a bit puzzled as to why my call to extattr_get_fd(2) is
> failing. Am I doing something wrong or are filesystem extended
> attributes not supported in a Capabilities-enabled process?
>
> Here's how I'm creating the file descriptor (before calling
> cap_enter(2)):
>
> ==== BEGIN CODE ====
> static int
> open_file(const char *path)
> {
>         cap_rights_t rights;
>         int fd;
>
>         fd = open(path, O_PATH | O_CLOEXEC);
>         if (fd == -1) {
>                 return (-1);
>         }
>
>         memset(&rights, 0, sizeof(rights));
>         cap_rights_init(&rights, CAP_EXTATTR_DELETE, CAP_EXTATTR_GET,
>             CAP_EXTATTR_LIST, CAP_EXTATTR_SET);
>         cap_rights_limit(fd, &rights);
>
>         return (fd);
> }
> ==== END CODE ====
>
> Eventually, after calling cap_enter(2), the following code is called:
>
> ==== BEGIN CODE ====
> #define ATTRNAME_ENABLED "hbsd.pax.aslr"
>         sz = extattr_get_fd(fd, ctx->hc_namespace, ATTRNAME_ENABLED, NULL, 0);
>         if (sz <= 0) {
>                 if (errno == ENOATTR) {
>                         /*
>                         * This is okay, it just means that nothing has been set.
>                         * No error condition here.
>                         */
>                         return (RES_SUCCESS);
>                 }
>                 return (RES_FAIL);
>         }
> ==== END CODE ====
>
> For reference, the program's code is here:
> https://git.hardenedbsd.org/shawn.webb/hbsdctrl/-/tree/main?ref_type=heads
>
> The library code, which is what's responsible for calling the
> filesystem extended attribute related syscalls is here:
>
> https://git.hardenedbsd.org/hardenedbsd/HardenedBSD/-/tree/hardened/current/hbsdcontrol-v2/lib/libhbsdcontrol?ref_type=heads
>
> From the rights(4) manual page, I'm instructed all I need are to apply
> those capabilities to that file descriptor:
>
> ==== BEGIN PASTE ====
>      CAP_EXTATTR_DELETE   Permit extattr_delete_fd(2).
>
>      CAP_EXTATTR_GET      Permit extattr_get_fd(2).
>
>      CAP_EXTATTR_LIST     Permit extattr_list_fd(2).
>
>      CAP_EXTATTR_SET      Permit extattr_set_fd(2).
> ==== END PASTE ====
>
> So I'm a bit unsure if I'm doing something wrong.
>
> Thanks,
>
> --
> Shawn Webb
> Cofounder / Security Engineer
> HardenedBSD
>
> Tor-ified Signal: +1 303-901-1600 / shawn_webb_opsec.50
> https://git.hardenedbsd.org/hardenedbsd/pubkeys/-/raw/master/Shawn_Webb/03A4CBEBB82EA5A67D9F3853FF2E67A277F8E1FA.pub.asc

What error code does it fail with?  If it's ENOTCAPABLE, then I
suggest using dtrace to find the reason why it fails.  Do something
like this:

dtrace -i 'fbt:kernel::return /arg1 == 93 && pid == $target/
{trace(".");}' -c ./my_application

That will print the name of every non-inlined kernel function that
returns ENOTCAPABLE during your process.  But it will also print the
names of any other kernel functions that return an integer value of
93.  From there, guess which function is the real source of the error.
Then you can do

dtrace -i 'fbt:kernel:some_function:return /arg1 == 93 && pid ==
$target/ {stack();}' -c ./myapplication

to get more information.

-Alan