kernel: Add a UID blacklist feature to restrict the operational permissions of specific users
This commit is contained in:
@@ -10,6 +10,8 @@
|
|||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/crc32.h>
|
||||||
|
|
||||||
#include "klog.h"
|
#include "klog.h"
|
||||||
#include "kernel_compat.h"
|
#include "kernel_compat.h"
|
||||||
@@ -21,6 +23,36 @@
|
|||||||
#define SULOG_MAX_SIZE (128 * 1024 * 1024) // 128MB
|
#define SULOG_MAX_SIZE (128 * 1024 * 1024) // 128MB
|
||||||
#define SULOG_ENTRY_MAX_LEN 512
|
#define SULOG_ENTRY_MAX_LEN 512
|
||||||
#define SULOG_COMM_LEN 256
|
#define SULOG_COMM_LEN 256
|
||||||
|
#define DEDUP_ENTRIES 256
|
||||||
|
#define DEDUP_SECS 60
|
||||||
|
|
||||||
|
struct dedup_key {
|
||||||
|
u32 crc;
|
||||||
|
uid_t uid;
|
||||||
|
u8 type;
|
||||||
|
u8 _pad[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dedup_entry {
|
||||||
|
struct dedup_key key;
|
||||||
|
u64 ts_ns;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dedup_entry dedup_tbl[DEDUP_ENTRIES];
|
||||||
|
static DEFINE_SPINLOCK(dedup_lock);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DEDUP_SU_GRANT = 0,
|
||||||
|
DEDUP_SU_ATTEMPT,
|
||||||
|
DEDUP_PERM_CHECK,
|
||||||
|
DEDUP_MANAGER_OP,
|
||||||
|
DEDUP_SYSCALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline u32 dedup_calc_hash(const char *content, size_t len)
|
||||||
|
{
|
||||||
|
return crc32(0, content, len);
|
||||||
|
}
|
||||||
|
|
||||||
struct sulog_entry {
|
struct sulog_entry {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
@@ -94,6 +126,35 @@ static void get_full_comm(char *comm_buf, size_t buf_len)
|
|||||||
comm_buf[buf_len - 1] = '\0';
|
comm_buf[buf_len - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool dedup_should_print(uid_t uid, u8 type,
|
||||||
|
const char *content, size_t len)
|
||||||
|
{
|
||||||
|
struct dedup_key key = {
|
||||||
|
.crc = dedup_calc_hash(content, len),
|
||||||
|
.uid = uid,
|
||||||
|
.type = type,
|
||||||
|
};
|
||||||
|
u64 now = ktime_get_ns();
|
||||||
|
u64 delta_ns = DEDUP_SECS * NSEC_PER_SEC;
|
||||||
|
|
||||||
|
u32 idx = key.crc & (DEDUP_ENTRIES - 1);
|
||||||
|
spin_lock(&dedup_lock);
|
||||||
|
|
||||||
|
struct dedup_entry *e = &dedup_tbl[idx];
|
||||||
|
if (e->key.crc == key.crc &&
|
||||||
|
e->key.uid == key.uid &&
|
||||||
|
e->key.type == key.type &&
|
||||||
|
(now - e->ts_ns) < delta_ns) {
|
||||||
|
spin_unlock(&dedup_lock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->key = key;
|
||||||
|
e->ts_ns = now;
|
||||||
|
spin_unlock(&dedup_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void sulog_work_handler(struct work_struct *work)
|
static void sulog_work_handler(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct file *fp;
|
struct file *fp;
|
||||||
@@ -221,8 +282,10 @@ void ksu_sulog_report_su_grant(uid_t uid, const char *comm, const char *method)
|
|||||||
timestamp, uid, full_comm,
|
timestamp, uid, full_comm,
|
||||||
method ? method : "unknown", current->pid);
|
method ? method : "unknown", current->pid);
|
||||||
|
|
||||||
|
if (!dedup_should_print(uid, DEDUP_SU_GRANT, log_buf, strlen(log_buf)))
|
||||||
|
goto cleanup_grant;
|
||||||
|
|
||||||
sulog_add_entry(log_buf);
|
sulog_add_entry(log_buf);
|
||||||
pr_info("sulog: %s", log_buf);
|
|
||||||
|
|
||||||
cleanup_grant:
|
cleanup_grant:
|
||||||
if (timestamp) kfree(timestamp);
|
if (timestamp) kfree(timestamp);
|
||||||
@@ -261,8 +324,10 @@ void ksu_sulog_report_su_attempt(uid_t uid, const char *comm, const char *target
|
|||||||
target_path ? target_path : "unknown",
|
target_path ? target_path : "unknown",
|
||||||
success ? "SUCCESS" : "DENIED", current->pid);
|
success ? "SUCCESS" : "DENIED", current->pid);
|
||||||
|
|
||||||
|
if (!dedup_should_print(uid, DEDUP_SU_GRANT, log_buf, strlen(log_buf)))
|
||||||
|
goto cleanup_attempt;
|
||||||
|
|
||||||
sulog_add_entry(log_buf);
|
sulog_add_entry(log_buf);
|
||||||
pr_info("sulog: %s", log_buf);
|
|
||||||
|
|
||||||
cleanup_attempt:
|
cleanup_attempt:
|
||||||
if (timestamp) kfree(timestamp);
|
if (timestamp) kfree(timestamp);
|
||||||
@@ -300,6 +365,9 @@ void ksu_sulog_report_permission_check(uid_t uid, const char *comm, bool allowed
|
|||||||
timestamp, uid, full_comm,
|
timestamp, uid, full_comm,
|
||||||
allowed ? "ALLOWED" : "DENIED", current->pid);
|
allowed ? "ALLOWED" : "DENIED", current->pid);
|
||||||
|
|
||||||
|
if (!dedup_should_print(uid, DEDUP_SU_GRANT, log_buf, strlen(log_buf)))
|
||||||
|
goto cleanup_perm;
|
||||||
|
|
||||||
sulog_add_entry(log_buf);
|
sulog_add_entry(log_buf);
|
||||||
|
|
||||||
cleanup_perm:
|
cleanup_perm:
|
||||||
@@ -332,8 +400,10 @@ void ksu_sulog_report_manager_operation(const char *operation, uid_t manager_uid
|
|||||||
timestamp, operation ? operation : "unknown",
|
timestamp, operation ? operation : "unknown",
|
||||||
manager_uid, target_uid, current->pid);
|
manager_uid, target_uid, current->pid);
|
||||||
|
|
||||||
|
if (!dedup_should_print(manager_uid, DEDUP_SU_GRANT, log_buf, strlen(log_buf)))
|
||||||
|
goto cleanup_mgr;
|
||||||
|
|
||||||
sulog_add_entry(log_buf);
|
sulog_add_entry(log_buf);
|
||||||
pr_info("sulog: %s", log_buf);
|
|
||||||
|
|
||||||
cleanup_mgr:
|
cleanup_mgr:
|
||||||
if (timestamp) kfree(timestamp);
|
if (timestamp) kfree(timestamp);
|
||||||
@@ -368,8 +438,10 @@ void ksu_sulog_report_syscall(uid_t uid, const char *comm,
|
|||||||
args ? args : "none",
|
args ? args : "none",
|
||||||
current->pid);
|
current->pid);
|
||||||
|
|
||||||
|
if (!dedup_should_print(uid, DEDUP_SU_GRANT, log_buf, strlen(log_buf)))
|
||||||
|
goto cleanup_mgr;
|
||||||
|
|
||||||
sulog_add_entry(log_buf);
|
sulog_add_entry(log_buf);
|
||||||
pr_info("sulog: %s", log_buf);
|
|
||||||
|
|
||||||
cleanup_mgr:
|
cleanup_mgr:
|
||||||
if (timestamp) kfree(timestamp);
|
if (timestamp) kfree(timestamp);
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ void ksu_sulog_report_syscall(uid_t uid, const char *comm, const char *syscall,
|
|||||||
void ksu_sulog_set_enabled(bool enabled);
|
void ksu_sulog_set_enabled(bool enabled);
|
||||||
bool ksu_sulog_is_enabled(void);
|
bool ksu_sulog_is_enabled(void);
|
||||||
|
|
||||||
|
void uid_blacklist_add(uid_t uid);
|
||||||
|
bool uid_blacklist_contains(uid_t uid);
|
||||||
|
void uid_blacklist_clear(void);
|
||||||
|
|
||||||
int ksu_sulog_init(void);
|
int ksu_sulog_init(void);
|
||||||
void ksu_sulog_exit(void);
|
void ksu_sulog_exit(void);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user