1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Dan Walsh
8 #include "selinux-access.h"
13 #include <selinux/avc.h>
14 #include <selinux/selinux.h>
22 #include "alloc-util.h"
26 #include "path-util.h"
27 #include "selinux-util.h"
28 #include "stdio-util.h"
32 static bool initialized
= false;
41 Any time an access gets denied this callback will be called
42 with the audit data. We then need to just copy the audit data into the msgbuf.
44 static int audit_callback(
50 const struct audit_info
*audit
= auditdata
;
51 uid_t uid
= 0, login_uid
= 0;
53 char login_uid_buf
[DECIMAL_STR_MAX(uid_t
) + 1] = "n/a";
54 char uid_buf
[DECIMAL_STR_MAX(uid_t
) + 1] = "n/a";
55 char gid_buf
[DECIMAL_STR_MAX(gid_t
) + 1] = "n/a";
57 if (sd_bus_creds_get_audit_login_uid(audit
->creds
, &login_uid
) >= 0)
58 xsprintf(login_uid_buf
, UID_FMT
, login_uid
);
59 if (sd_bus_creds_get_euid(audit
->creds
, &uid
) >= 0)
60 xsprintf(uid_buf
, UID_FMT
, uid
);
61 if (sd_bus_creds_get_egid(audit
->creds
, &gid
) >= 0)
62 xsprintf(gid_buf
, GID_FMT
, gid
);
64 snprintf(msgbuf
, msgbufsize
,
65 "auid=%s uid=%s gid=%s%s%s%s%s%s%s",
66 login_uid_buf
, uid_buf
, gid_buf
,
67 audit
->path
? " path=\"" : "", strempty(audit
->path
), audit
->path
? "\"" : "",
68 audit
->cmdline
? " cmdline=\"" : "", strempty(audit
->cmdline
), audit
->cmdline
? "\"" : "");
73 static int callback_type_to_priority(int type
) {
92 libselinux uses this callback when access gets denied or other
93 events happen. If audit is turned on, messages will be reported
94 using audit netlink, otherwise they will be logged using the usual
97 Code copied from dbus and modified.
99 _printf_(2, 3) static int log_callback(int type
, const char *fmt
, ...) {
109 _cleanup_free_
char *buf
= NULL
;
113 r
= vasprintf(&buf
, fmt
, ap
);
117 audit_log_user_avc_message(fd
, AUDIT_USER_AVC
, buf
, NULL
, NULL
, NULL
, 0);
123 fmt2
= strjoina("selinux: ", fmt
);
126 #pragma GCC diagnostic push
127 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
128 log_internalv(LOG_AUTH
| callback_type_to_priority(type
),
129 0, __FILE__
, __LINE__
, __FUNCTION__
,
131 #pragma GCC diagnostic pop
137 static int access_init(sd_bus_error
*error
) {
139 if (!mac_selinux_use())
145 if (avc_open(NULL
, 0) != 0) {
146 int enforce
, saved_errno
= errno
;
148 enforce
= security_getenforce();
149 log_full_errno(enforce
!= 0 ? LOG_ERR
: LOG_WARNING
, saved_errno
, "Failed to open the SELinux AVC: %m");
151 /* If enforcement isn't on, then let's suppress this
152 * error, and just don't do any AVC checks. The
153 * warning we printed is hence all the admin will
158 /* Return an access denied error, if we couldn't load
159 * the AVC but enforcing mode was on, or we couldn't
160 * determine whether it is one. */
161 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to open the SELinux AVC: %s", strerror(saved_errno
));
164 selinux_set_callback(SELINUX_CB_AUDIT
, (union selinux_callback
) audit_callback
);
165 selinux_set_callback(SELINUX_CB_LOG
, (union selinux_callback
) log_callback
);
172 This function communicates with the kernel to check whether or not it should
174 If the machine is in permissive mode it will return ok. Audit messages will
175 still be generated if the access would be denied in enforcing mode.
177 int mac_selinux_generic_access_check(
178 sd_bus_message
*message
,
180 const char *permission
,
181 sd_bus_error
*error
) {
183 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
184 const char *tclass
= NULL
, *scon
= NULL
;
185 struct audit_info audit_info
= {};
186 _cleanup_free_
char *cl
= NULL
;
188 char **cmdline
= NULL
;
195 r
= access_init(error
);
199 r
= sd_bus_query_sender_creds(
201 SD_BUS_CREDS_PID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EGID
|
202 SD_BUS_CREDS_CMDLINE
|SD_BUS_CREDS_AUDIT_LOGIN_UID
|
203 SD_BUS_CREDS_SELINUX_CONTEXT
|
204 SD_BUS_CREDS_AUGMENT
/* get more bits from /proc */,
209 /* The SELinux context is something we really should have
210 * gotten directly from the message or sender, and not be an
211 * augmented field. If it was augmented we cannot use it for
212 * authorization, since this is racy and vulnerable. Let's add
213 * an extra check, just in case, even though this really
214 * shouldn't be possible. */
215 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_SELINUX_CONTEXT
) == 0, -EPERM
);
217 r
= sd_bus_creds_get_selinux_context(creds
, &scon
);
222 /* Get the file context of the unit file */
224 r
= getfilecon_raw(path
, &fcon
);
226 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to get file context on %s.", path
);
232 r
= getcon_raw(&fcon
);
234 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to get current context.");
241 sd_bus_creds_get_cmdline(creds
, &cmdline
);
242 cl
= strv_join(cmdline
, " ");
244 audit_info
.creds
= creds
;
245 audit_info
.path
= path
;
246 audit_info
.cmdline
= cl
;
248 r
= selinux_check_access(scon
, fcon
, tclass
, permission
, &audit_info
);
250 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "SELinux policy denies access.");
252 log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon
, fcon
, tclass
, permission
, path
, cl
, r
);
257 if (r
< 0 && security_getenforce() != 1) {
258 sd_bus_error_free(error
);
267 int mac_selinux_generic_access_check(
268 sd_bus_message
*message
,
270 const char *permission
,
271 sd_bus_error
*error
) {