#include "parse-util.h"
#include "process-util.h"
#include "socket-util.h"
+#include "stat-util.h"
#include "user-util.h"
+#include "virt.h"
-int audit_session_from_pid(pid_t pid, uint32_t *id) {
- _cleanup_free_ char *s = NULL;
- const char *p;
- uint32_t u;
+static int audit_read_field(const PidRef *pid, const char *field, char **ret) {
int r;
- assert(id);
+ assert(field);
+ assert(ret);
- /* We don't convert ENOENT to ESRCH here, since we can't
- * really distinguish between "audit is not available in the
- * kernel" and "the process does not exist", both which will
- * result in ENOENT. */
+ if (!pidref_is_set(pid))
+ return -ESRCH;
- p = procfs_file_alloca(pid, "sessionid");
+ /* Auditing is currently not virtualized for containers. Let's hence not use the audit session ID or
+ * login UID for now, it will be leaked in from the host */
+ if (detect_container() > 0)
+ return -ENODATA;
- r = read_one_line_file(p, &s);
- if (r < 0)
+ const char *p = procfs_file_alloca(pid->pid, field);
+
+ _cleanup_free_ char *s = NULL;
+ bool enoent = false;
+ r = read_virtual_file(p, SIZE_MAX, &s, /* ret_size= */ NULL);
+ if (r == -ENOENT) {
+ if (proc_mounted() == 0)
+ return -ENOSYS;
+ enoent = true;
+ } else if (r < 0)
return r;
- r = safe_atou32(s, &u);
+ r = pidref_verify(pid);
if (r < 0)
return r;
- if (!audit_session_is_valid(u))
+ if (enoent) /* We got ENOENT, but /proc/ was mounted and the PID still valid? In that case it appears
+ * auditing is not supported by the kernel. */
return -ENODATA;
- *id = u;
+ delete_trailing_chars(s, NEWLINE);
+
+ *ret = TAKE_PTR(s);
return 0;
}
-int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
+int audit_session_from_pid(const PidRef *pid, uint32_t *ret_id) {
_cleanup_free_ char *s = NULL;
- const char *p;
- uid_t u;
int r;
- assert(uid);
-
- p = procfs_file_alloca(pid, "loginuid");
+ r = audit_read_field(pid, "sessionid", &s);
+ if (r < 0)
+ return r;
- r = read_one_line_file(p, &s);
+ uint32_t u;
+ r = safe_atou32(s, &u);
if (r < 0)
return r;
- r = parse_uid(s, &u);
- if (r == -ENXIO) /* the UID was -1 */
+ if (!audit_session_is_valid(u))
return -ENODATA;
+
+ if (ret_id)
+ *ret_id = u;
+
+ return 0;
+}
+
+int audit_loginuid_from_pid(const PidRef *pid, uid_t *ret_uid) {
+ _cleanup_free_ char *s = NULL;
+ int r;
+
+ r = audit_read_field(pid, "loginuid", &s);
if (r < 0)
return r;
- *uid = u;
- return 0;
+ if (streq(s, "4294967295")) /* loginuid as 4294967295 means not part of any session. */
+ return -ENODATA;
+
+ return parse_uid(s, ret_uid);
}
static int try_audit_request(int fd) {
#include <stdint.h>
#include <sys/types.h>
+#include "pidref.h"
+
#define AUDIT_SESSION_INVALID UINT32_MAX
-int audit_session_from_pid(pid_t pid, uint32_t *id);
-int audit_loginuid_from_pid(pid_t pid, uid_t *uid);
+int audit_session_from_pid(const PidRef *pid, uint32_t *id);
+int audit_loginuid_from_pid(const PidRef *pid, uid_t *uid);
bool use_audit(void);
client_context_read_basic(c);
(void) client_context_read_label(c, label, label_size);
- (void) audit_session_from_pid(c->pid, &c->auditid);
- (void) audit_loginuid_from_pid(c->pid, &c->loginuid);
+ (void) audit_session_from_pid(&PIDREF_MAKE_FROM_PID(c->pid), &c->auditid);
+ (void) audit_loginuid_from_pid(&PIDREF_MAKE_FROM_PID(c->pid), &c->loginuid);
(void) client_context_read_cgroup(s, c, unit_id);
(void) client_context_read_invocation_id(s, c);
}
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
- r = audit_session_from_pid(pidref->pid, &c->audit_session_id);
+ r = audit_session_from_pid(pidref, &c->audit_session_id);
if (r == -ENODATA) {
/* ENODATA means: no audit session id assigned */
c->audit_session_id = AUDIT_SESSION_INVALID;
}
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
- r = audit_loginuid_from_pid(pidref->pid, &c->audit_login_uid);
+ r = audit_loginuid_from_pid(pidref, &c->audit_login_uid);
if (r == -ENODATA) {
/* ENODATA means: no audit login uid assigned */
c->audit_login_uid = UID_INVALID;
"Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.",
m->sessions_max);
- (void) audit_session_from_pid(leader.pid, &audit_id);
+ (void) audit_session_from_pid(&leader, &audit_id);
if (audit_session_is_valid(audit_id)) {
/* Keep our session IDs and the audit session IDs in sync */
s->leader_fd_saved = true;
}
- (void) audit_session_from_pid(s->leader.pid, &s->audit_id);
+ (void) audit_session_from_pid(&s->leader, &s->audit_id);
return 1;
}
'test-alloc-util.c',
'test-architecture.c',
'test-argv-util.c',
+ 'test-audit-util.c',
'test-barrier.c',
'test-bitfield.c',
'test-bitmap.c',
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "audit-util.h"
+#include "tests.h"
+
+TEST(audit_loginuid_from_pid) {
+ _cleanup_(pidref_done) PidRef self = PIDREF_NULL, pid1 = PIDREF_NULL;
+ int r;
+
+ assert_se(pidref_set_self(&self) >= 0);
+ assert_se(pidref_set_pid(&pid1, 1) >= 0);
+
+ uid_t uid;
+ r = audit_loginuid_from_pid(&self, &uid);
+ assert_se(r >= 0 || r == -ENODATA);
+ if (r >= 0)
+ log_info("self audit login uid: " UID_FMT, uid);
+
+ assert_se(audit_loginuid_from_pid(&pid1, &uid) == -ENODATA);
+
+ uint32_t sessionid;
+ r = audit_session_from_pid(&self, &sessionid);
+ assert_se(r >= 0 || r == -ENODATA);
+ if (r >= 0)
+ log_info("self audit session id: %" PRIu32, sessionid);
+
+ assert_se(audit_session_from_pid(&pid1, &sessionid) == -ENODATA);
+}
+
+static int intro(void) {
+ log_show_color(true);
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);