selinux_set_mapping(3)

πŸ“¦
version 3.11 Β· 3 versions
, in alpine 3.24, centos-stream 10, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu questing, ubuntu resolute, ubuntu stonking

πŸ’– selinux_set_mapping(3) πŸ’–

okay bestie, so this one lives in the SELinux API documentation section of the manual, and it's literally the page about dynamic object class and permission mapping. it's giving "make your own numbering system" energy, and honestly? kinda iconic.


✨ NAME ✨

selinux_set_mapping β€” establish dynamic object class and permission mapping πŸ¦‹


🌸 SYNOPSIS 🌸

#include <selinux/selinux.h>

struct security_class_mapping {
     const char *name;
     const char *perms[];
};

int selinux_set_mapping(const struct security_class_mapping *map);

πŸ‘‘ DESCRIPTION πŸ‘‘

so selinux_set_mapping() does the thing where it establishes a mapping from your ordering of object classes and permissions β†’ to the actual numbers that the currently loaded system policy is using. like, you pick the order you want, and this function translates it into policy reality. fr fr.

if you're using this function, there's a whole extra step you need to know about: apps should also set a SELINUX_CB_POLICYLOAD callback via selinux_set_callback(3). why? because that callback needs to call this function again whenever the policy reloads, so the mapping gets re-created in case the class or permission values changed in the new policy. policy reloads are messy like that. πŸ’€

and now for the plot twist: it's generally preferred to instead use selinux_check_access(3) rather than avc_has_perm(3) or security_compute_av(3), and to just… not use this function at all. no cap. that's straight from the page. πŸ™ˆ

once the mapping is established, all libselinux functions that operate on class and permission values will take the user-provided numbers. and those numbers are determined like this:

the map argument is an array of security_class_mapping structures, and it must be terminated by a structure whose name field is NULL. that's the little "we're done here" sentinel, bestie. except for that last structure, the name field should point to the string name of an object class, and the matching perms field should point to an array of permission bit names terminated by a NULL string. (yes, another NULL terminator. they love a NULL terminator here. πŸŽ€)

the object classes named in the mapping, and the bit indexes of each set of permission bits named in the mapping, are numbered in order starting from 1. those numbers are the values you should be passing to subsequent libselinux calls. periodt.


πŸ’… RETURN VALUE πŸ’…

  • 0 β€” returned on success ✨
  • -1 β€” returned on error, and errno gets set appropriately

πŸ”₯ ERRORS πŸ”₯

  • EINVAL β€” one of the class or permission names you requested in the mapping is not present in the loaded policy. (rip, that name doesn't exist in this policy πŸ’€)
  • ENOMEM β€” an attempt to allocate memory failed 😭

🌈 EXAMPLE 🌈

struct security_class_mapping map[] = {
    { "file", { "create", "unlink", "read", "write", NULL } },
    { "socket", { "bind", NULL } },
    { "process", { "signal", NULL } },
    { NULL }
};

if (selinux_set_mapping(map) < 0)
    exit(1);

so in this example, after the call has succeeded: classes file, socket, and process will be identified by 1, 2 and 3 respectively. and the permissions create, unlink, read, and write (for the file class) will be identified by 1, 2, 4, and 8 respectively. yes those are powers of two, she's doing bit math, she ate. πŸ‘‘

⚠️ classes and permissions that are not listed in the mapping cannot be used. like, at all. so don't forget anybody important. 🫢

πŸ¦‹ AUTHOR πŸ¦‹

Originally Eamon Walsh. Updated by Stephen Smalley <stephen.smalley.work@gmail.com> πŸ’œ


⭐ SEE ALSO ⭐


k bye bestie, go map those classes πŸ’–βœ¨πŸŽ€ β€” this lil page is from the SELinux API documentation, dated 12 Jun 2008, and it's the selinux_set_mapping(3) page itself. stay slay, stay selinux. 🧚🌈