1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "selinux-access.h"
8 #include <selinux/avc.h>
9 #include <selinux/selinux.h>
17 #include "alloc-util.h"
21 #include "path-util.h"
22 #include "selinux-util.h"
23 #include "stdio-util.h"
27 static bool initialized
= false;
36 Any time an access gets denied this callback will be called
37 with the audit data. We then need to just copy the audit data into the msgbuf.
39 static int audit_callback(
45 const struct audit_info
*audit
= auditdata
;
46 uid_t uid
= 0, login_uid
= 0;
48 char login_uid_buf
[DECIMAL_STR_MAX(uid_t
) + 1] = "n/a";
49 char uid_buf
[DECIMAL_STR_MAX(uid_t
) + 1] = "n/a";
50 char gid_buf
[DECIMAL_STR_MAX(gid_t
) + 1] = "n/a";
52 if (sd_bus_creds_get_audit_login_uid(audit
->creds
, &login_uid
) >= 0)
53 xsprintf(login_uid_buf
, UID_FMT
, login_uid
);
54 if (sd_bus_creds_get_euid(audit
->creds
, &uid
) >= 0)
55 xsprintf(uid_buf
, UID_FMT
, uid
);
56 if (sd_bus_creds_get_egid(audit
->creds
, &gid
) >= 0)
57 xsprintf(gid_buf
, GID_FMT
, gid
);
59 snprintf(msgbuf
, msgbufsize
,
60 "auid=%s uid=%s gid=%s%s%s%s%s%s%s",
61 login_uid_buf
, uid_buf
, gid_buf
,
62 audit
->path
? " path=\"" : "", strempty(audit
->path
), audit
->path
? "\"" : "",
63 audit
->cmdline
? " cmdline=\"" : "", strempty(audit
->cmdline
), audit
->cmdline
? "\"" : "");
68 static int callback_type_to_priority(int type
) {
87 libselinux uses this callback when access gets denied or other
88 events happen. If audit is turned on, messages will be reported
89 using audit netlink, otherwise they will be logged using the usual
92 Code copied from dbus and modified.
94 _printf_(2, 3) static int log_callback(int type
, const char *fmt
, ...) {
104 _cleanup_free_
char *buf
= NULL
;
108 r
= vasprintf(&buf
, fmt
, ap
);
112 audit_log_user_avc_message(fd
, AUDIT_USER_AVC
, buf
, NULL
, NULL
, NULL
, 0);
118 fmt2
= strjoina("selinux: ", fmt
);
121 #pragma GCC diagnostic push
122 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
123 log_internalv(LOG_AUTH
| callback_type_to_priority(type
),
124 0, __FILE__
, __LINE__
, __FUNCTION__
,
126 #pragma GCC diagnostic pop
132 static int access_init(sd_bus_error
*error
) {
134 if (!mac_selinux_use())
140 if (avc_open(NULL
, 0) != 0) {
141 int enforce
, saved_errno
= errno
;
143 enforce
= security_getenforce();
144 log_full_errno(enforce
!= 0 ? LOG_ERR
: LOG_WARNING
, saved_errno
, "Failed to open the SELinux AVC: %m");
146 /* If enforcement isn't on, then let's suppress this
147 * error, and just don't do any AVC checks. The
148 * warning we printed is hence all the admin will
153 /* Return an access denied error, if we couldn't load
154 * the AVC but enforcing mode was on, or we couldn't
155 * determine whether it is one. */
156 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to open the SELinux AVC: %s", strerror(saved_errno
));
159 selinux_set_callback(SELINUX_CB_AUDIT
, (union selinux_callback
) audit_callback
);
160 selinux_set_callback(SELINUX_CB_LOG
, (union selinux_callback
) log_callback
);
167 This function communicates with the kernel to check whether or not it should
169 If the machine is in permissive mode it will return ok. Audit messages will
170 still be generated if the access would be denied in enforcing mode.
172 int mac_selinux_generic_access_check(
173 sd_bus_message
*message
,
175 const char *permission
,
176 sd_bus_error
*error
) {
178 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
179 const char *tclass
= NULL
, *scon
= NULL
;
180 struct audit_info audit_info
= {};
181 _cleanup_free_
char *cl
= NULL
;
183 char **cmdline
= NULL
;
190 r
= access_init(error
);
194 r
= sd_bus_query_sender_creds(
196 SD_BUS_CREDS_PID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EGID
|
197 SD_BUS_CREDS_CMDLINE
|SD_BUS_CREDS_AUDIT_LOGIN_UID
|
198 SD_BUS_CREDS_SELINUX_CONTEXT
|
199 SD_BUS_CREDS_AUGMENT
/* get more bits from /proc */,
204 /* The SELinux context is something we really should have
205 * gotten directly from the message or sender, and not be an
206 * augmented field. If it was augmented we cannot use it for
207 * authorization, since this is racy and vulnerable. Let's add
208 * an extra check, just in case, even though this really
209 * shouldn't be possible. */
210 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_SELINUX_CONTEXT
) == 0, -EPERM
);
212 r
= sd_bus_creds_get_selinux_context(creds
, &scon
);
217 /* Get the file context of the unit file */
219 r
= getfilecon_raw(path
, &fcon
);
221 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to get file context on %s.", path
);
227 r
= getcon_raw(&fcon
);
229 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to get current context.");
236 sd_bus_creds_get_cmdline(creds
, &cmdline
);
237 cl
= strv_join(cmdline
, " ");
239 audit_info
.creds
= creds
;
240 audit_info
.path
= path
;
241 audit_info
.cmdline
= cl
;
243 r
= selinux_check_access(scon
, fcon
, tclass
, permission
, &audit_info
);
245 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "SELinux policy denies access.");
247 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
);
252 if (r
< 0 && security_getenforce() != 1) {
253 sd_bus_error_free(error
);
262 int mac_selinux_generic_access_check(
263 sd_bus_message
*message
,
265 const char *permission
,
266 sd_bus_error
*error
) {