kernel: fix filp_open on older kernel's kworker (#205)

On older kernel, kworker missing keyring from init process , and this
keyring is related to FBE , which causes filp_open return ENOKEY or
other errors.To fix this,just install init's keyring to per
kworkers.This works on Kernel 4.4 and 4.9.
This commit is contained in:
f19 2023-02-05 07:14:59 +08:00 committed by GitHub
parent cd33a6dd07
commit 0c322a33bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 10 deletions

View File

@ -22,12 +22,7 @@ struct perm_data {
static struct list_head allow_list;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
#else
// filp_open return error if under encryption dir on Kernel4.4
#define KERNEL_SU_ALLOWLIST "/data/user_de/.ksu_allowlist"
#endif
static struct work_struct ksu_save_work;
static struct work_struct ksu_load_work;
@ -124,7 +119,7 @@ void do_persistent_allow_list(struct work_struct *work)
struct perm_data *p = NULL;
struct list_head *pos = NULL;
loff_t off = 0;
KWORKER_INSTALL_KEYRING();
struct file *fp =
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
@ -164,7 +159,7 @@ void do_load_allow_list(struct work_struct *work)
struct file *fp = NULL;
u32 magic;
u32 version;
KWORKER_INSTALL_KEYRING();
fp = filp_open("/data/adb", O_RDONLY, 0);
if (IS_ERR(fp)) {
int errno = PTR_ERR(fp);

View File

@ -22,6 +22,7 @@
#include "manager.h"
#include "selinux/selinux.h"
#include "uid_observer.h"
#include "kernel_compat.h"
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
@ -356,7 +357,26 @@ static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
return -ENOSYS;
}
// kernel 4.4 and 4.9
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
static int ksu_key_permission(key_ref_t key_ref,
const struct cred *cred,
unsigned perm)
{
if (init_session_keyring != NULL)
{
return 0;
}
if (strcmp(current->comm, "init"))
{
// we are only interested in `init` process
return 0;
}
init_session_keyring = cred->session_keyring;
pr_info("kernel_compat: got init_session_keyring");
return 0;
}
#endif
static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
struct inode *new_inode, struct dentry *new_dentry)
{
@ -366,6 +386,9 @@ static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
static struct security_hook_list ksu_hooks[] = {
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
LSM_HOOK_INIT(key_permission, ksu_key_permission)
#endif
};
void __init ksu_lsm_hook_init(void)

View File

@ -1,6 +1,10 @@
#include "linux/version.h"
#include "linux/init.h"
#include "linux/fs.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#include "linux/key.h"
#include "linux/errno.h"
struct key *init_session_keyring = NULL;
#endif
ssize_t kernel_read_compat(struct file *p, void *buf, size_t count, loff_t *pos){
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_read(p, buf, count, pos);

View File

@ -2,7 +2,41 @@
#define __KSU_H_KERNEL_COMPAT
#include "linux/fs.h"
#include "linux/key.h"
#include "linux/version.h"
extern ssize_t kernel_read_compat(struct file *p, void* buf, size_t count, loff_t *pos);
extern struct key *init_session_keyring;
extern ssize_t kernel_read_compat(struct file *p, void *buf, size_t count, loff_t *pos);
extern ssize_t kernel_write_compat(struct file *p, const void *buf, size_t count, loff_t *pos);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
static inline int install_session_keyring(struct key *keyring)
{
struct cred *new;
int ret;
new = prepare_creds();
if (!new)
return -ENOMEM;
ret = install_session_keyring_to_cred(new, keyring);
if (ret < 0) {
abort_creds(new);
return ret;
}
return commit_creds(new);
}
#define KWORKER_INSTALL_KEYRING() \
static bool keyring_installed = false; \
if (init_session_keyring != NULL && !keyring_installed) \
{ \
install_session_keyring(init_session_keyring); \
keyring_installed = true; \
}
#else
#define KWORKER_INSTALL_KEYRING()
#endif
#endif

View File

@ -39,6 +39,7 @@ static bool is_uid_exist(uid_t uid, void *data)
static void do_update_uid(struct work_struct *work)
{
KWORKER_INSTALL_KEYRING();
struct file *fp = filp_open(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("do_update_uid, open " SYSTEM_PACKAGES_LIST_PATH