1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2012 Dan Walsh
6 #include "selinux-access.h"
11 #include <selinux/avc.h>
12 #include <selinux/selinux.h>
20 #include "alloc-util.h"
24 #include "path-util.h"
25 #include "selinux-util.h"
26 #include "stdio-util.h"
30 static bool initialized
= false;
39 Any time an access gets denied this callback will be called
40 with the audit data. We then need to just copy the audit data into the msgbuf.
42 static int audit_callback(
48 const struct audit_info
*audit
= auditdata
;
49 uid_t uid
= 0, login_uid
= 0;
51 char login_uid_buf
[DECIMAL_STR_MAX(uid_t
) + 1] = "n/a";
52 char uid_buf
[DECIMAL_STR_MAX(uid_t
) + 1] = "n/a";
53 char gid_buf
[DECIMAL_STR_MAX(gid_t
) + 1] = "n/a";
55 if (sd_bus_creds_get_audit_login_uid(audit
->creds
, &login_uid
) >= 0)
56 xsprintf(login_uid_buf
, UID_FMT
, login_uid
);
57 if (sd_bus_creds_get_euid(audit
->creds
, &uid
) >= 0)
58 xsprintf(uid_buf
, UID_FMT
, uid
);
59 if (sd_bus_creds_get_egid(audit
->creds
, &gid
) >= 0)
60 xsprintf(gid_buf
, GID_FMT
, gid
);
62 snprintf(msgbuf
, msgbufsize
,
63 "auid=%s uid=%s gid=%s%s%s%s%s%s%s",
64 login_uid_buf
, uid_buf
, gid_buf
,
65 audit
->path
? " path=\"" : "", strempty(audit
->path
), audit
->path
? "\"" : "",
66 audit
->cmdline
? " cmdline=\"" : "", strempty(audit
->cmdline
), audit
->cmdline
? "\"" : "");
71 static int callback_type_to_priority(int type
) {
90 libselinux uses this callback when access gets denied or other
91 events happen. If audit is turned on, messages will be reported
92 using audit netlink, otherwise they will be logged using the usual
95 Code copied from dbus and modified.
97 _printf_(2, 3) static int log_callback(int type
, const char *fmt
, ...) {
107 _cleanup_free_
char *buf
= NULL
;
111 r
= vasprintf(&buf
, fmt
, ap
);
115 audit_log_user_avc_message(fd
, AUDIT_USER_AVC
, buf
, NULL
, NULL
, NULL
, 0);
121 fmt2
= strjoina("selinux: ", fmt
);
124 #pragma GCC diagnostic push
125 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
126 log_internalv(LOG_AUTH
| callback_type_to_priority(type
),
127 0, __FILE__
, __LINE__
, __FUNCTION__
,
129 #pragma GCC diagnostic pop
135 static int access_init(sd_bus_error
*error
) {
137 if (!mac_selinux_use())
143 if (avc_open(NULL
, 0) != 0) {
144 int enforce
, saved_errno
= errno
;
146 enforce
= security_getenforce();
147 log_full_errno(enforce
!= 0 ? LOG_ERR
: LOG_WARNING
, saved_errno
, "Failed to open the SELinux AVC: %m");
149 /* If enforcement isn't on, then let's suppress this
150 * error, and just don't do any AVC checks. The
151 * warning we printed is hence all the admin will
156 /* Return an access denied error, if we couldn't load
157 * the AVC but enforcing mode was on, or we couldn't
158 * determine whether it is one. */
159 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to open the SELinux AVC: %s", strerror(saved_errno
));
162 selinux_set_callback(SELINUX_CB_AUDIT
, (union selinux_callback
) audit_callback
);
163 selinux_set_callback(SELINUX_CB_LOG
, (union selinux_callback
) log_callback
);
170 This function communicates with the kernel to check whether or not it should
172 If the machine is in permissive mode it will return ok. Audit messages will
173 still be generated if the access would be denied in enforcing mode.
175 int mac_selinux_generic_access_check(
176 sd_bus_message
*message
,
178 const char *permission
,
179 sd_bus_error
*error
) {
181 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
182 const char *tclass
= NULL
, *scon
= NULL
;
183 struct audit_info audit_info
= {};
184 _cleanup_free_
char *cl
= NULL
;
186 char **cmdline
= NULL
;
193 r
= access_init(error
);
197 r
= sd_bus_query_sender_creds(
199 SD_BUS_CREDS_PID
|SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EGID
|
200 SD_BUS_CREDS_CMDLINE
|SD_BUS_CREDS_AUDIT_LOGIN_UID
|
201 SD_BUS_CREDS_SELINUX_CONTEXT
|
202 SD_BUS_CREDS_AUGMENT
/* get more bits from /proc */,
207 /* The SELinux context is something we really should have
208 * gotten directly from the message or sender, and not be an
209 * augmented field. If it was augmented we cannot use it for
210 * authorization, since this is racy and vulnerable. Let's add
211 * an extra check, just in case, even though this really
212 * shouldn't be possible. */
213 assert_return((sd_bus_creds_get_augmented_mask(creds
) & SD_BUS_CREDS_SELINUX_CONTEXT
) == 0, -EPERM
);
215 r
= sd_bus_creds_get_selinux_context(creds
, &scon
);
220 /* Get the file context of the unit file */
222 r
= getfilecon_raw(path
, &fcon
);
224 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to get file context on %s.", path
);
230 r
= getcon_raw(&fcon
);
232 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Failed to get current context.");
239 sd_bus_creds_get_cmdline(creds
, &cmdline
);
240 cl
= strv_join(cmdline
, " ");
242 audit_info
.creds
= creds
;
243 audit_info
.path
= path
;
244 audit_info
.cmdline
= cl
;
246 r
= selinux_check_access(scon
, fcon
, tclass
, permission
, &audit_info
);
248 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "SELinux policy denies access.");
250 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
);
255 if (r
< 0 && security_getenforce() != 1) {
256 sd_bus_error_free(error
);
265 int mac_selinux_generic_access_check(
266 sd_bus_message
*message
,
268 const char *permission
,
269 sd_bus_error
*error
) {