Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lineage-19] Fix CVE-2021-3968 #67

Merged
merged 9 commits into from
Dec 29, 2022
17 changes: 10 additions & 7 deletions drivers/android/binder.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ struct binder_proc {
struct task_struct *tsk;
struct files_struct *files;
struct mutex files_lock;
const struct cred *cred;
struct hlist_node deferred_work_node;
int deferred_work;
bool is_dead;
Expand Down Expand Up @@ -2503,7 +2504,7 @@ static int binder_translate_binder(struct flat_binder_object *fp,
ret = -EINVAL;
goto done;
}
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
if (security_binder_transfer_binder(proc->cred, target_proc->cred)) {
ret = -EPERM;
goto done;
}
Expand Down Expand Up @@ -2549,7 +2550,7 @@ static int binder_translate_handle(struct flat_binder_object *fp,
proc->pid, thread->pid, fp->handle);
return -EINVAL;
}
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
if (security_binder_transfer_binder(proc->cred, target_proc->cred)) {
ret = -EPERM;
goto done;
}
Expand Down Expand Up @@ -2633,7 +2634,7 @@ static int binder_translate_fd(int fd,
ret = -EBADF;
goto err_fget;
}
ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
ret = security_binder_transfer_file(proc->cred, target_proc->cred, file);
if (ret < 0) {
ret = -EPERM;
goto err_security;
Expand Down Expand Up @@ -3024,8 +3025,8 @@ static void binder_transaction(struct binder_proc *proc,
return_error_line = __LINE__;
goto err_invalid_target_handle;
}
if (security_binder_transaction(proc->tsk,
target_proc->tsk) < 0) {
if (security_binder_transaction(proc->cred,
target_proc->cred) < 0) {
return_error = BR_FAILED_REPLY;
return_error_param = -EPERM;
return_error_line = __LINE__;
Expand Down Expand Up @@ -3136,7 +3137,7 @@ static void binder_transaction(struct binder_proc *proc,
size_t added_size;
int max_retries = 100;

security_task_getsecid(proc->tsk, &secid);
security_cred_getsecid(proc->cred, &secid);
retry_alloc:
ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
if (ret == -ENOMEM && max_retries-- > 0) {
Expand Down Expand Up @@ -4574,6 +4575,7 @@ static void binder_free_proc(struct binder_proc *proc)
BUG_ON(!list_empty(&proc->delivered_death));
binder_alloc_deferred_release(&proc->alloc);
put_task_struct(proc->tsk);
put_cred(proc->cred);
binder_stats_deleted(BINDER_STAT_PROC);
kfree(proc);
}
Expand Down Expand Up @@ -4776,7 +4778,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp,
ret = -EBUSY;
goto out;
}
ret = security_binder_set_context_mgr(proc->tsk);
ret = security_binder_set_context_mgr(proc->cred);
if (ret < 0)
goto out;
if (uid_valid(context->binder_context_mgr_uid)) {
Expand Down Expand Up @@ -5097,6 +5099,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
atomic_set(&proc->tmp_ref, 0);
get_task_struct(current->group_leader);
proc->tsk = current->group_leader;
proc->cred = get_cred(filp->f_cred);
mutex_init(&proc->files_lock);
INIT_LIST_HEAD(&proc->todo);
if (binder_supported_policy(current->policy)) {
Expand Down
45 changes: 29 additions & 16 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,10 @@
* @new points to the new credentials.
* @old points to the original credentials.
* Transfer data from original creds to new creds
* @cred_getsecid:
* Retrieve the security identifier of the cred structure @c
* @c contains the credentials, secid will be placed into @secid.
* In case of failure, @secid will be set to zero.
* @kernel_act_as:
* Set the credentials for a kernel service to act as (subjective context).
* @new points to the credentials to be modified.
Expand Down Expand Up @@ -1121,22 +1125,22 @@
*
* @binder_set_context_mgr
* Check whether @mgr is allowed to be the binder context manager.
* @mgr contains the task_struct for the task being registered.
* @mgr contains the struct cred for the current binder process.
* Return 0 if permission is granted.
* @binder_transaction
* Check whether @from is allowed to invoke a binder transaction call
* to @to.
* @from contains the task_struct for the sending task.
* @to contains the task_struct for the receiving task.
* @binder_transfer_binder
* @from contains the struct cred for the sending process.
* @to contains the struct cred for the receiving process.
* @binder_transfer_binder:
* Check whether @from is allowed to transfer a binder reference to @to.
* @from contains the task_struct for the sending task.
* @to contains the task_struct for the receiving task.
* @binder_transfer_file
* @from contains the struct cred for the sending process.
* @to contains the struct cred for the receiving process.
* @binder_transfer_file:
* Check whether @from is allowed to transfer @file to @to.
* @from contains the task_struct for the sending task.
* @from contains the struct cred for the sending process.
* @file contains the struct file being transferred.
* @to contains the task_struct for the receiving task.
* @to contains the struct cred for the receiving process.
*
* @ptrace_access_check:
* Check permission before allowing the current process to trace the
Expand Down Expand Up @@ -1338,13 +1342,13 @@
*/

union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
int (*binder_transaction)(struct task_struct *from,
struct task_struct *to);
int (*binder_transfer_binder)(struct task_struct *from,
struct task_struct *to);
int (*binder_transfer_file)(struct task_struct *from,
struct task_struct *to,
int (*binder_set_context_mgr)(const struct cred *mgr);
int (*binder_transaction)(const struct cred *from,
const struct cred *to);
int (*binder_transfer_binder)(const struct cred *from,
const struct cred *to);
int (*binder_transfer_file)(const struct cred *from,
const struct cred *to,
struct file *file);

int (*ptrace_access_check)(struct task_struct *child,
Expand Down Expand Up @@ -1488,6 +1492,7 @@ union security_list_options {
int (*cred_prepare)(struct cred *new, const struct cred *old,
gfp_t gfp);
void (*cred_transfer)(struct cred *new, const struct cred *old);
void (*cred_getsecid)(const struct cred *c, u32 *secid);
int (*kernel_act_as)(struct cred *new, u32 secid);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*kernel_fw_from_file)(struct file *file, char *buf, size_t size);
Expand Down Expand Up @@ -1762,6 +1767,7 @@ struct security_hook_heads {
struct list_head cred_free;
struct list_head cred_prepare;
struct list_head cred_transfer;
struct list_head cred_getsecid;
struct list_head kernel_act_as;
struct list_head kernel_create_files_as;
struct list_head kernel_fw_from_file;
Expand Down Expand Up @@ -1943,6 +1949,13 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
}
#endif /* CONFIG_SECURITY_SELINUX_DISABLE */

/* Currently required to handle SELinux runtime hook disable. */
#ifdef CONFIG_SECURITY_WRITABLE_HOOKS
#define __lsm_ro_after_init
#else
#define __lsm_ro_after_init __ro_after_init
#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */

extern int __init security_module_enable(const char *module);
extern void __init capability_add_hooks(void);
#ifdef CONFIG_SECURITY_YAMA
Expand Down
34 changes: 20 additions & 14 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
extern int security_init(void);

/* Security operations */
int security_binder_set_context_mgr(struct task_struct *mgr);
int security_binder_transaction(struct task_struct *from,
struct task_struct *to);
int security_binder_transfer_binder(struct task_struct *from,
struct task_struct *to);
int security_binder_transfer_file(struct task_struct *from,
struct task_struct *to, struct file *file);
int security_binder_set_context_mgr(const struct cred *mgr);
int security_binder_transaction(const struct cred *from,
const struct cred *to);
int security_binder_transfer_binder(const struct cred *from,
const struct cred *to);
int security_binder_transfer_file(const struct cred *from,
const struct cred *to, struct file *file);
int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
int security_ptrace_traceme(struct task_struct *parent);
int security_capget(struct task_struct *target,
Expand Down Expand Up @@ -299,6 +299,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
void security_cred_free(struct cred *cred);
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
void security_transfer_creds(struct cred *new, const struct cred *old);
void security_cred_getsecid(const struct cred *c, u32 *secid);
int security_kernel_act_as(struct cred *new, u32 secid);
int security_kernel_create_files_as(struct cred *new, struct inode *inode);
int security_kernel_fw_from_file(struct file *file, char *buf, size_t size);
Expand Down Expand Up @@ -382,25 +383,25 @@ static inline int security_init(void)
return 0;
}

static inline int security_binder_set_context_mgr(struct task_struct *mgr)
static inline int security_binder_set_context_mgr(const struct cred *mgr)
{
return 0;
}

static inline int security_binder_transaction(struct task_struct *from,
struct task_struct *to)
static inline int security_binder_transaction(const struct cred *from,
const struct cred *to)
{
return 0;
}

static inline int security_binder_transfer_binder(struct task_struct *from,
struct task_struct *to)
static inline int security_binder_transfer_binder(const struct cred *from,
const struct cred *to)
{
return 0;
}

static inline int security_binder_transfer_file(struct task_struct *from,
struct task_struct *to,
static inline int security_binder_transfer_file(const struct cred *from,
const struct cred *to,
struct file *file)
{
return 0;
Expand Down Expand Up @@ -849,6 +850,11 @@ static inline void security_transfer_creds(struct cred *new,
{
}

static inline void security_cred_getsecid(const struct cred *c, u32 *secid)
{
*secid = 0;
}

static inline int security_kernel_act_as(struct cred *cred, u32 secid)
{
return 0;
Expand Down
4 changes: 4 additions & 0 deletions net/ipv4/ip_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,10 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
static struct sk_buff *gre_handle_offloads(struct sk_buff *skb,
bool csum)
{
unsigned char *skb_checksum_start = skb->head + skb->csum_start;

if (csum && skb_checksum_start < skb->data)
return ERR_PTR(-EINVAL);
return iptunnel_handle_offloads(skb, csum,
csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
}
Expand Down
5 changes: 5 additions & 0 deletions security/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ config SECURITY

If you are unsure how to answer this question, answer N.

config SECURITY_WRITABLE_HOOKS
depends on SECURITY
bool
default n

config PAGE_TABLE_ISOLATION
bool "Remove the kernel mapping in user mode"
default y
Expand Down
2 changes: 1 addition & 1 deletion security/apparmor/lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}

static struct security_hook_list apparmor_hooks[] = {
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
LSM_HOOK_INIT(capget, apparmor_capget),
Expand Down
2 changes: 1 addition & 1 deletion security/commoncap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,7 @@ int cap_mmap_file(struct file *file, unsigned long reqprot,

#ifdef CONFIG_SECURITY

struct security_hook_list capability_hooks[] = {
struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(capable, cap_capable),
LSM_HOOK_INIT(settime, cap_settime),
LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check),
Expand Down
Loading