/
githubmirror
/
audit-userspace
Обзор
Документация
Войти
/
githubmirror
/
audit-userspace
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/ausearch-lookup.c
597 строк
13 KB
Steve Grubb
ausearch: handle UID cache allocation failures
13 июл 2026, 06:03
13 июл 2026, 06:03
df1c284
Код
Авторство
О чём код?
/* * ausearch-lookup.c - Lookup values to something more readable * Copyright (c) 2005-06,2011-12,2015-17 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb <sgrubb@redhat.com> */ #include "config.h" #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <linux/net.h> #include "ausearch-lookup.h" #include "ausearch-options.h" #include "ausearch-nvpair.h" #include "auparse-idata.h" static int interp_init = 0; static auparse_state_t *au = NULL; /* This is the name/value pair used by search tables */ struct nv_pair { int value; const char *name; }; /* The machine based on elf type */ static int machine = 0; static const char *Q = "?"; static const char *results[3]= { "unset", "denied", "granted" }; static const char *success[3]= { "unset", "no", "yes" }; static const char *aulookup_socketcall(long sc); static const char *aulookup_ipccall(long ic); const char *aulookup_result(avc_t result) { return results[result]; } const char *aulookup_success(int s) { switch (s) { default: return success[0]; break; case S_FAILED: return success[1]; break; case S_SUCCESS: return success[2]; break; } } const char *aulookup_syscall(llist *l, char *buf, size_t size) { const char *sys; if (!interp_init) { au = auparse_init(AUSOURCE_BUFFER, ""); if (au == NULL) return NULL; interp_init = 1; } if (report_format <= RPT_DEFAULT) { snprintf(buf, size, "%d", l->s.syscall); return buf; } sys = _auparse_lookup_interpretation(au, "syscall"); if (sys) { snprintf(buf, size, "%s", sys); free((void *)sys); return buf; } machine = audit_elf_to_machine(l->s.arch); if (machine < 0) return Q; sys = audit_syscall_to_name(l->s.syscall, machine); if (sys) { const char *func = NULL; if (strcmp(sys, "socketcall") == 0) { if (list_find_item(l, AUDIT_SYSCALL)) func = aulookup_socketcall((long)l->cur->a0); } else if (strcmp(sys, "ipc") == 0) { if(list_find_item(l, AUDIT_SYSCALL)) func = aulookup_ipccall((long)l->cur->a0); } if (func) { snprintf(buf, size, "%s(%s)", sys, func); return buf; } snprintf(buf, size, "%s", sys); return buf; } snprintf(buf, size, "%d", l->s.syscall); return buf; } // See include/linux/net.h static const struct nv_pair socktab[] = { {SYS_SOCKET, "socket"}, {SYS_BIND, "bind"}, {SYS_CONNECT, "connect"}, {SYS_LISTEN, "listen"}, {SYS_ACCEPT, "accept"}, {SYS_GETSOCKNAME, "getsockname"}, {SYS_GETPEERNAME, "getpeername"}, {SYS_SOCKETPAIR, "socketpair"}, {SYS_SEND, "send"}, {SYS_RECV, "recv"}, {SYS_SENDTO, "sendto"}, {SYS_RECVFROM, "recvfrom"}, {SYS_SHUTDOWN, "shutdown"}, {SYS_SETSOCKOPT, "setsockopt"}, {SYS_GETSOCKOPT, "getsockopt"}, {SYS_SENDMSG, "sendmsg"}, {SYS_RECVMSG, "recvmsg"}, {SYS_ACCEPT4, "accept4"}, {19, "recvmmsg"}, {20, "sendmmsg"} }; #define SOCK_NAMES (sizeof(socktab)/sizeof(socktab[0])) static const char *aulookup_socketcall(long sc) { unsigned int i; for (i = 0; i < SOCK_NAMES; i++) if (socktab[i].value == sc) return socktab[i].name; return NULL; } /* This is from asm/ipc.h. Copying it for now as some platforms * have broken headers. */ #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 #define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 #define MSGCTL 14 #define SHMAT 21 #define SHMDT 22 #define SHMGET 23 #define SHMCTL 24 /* * This table maps ipc calls to their text name */ static const struct nv_pair ipctab[] = { {SEMOP, "semop"}, {SEMGET, "semget"}, {SEMCTL, "semctl"}, {SEMTIMEDOP, "semtimedop"}, {MSGSND, "msgsnd"}, {MSGRCV, "msgrcv"}, {MSGGET, "msgget"}, {MSGCTL, "msgctl"}, {SHMAT, "shmat"}, {SHMDT, "shmdt"}, {SHMGET, "shmget"}, {SHMCTL, "shmctl"} }; #define IPC_NAMES (sizeof(ipctab)/sizeof(ipctab[0])) static const char *aulookup_ipccall(long ic) { unsigned int i; for (i = 0; i < IPC_NAMES; i++) if (ipctab[i].value == ic) return ipctab[i].name; return NULL; } static nvlist uid_nvl; static int uid_list_created=0; const char *aulookup_uid(uid_t uid, char *buf, size_t size) { const char *name; int rc; if (!interp_init) { au = auparse_init(AUSOURCE_BUFFER, ""); if (au == NULL) return NULL; interp_init = 1; } if (report_format <= RPT_DEFAULT) { snprintf(buf, size, "%d", uid); return buf; } if (uid == -1) { snprintf(buf, size, "unset"); return buf; } name = _auparse_lookup_interpretation(au, "auid"); if (name) { snprintf(buf, size, "%s", name); free((void *)name); return buf; } // Check the cache first if (uid_list_created == 0) { search_list_create(&uid_nvl); search_list_clear(&uid_nvl); uid_list_created = 1; } rc = search_list_find_val(&uid_nvl, uid); if (rc) { name = uid_nvl.cur->name; } else { // This getpw use is OK because its for protocol 1 compatibility // Add it to cache struct passwd *pw; pw = getpwuid(uid); if (pw) { nvnode nv; nv.name = strdup(pw->pw_name); nv.val = uid; if (nv.name && search_list_append(&uid_nvl, &nv) == 0) name = uid_nvl.cur->name; else { /* search_list_append owns nv.name only on success. */ free(nv.name); name = pw->pw_name; } } } if (name != NULL) snprintf(buf, size, "%s", name); else snprintf(buf, size, "unknown(%d)", uid); return buf; } void aulookup_destroy_uid_list(void) { if (uid_list_created == 0) return; search_list_clear(&uid_nvl); uid_list_created = 0; } static int is_hex_string(const char *str) { while (*str) { if (!isxdigit(*str)) return 0; str++; } return 1; } /* * This function will take a pointer to a 2 byte Ascii character buffer and * return the actual hex value. */ static unsigned char x2c(unsigned char *buf) { static const char AsciiArray[17] = "0123456789ABCDEF"; const char *ptr; unsigned char total=0; ptr = strchr(AsciiArray, (char)toupper(buf[0])); if (ptr) total = (unsigned char)(((ptr-AsciiArray) & 0x0F)<<4); ptr = strchr(AsciiArray, (char)toupper(buf[1])); if (ptr) total += (unsigned char)((ptr-AsciiArray) & 0x0F); return total; } /* returns a freshly malloc'ed and converted buffer */ char *unescape(const char *buf) { int len, i; char *str, *strptr; const char *ptr = buf; /* Find the end of the name */ if (*ptr == '(') { ptr = strchr(ptr, ')'); if (ptr == NULL) return NULL; else ptr++; } else { while (isxdigit(*ptr)) ptr++; } if ((ptr - buf) == 0) return NULL; str = strndup(buf, ptr - buf); if (str == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); return NULL; } if (*buf == '(') return str; /* We can get away with this since the buffer is 2 times * bigger than what we are putting there. */ len = strlen(str); if (len < 2) { free(str); return NULL; } strptr = str; for (i=0; i<len; i+=2) { *strptr = x2c((unsigned char *)&str[i]); strptr++; } *strptr = 0; return str; } static int need_tty_escape(const unsigned char *s, unsigned int len) { unsigned int i = 0; while (i < len) { if (s[i] < 32) return 1; i++; } return 0; } static void tty_escape(const char *s, unsigned int len) { unsigned int i = 0; while (i < len) { if ((unsigned char)s[i] < 32) { putchar('\\'); putchar('0' + ((s[i] & 0300) >> 6)); putchar('0' + ((s[i] & 0070) >> 3)); putchar('0' + (s[i] & 0007)); } else putchar(s[i]); i++; } } static const char sh_set[] = "\"'`$\\!()| "; static unsigned int need_shell_escape(const char *s, unsigned int len) { unsigned int i = 0, cnt = 0; while (i < len) { if (s[i] < 32) cnt++; else if (strchr(sh_set, s[i])) cnt++; i++; } return cnt; } static void shell_escape(const char *s, unsigned int len) { unsigned int i = 0; while (i < len) { if ((unsigned char)s[i] < 32) { putchar('\\'); putchar('0' + ((s[i] & 0300) >> 6)); putchar('0' + ((s[i] & 0070) >> 3)); putchar('0' + (s[i] & 0007)); } else if (strchr(sh_set, s[i])) { putchar('\\'); putchar(s[i]); } else putchar(s[i]); i++; } } static const char quote_set[] = "\"'`$\\!()| ;#&*?[]<>{}"; static unsigned int need_shell_quote_escape(const unsigned char *s, unsigned int len) { unsigned int i = 0, cnt = 0; while (i < len) { if (s[i] < 32) cnt++; else if (strchr(quote_set, s[i])) cnt++; i++; } return cnt; } static void shell_quote_escape(const char *s, unsigned int len) { unsigned int i = 0; while (i < len) { if ((unsigned char)s[i] < 32) { putchar('\\'); putchar('0' + ((s[i] & 0300) >> 6)); putchar('0' + ((s[i] & 0070) >> 3)); putchar('0' + (s[i] & 0007)); } else if (strchr(quote_set, s[i])) { putchar('\\'); putchar(s[i]); } else putchar(s[i]); i++; } } static unsigned int need_escaping(const char *s, unsigned int len) { switch (escape_mode) { case AUPARSE_ESC_RAW: break; case AUPARSE_ESC_TTY: return need_tty_escape(s, len); case AUPARSE_ESC_SHELL: return need_shell_escape(s, len); case AUPARSE_ESC_SHELL_QUOTE: return need_shell_quote_escape(s, len); } return 0; } static void escape(const char *s, unsigned int len) { switch (escape_mode) { case AUPARSE_ESC_RAW: break; case AUPARSE_ESC_TTY: tty_escape(s, len); break; case AUPARSE_ESC_SHELL: shell_escape(s, len); break; case AUPARSE_ESC_SHELL_QUOTE: shell_quote_escape(s, len); break; } } void safe_print_string_n(const char *s, unsigned int len, int ret) { if (len > MAX_AUDIT_MESSAGE_LENGTH) len = MAX_AUDIT_MESSAGE_LENGTH; if (need_escaping(s, len)) { escape(s, len); if (ret) putchar('\n'); } else if (ret) puts(s); else printf("%s", s); } void safe_print_string(const char *s, int ret) { if (s == NULL) fputs("(null)", stdout); else safe_print_string_n(s, strlen(s), ret); } /* Represent c as a character within a quoted string, and append it to buf. */ static void tty_printable_char(unsigned char c) { if (c < 0x20 || c > 0x7E) { putchar('\\'); putchar('0' + ((c >> 6) & 07)); putchar('0' + ((c >> 3) & 07)); putchar('0' + (c & 07)); } else { if (c == '\\' || c == '"') putchar('\\'); putchar(c); } } /* Search for a name of a sequence of TTY bytes. * If found, return the name and advance *INPUT. * Return NULL otherwise. */ static const char *tty_find_named_key(unsigned char **input, size_t input_len) { /* NUL-terminated list of (sequence, NUL, name, NUL) entries. First match wins, even if a longer match were possible later */ static const unsigned char named_keys[] = #define E(SEQ, NAME) SEQ "\0" NAME "\0" #include "auparse/tty_named_keys.h" #undef E "\0"; unsigned char *src; const unsigned char *nk; src = *input; if (*src >= ' ' && (*src < 0x7F || *src >= 0xA0)) return NULL; /* Fast path */ nk = named_keys; do { const unsigned char *p; size_t nk_len; p = strchr((const char *)nk, '\0'); nk_len = p - nk; if (nk_len <= input_len && memcmp(src, nk, nk_len) == 0) { *input += nk_len; return (const char *)(p + 1); } nk = strchr((const char *)p + 1, '\0') + 1; } while (*nk != '\0'); return NULL; } void print_tty_data(const char *val) { int need_comma, in_printable = 0; unsigned char *data, *data_pos, *data_end; if (!is_hex_string(val)) { printf("%s", val); return; } if ((data = unescape((char *)val)) == NULL) { printf("conversion error(%s)", val); return; } data_end = data + strlen(val) / 2; data_pos = data; need_comma = 0; while (data_pos < data_end) { /* FIXME: Unicode */ const char *desc; desc = tty_find_named_key(&data_pos, data_end - data_pos); if (desc != NULL) { if (in_printable != 0) { putchar('"'); in_printable = 0; } if (need_comma != 0) putchar(','); printf("<%s>", desc); } else { if (in_printable == 0) { if (need_comma != 0) putchar(','); putchar('"'); in_printable = 1; } tty_printable_char(*data_pos); data_pos++; } need_comma = 1; } if (in_printable != 0) putchar('"'); free(data); }