selinux.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /* SELinux access controls for nscd.
  2. Copyright (C) 2004-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include "config.h"
  16. #include <error.h>
  17. #include <errno.h>
  18. #include <libintl.h>
  19. #include <pthread.h>
  20. #include <stdarg.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <syslog.h>
  24. #include <unistd.h>
  25. #include <sys/prctl.h>
  26. #include <selinux/avc.h>
  27. #include <selinux/selinux.h>
  28. #ifdef HAVE_LIBAUDIT
  29. # include <libaudit.h>
  30. #endif
  31. #include <libc-diag.h>
  32. #include "dbg_log.h"
  33. #include "selinux.h"
  34. #ifdef HAVE_SELINUX
  35. /* Global variable to tell if the kernel has SELinux support. */
  36. int selinux_enabled;
  37. /* Define mappings of request type to AVC permission name. */
  38. static const char *perms[LASTREQ] =
  39. {
  40. [GETPWBYNAME] = "getpwd",
  41. [GETPWBYUID] = "getpwd",
  42. [GETGRBYNAME] = "getgrp",
  43. [GETGRBYGID] = "getgrp",
  44. [GETHOSTBYNAME] = "gethost",
  45. [GETHOSTBYNAMEv6] = "gethost",
  46. [GETHOSTBYADDR] = "gethost",
  47. [GETHOSTBYADDRv6] = "gethost",
  48. [SHUTDOWN] = "admin",
  49. [GETSTAT] = "getstat",
  50. [INVALIDATE] = "admin",
  51. [GETFDPW] = "shmempwd",
  52. [GETFDGR] = "shmemgrp",
  53. [GETFDHST] = "shmemhost",
  54. [GETAI] = "gethost",
  55. [INITGROUPS] = "getgrp",
  56. [GETSERVBYNAME] = "getserv",
  57. [GETSERVBYPORT] = "getserv",
  58. [GETFDSERV] = "shmemserv",
  59. [GETNETGRENT] = "getnetgrp",
  60. [INNETGR] = "getnetgrp",
  61. [GETFDNETGR] = "shmemnetgrp",
  62. };
  63. /* Store an entry ref to speed AVC decisions. */
  64. static struct avc_entry_ref aeref;
  65. /* Thread to listen for SELinux status changes via netlink. */
  66. static pthread_t avc_notify_thread;
  67. #ifdef HAVE_LIBAUDIT
  68. /* Prototype for supporting the audit daemon */
  69. static void log_callback (const char *fmt, ...);
  70. #endif
  71. /* Prototypes for AVC callback functions. */
  72. static void *avc_create_thread (void (*run) (void));
  73. static void avc_stop_thread (void *thread);
  74. static void *avc_alloc_lock (void);
  75. static void avc_get_lock (void *lock);
  76. static void avc_release_lock (void *lock);
  77. static void avc_free_lock (void *lock);
  78. /* AVC callback structures for use in avc_init. */
  79. static const struct avc_log_callback log_cb =
  80. {
  81. #ifdef HAVE_LIBAUDIT
  82. .func_log = log_callback,
  83. #else
  84. .func_log = dbg_log,
  85. #endif
  86. .func_audit = NULL
  87. };
  88. static const struct avc_thread_callback thread_cb =
  89. {
  90. .func_create_thread = avc_create_thread,
  91. .func_stop_thread = avc_stop_thread
  92. };
  93. static const struct avc_lock_callback lock_cb =
  94. {
  95. .func_alloc_lock = avc_alloc_lock,
  96. .func_get_lock = avc_get_lock,
  97. .func_release_lock = avc_release_lock,
  98. .func_free_lock = avc_free_lock
  99. };
  100. #ifdef HAVE_LIBAUDIT
  101. /* The audit system's netlink socket descriptor */
  102. static int audit_fd = -1;
  103. /* When an avc denial occurs, log it to audit system */
  104. static void
  105. log_callback (const char *fmt, ...)
  106. {
  107. if (audit_fd >= 0)
  108. {
  109. va_list ap;
  110. va_start (ap, fmt);
  111. char *buf;
  112. int e = vasprintf (&buf, fmt, ap);
  113. if (e < 0)
  114. {
  115. buf = alloca (BUFSIZ);
  116. vsnprintf (buf, BUFSIZ, fmt, ap);
  117. }
  118. /* FIXME: need to attribute this to real user, using getuid for now */
  119. audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
  120. NULL, getuid ());
  121. if (e >= 0)
  122. free (buf);
  123. va_end (ap);
  124. }
  125. }
  126. /* Initialize the connection to the audit system */
  127. static void
  128. audit_init (void)
  129. {
  130. audit_fd = audit_open ();
  131. if (audit_fd < 0
  132. /* If kernel doesn't support audit, bail out */
  133. && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
  134. dbg_log (_("Failed opening connection to the audit subsystem: %m"));
  135. }
  136. # ifdef HAVE_LIBCAP
  137. static const cap_value_t new_cap_list[] =
  138. { CAP_AUDIT_WRITE };
  139. # define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0]))
  140. static const cap_value_t tmp_cap_list[] =
  141. { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
  142. # define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0]))
  143. cap_t
  144. preserve_capabilities (void)
  145. {
  146. if (getuid () != 0)
  147. /* Not root, then we cannot preserve anything. */
  148. return NULL;
  149. if (prctl (PR_SET_KEEPCAPS, 1) == -1)
  150. {
  151. dbg_log (_("Failed to set keep-capabilities"));
  152. do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
  153. /* NOTREACHED */
  154. }
  155. cap_t tmp_caps = cap_init ();
  156. cap_t new_caps = NULL;
  157. if (tmp_caps != NULL)
  158. new_caps = cap_init ();
  159. if (tmp_caps == NULL || new_caps == NULL)
  160. {
  161. if (tmp_caps != NULL)
  162. cap_free (tmp_caps);
  163. dbg_log (_("Failed to initialize drop of capabilities"));
  164. do_exit (EXIT_FAILURE, 0, _("cap_init failed"));
  165. }
  166. /* There is no reason why these should not work. */
  167. cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list,
  168. (cap_value_t *) new_cap_list, CAP_SET);
  169. cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list,
  170. (cap_value_t *) new_cap_list, CAP_SET);
  171. cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list,
  172. (cap_value_t *) tmp_cap_list, CAP_SET);
  173. cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list,
  174. (cap_value_t *) tmp_cap_list, CAP_SET);
  175. int res = cap_set_proc (tmp_caps);
  176. cap_free (tmp_caps);
  177. if (__glibc_unlikely (res != 0))
  178. {
  179. cap_free (new_caps);
  180. dbg_log (_("Failed to drop capabilities"));
  181. do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
  182. }
  183. return new_caps;
  184. }
  185. void
  186. install_real_capabilities (cap_t new_caps)
  187. {
  188. /* If we have no capabilities there is nothing to do here. */
  189. if (new_caps == NULL)
  190. return;
  191. if (cap_set_proc (new_caps))
  192. {
  193. cap_free (new_caps);
  194. dbg_log (_("Failed to drop capabilities"));
  195. do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
  196. /* NOTREACHED */
  197. }
  198. cap_free (new_caps);
  199. if (prctl (PR_SET_KEEPCAPS, 0) == -1)
  200. {
  201. dbg_log (_("Failed to unset keep-capabilities"));
  202. do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
  203. /* NOTREACHED */
  204. }
  205. }
  206. # endif /* HAVE_LIBCAP */
  207. #endif /* HAVE_LIBAUDIT */
  208. /* Determine if we are running on an SELinux kernel. Set selinux_enabled
  209. to the result. */
  210. void
  211. nscd_selinux_enabled (int *selinux_enabled)
  212. {
  213. *selinux_enabled = is_selinux_enabled ();
  214. if (*selinux_enabled < 0)
  215. {
  216. dbg_log (_("Failed to determine if kernel supports SELinux"));
  217. do_exit (EXIT_FAILURE, 0, NULL);
  218. }
  219. }
  220. /* Create thread for AVC netlink notification. */
  221. static void *
  222. avc_create_thread (void (*run) (void))
  223. {
  224. int rc;
  225. rc =
  226. pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
  227. if (rc != 0)
  228. do_exit (EXIT_FAILURE, rc, _("Failed to start AVC thread"));
  229. return &avc_notify_thread;
  230. }
  231. /* Stop AVC netlink thread. */
  232. static void
  233. avc_stop_thread (void *thread)
  234. {
  235. pthread_cancel (*(pthread_t *) thread);
  236. }
  237. /* Allocate a new AVC lock. */
  238. static void *
  239. avc_alloc_lock (void)
  240. {
  241. pthread_mutex_t *avc_mutex;
  242. avc_mutex = malloc (sizeof (pthread_mutex_t));
  243. if (avc_mutex == NULL)
  244. do_exit (EXIT_FAILURE, errno, _("Failed to create AVC lock"));
  245. pthread_mutex_init (avc_mutex, NULL);
  246. return avc_mutex;
  247. }
  248. /* Acquire an AVC lock. */
  249. static void
  250. avc_get_lock (void *lock)
  251. {
  252. pthread_mutex_lock (lock);
  253. }
  254. /* Release an AVC lock. */
  255. static void
  256. avc_release_lock (void *lock)
  257. {
  258. pthread_mutex_unlock (lock);
  259. }
  260. /* Free an AVC lock. */
  261. static void
  262. avc_free_lock (void *lock)
  263. {
  264. pthread_mutex_destroy (lock);
  265. free (lock);
  266. }
  267. /* avc_init (along with several other symbols) was marked as deprecated by the
  268. SELinux API starting from version 3.1. We use it here, but should
  269. eventually switch to the newer API. */
  270. DIAG_PUSH_NEEDS_COMMENT
  271. DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
  272. /* Initialize the user space access vector cache (AVC) for NSCD along with
  273. log/thread/lock callbacks. */
  274. void
  275. nscd_avc_init (void)
  276. {
  277. avc_entry_ref_init (&aeref);
  278. if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0)
  279. do_exit (EXIT_FAILURE, errno, _("Failed to start AVC"));
  280. else
  281. dbg_log (_("Access Vector Cache (AVC) started"));
  282. #ifdef HAVE_LIBAUDIT
  283. audit_init ();
  284. #endif
  285. }
  286. DIAG_POP_NEEDS_COMMENT
  287. /* security_context_t and sidput (along with several other symbols) were marked
  288. as deprecated by the SELinux API starting from version 3.1. We use them
  289. here, but should eventually switch to the newer API. */
  290. DIAG_PUSH_NEEDS_COMMENT
  291. DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
  292. /* Check the permission from the caller (via getpeercon) to nscd.
  293. Returns 0 if access is allowed, 1 if denied, and -1 on error.
  294. The SELinux policy, enablement, and permission bits are all dynamic and the
  295. caching done by glibc is not entirely correct. This nscd support should be
  296. rewritten to use selinux_check_permission. A rewrite is risky though and
  297. requires some refactoring. Currently we use symbolic mappings instead of
  298. compile time constants (which SELinux upstream says are going away), and we
  299. use security_deny_unknown to determine what to do if selinux-policy* doesn't
  300. have a definition for the the permission or object class we are looking
  301. up. */
  302. int
  303. nscd_request_avc_has_perm (int fd, request_type req)
  304. {
  305. /* Initialize to NULL so we know what to free in case of failure. */
  306. security_context_t scon = NULL;
  307. security_context_t tcon = NULL;
  308. security_id_t ssid = NULL;
  309. security_id_t tsid = NULL;
  310. int rc = -1;
  311. security_class_t sc_nscd;
  312. access_vector_t perm;
  313. int avc_deny_unknown;
  314. /* Check if SELinux denys or allows unknown object classes
  315. and permissions. It is 0 if they are allowed, 1 if they
  316. are not allowed and -1 on error. */
  317. if ((avc_deny_unknown = security_deny_unknown ()) == -1)
  318. dbg_log (_("Error querying policy for undefined object classes "
  319. "or permissions."));
  320. /* Get the security class for nscd. If this fails we will likely be
  321. unable to do anything unless avc_deny_unknown is 0. */
  322. sc_nscd = string_to_security_class ("nscd");
  323. if (sc_nscd == 0 && avc_deny_unknown == 1)
  324. dbg_log (_("Error getting security class for nscd."));
  325. /* Convert permission to AVC bits. */
  326. perm = string_to_av_perm (sc_nscd, perms[req]);
  327. if (perm == 0 && avc_deny_unknown == 1)
  328. dbg_log (_("Error translating permission name "
  329. "\"%s\" to access vector bit."), perms[req]);
  330. /* If the nscd security class was not found or perms were not
  331. found and AVC does not deny unknown values then allow it. */
  332. if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0)
  333. return 0;
  334. if (getpeercon (fd, &scon) < 0)
  335. {
  336. dbg_log (_("Error getting context of socket peer"));
  337. goto out;
  338. }
  339. if (getcon (&tcon) < 0)
  340. {
  341. dbg_log (_("Error getting context of nscd"));
  342. goto out;
  343. }
  344. if (avc_context_to_sid (scon, &ssid) < 0
  345. || avc_context_to_sid (tcon, &tsid) < 0)
  346. {
  347. dbg_log (_("Error getting sid from context"));
  348. goto out;
  349. }
  350. /* The SELinux API for avc_has_perm conflates access denied and error into
  351. the return code -1, while nscd_request_avs_has_perm has distinct error
  352. (-1) and denied (1) return codes. We map the avc_has_perm access denied or
  353. error into an access denied at the nscd interface level (we do accurately
  354. report error for the getpeercon, getcon, and avc_context_to_sid interfaces
  355. used above). */
  356. rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0;
  357. out:
  358. if (scon)
  359. freecon (scon);
  360. if (tcon)
  361. freecon (tcon);
  362. if (ssid)
  363. sidput (ssid);
  364. if (tsid)
  365. sidput (tsid);
  366. return rc;
  367. }
  368. DIAG_POP_NEEDS_COMMENT
  369. /* Wrapper to get AVC statistics. */
  370. void
  371. nscd_avc_cache_stats (struct avc_cache_stats *cstats)
  372. {
  373. avc_cache_stats (cstats);
  374. }
  375. /* Print the AVC statistics to stdout. */
  376. void
  377. nscd_avc_print_stats (struct avc_cache_stats *cstats)
  378. {
  379. printf (_("\nSELinux AVC Statistics:\n\n"
  380. "%15u entry lookups\n"
  381. "%15u entry hits\n"
  382. "%15u entry misses\n"
  383. "%15u entry discards\n"
  384. "%15u CAV lookups\n"
  385. "%15u CAV hits\n"
  386. "%15u CAV probes\n"
  387. "%15u CAV misses\n"),
  388. cstats->entry_lookups, cstats->entry_hits, cstats->entry_misses,
  389. cstats->entry_discards, cstats->cav_lookups, cstats->cav_hits,
  390. cstats->cav_probes, cstats->cav_misses);
  391. }
  392. #endif /* HAVE_SELINUX */