1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "selinux_klog.h"
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include "securec.h"
20
21 #define MAX_LOG_SIZE 1024
22 #define MAX_LEVEL_SIZE 4
23
24 static int g_logLevel = SELINUX_KERROR;
25 static const char *LOG_LEVEL_STR[] = {"ERROR", "WARNING", "INFO", "AVC"};
26
27 #ifndef UNLIKELY
28 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
29 #endif
30
SetSelinuxKmsgLevel(int logLevel)31 void SetSelinuxKmsgLevel(int logLevel)
32 {
33 g_logLevel = logLevel;
34 }
35
36 static int g_fd = -1;
SelinuxOpenLogDevice(void)37 static void SelinuxOpenLogDevice(void)
38 {
39 int fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IRGRP);
40 if (fd >= 0) {
41 g_fd = fd;
42 }
43 return;
44 }
45
SelinuxKmsg(int logLevel,const char * fmt,...)46 int SelinuxKmsg(int logLevel, const char *fmt, ...)
47 {
48 if (logLevel != SELINUX_KAVC && logLevel > g_logLevel) {
49 return -1;
50 }
51
52 if ((logLevel < 0) || (logLevel >= MAX_LEVEL_SIZE)) {
53 return -1;
54 }
55 if (UNLIKELY(g_fd < 0)) {
56 SelinuxOpenLogDevice();
57 if (g_fd < 0) {
58 return -1;
59 }
60 }
61 va_list vargs;
62 va_start(vargs, fmt);
63 char tmpFmt[MAX_LOG_SIZE];
64 if (vsnprintf_s(tmpFmt, MAX_LOG_SIZE, MAX_LOG_SIZE - 1, fmt, vargs) == -1) {
65 close(g_fd);
66 g_fd = -1;
67 va_end(vargs);
68 return -1;
69 }
70
71 char logInfo[MAX_LOG_SIZE];
72 int res = 0;
73 if (logLevel != SELINUX_KAVC) {
74 res = snprintf_s(logInfo, MAX_LOG_SIZE, MAX_LOG_SIZE - 1, "[pid=%d][%s][%s] %s", getpid(), "SELINUX",
75 LOG_LEVEL_STR[logLevel], tmpFmt);
76 } else {
77 res = snprintf_s(logInfo, MAX_LOG_SIZE, MAX_LOG_SIZE - 1, "%s", tmpFmt);
78 }
79 if (res == -1) {
80 close(g_fd);
81 g_fd = -1;
82 va_end(vargs);
83 return -1;
84 }
85 va_end(vargs);
86
87 if (write(g_fd, logInfo, strlen(logInfo)) < 0) {
88 close(g_fd);
89 g_fd = -1;
90 }
91 return 0;
92 }
93