mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
214 lines
4.8 KiB
Diff
214 lines
4.8 KiB
Diff
From 70cfbfda0071b16160b82835a757ebecd14dc48b Mon Sep 17 00:00:00 2001
|
|
From: Tom Marshall <tdm.code@gmail.com>
|
|
Date: Fri, 28 Apr 2017 22:46:37 +0000
|
|
Subject: [PATCH] kernel: Only expose su when daemon is running
|
|
|
|
Note: this is for the 3.4 kernel and lacks the read-only mount point
|
|
logic due to the non-extensible readdir implementation.
|
|
|
|
It has been claimed that the PG implementation of 'su' has security
|
|
vulnerabilities even when disabled. Unfortunately, the people that
|
|
find these vulnerabilities often like to keep them private so they
|
|
can profit from exploits while leaving users exposed to malicious
|
|
hackers.
|
|
|
|
In order to reduce the attack surface for vulnerabilites, it is
|
|
therefore necessary to make 'su' completely inaccessible when it
|
|
is not in use (except by the root and system users).
|
|
|
|
Change-Id: Ia7d50ba46c3d932c2b0ca5fc8e9ec69ec9045f85
|
|
---
|
|
|
|
diff --git a/fs/exec.c b/fs/exec.c
|
|
index a4d05ce..b8c9af0 100644
|
|
--- a/fs/exec.c
|
|
+++ b/fs/exec.c
|
|
@@ -1591,6 +1591,11 @@
|
|
if (retval < 0)
|
|
goto out;
|
|
|
|
+ if (capable(CAP_SYS_ADMIN) && d_is_su(file->f_dentry)) {
|
|
+ current->flags |= PF_SU;
|
|
+ su_exec();
|
|
+ }
|
|
+
|
|
/* execve succeeded */
|
|
current->fs->in_exec = 0;
|
|
current->in_execve = 0;
|
|
diff --git a/fs/namei.c b/fs/namei.c
|
|
index df12b57..0446469 100644
|
|
--- a/fs/namei.c
|
|
+++ b/fs/namei.c
|
|
@@ -1800,6 +1800,11 @@
|
|
}
|
|
}
|
|
|
|
+ if (!err) {
|
|
+ if (d_is_su(nd->path.dentry) && !su_visible())
|
|
+ err = -ENOENT;
|
|
+ }
|
|
+
|
|
if (base)
|
|
fput(base);
|
|
|
|
diff --git a/fs/readdir.c b/fs/readdir.c
|
|
index cc0a822..106f156 100644
|
|
--- a/fs/readdir.c
|
|
+++ b/fs/readdir.c
|
|
@@ -47,6 +47,14 @@
|
|
|
|
EXPORT_SYMBOL(vfs_readdir);
|
|
|
|
+static bool hide_name(const char *name, int namlen)
|
|
+{
|
|
+ if (namlen == 2 && !memcmp(name, "su", 2))
|
|
+ if (!su_visible())
|
|
+ return true;
|
|
+ return false;
|
|
+}
|
|
+
|
|
/*
|
|
* Traditional linux readdir() handling..
|
|
*
|
|
@@ -84,6 +92,8 @@
|
|
buf->result = -EOVERFLOW;
|
|
return -EOVERFLOW;
|
|
}
|
|
+ if (hide_name(name, namlen))
|
|
+ return 0;
|
|
buf->result++;
|
|
dirent = buf->dirent;
|
|
if (!access_ok(VERIFY_WRITE, dirent,
|
|
@@ -163,6 +173,8 @@
|
|
buf->error = -EOVERFLOW;
|
|
return -EOVERFLOW;
|
|
}
|
|
+ if (hide_name(name, namlen))
|
|
+ return 0;
|
|
dirent = buf->previous;
|
|
if (dirent) {
|
|
if (__put_user(offset, &dirent->d_off))
|
|
@@ -244,6 +256,8 @@
|
|
buf->error = -EINVAL; /* only used if we fail.. */
|
|
if (reclen > buf->count)
|
|
return -EINVAL;
|
|
+ if (hide_name(name, namlen))
|
|
+ return 0;
|
|
dirent = buf->previous;
|
|
if (dirent) {
|
|
if (__put_user(offset, &dirent->d_off))
|
|
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
|
|
index 92e9d19..13efe38 100644
|
|
--- a/include/linux/dcache.h
|
|
+++ b/include/linux/dcache.h
|
|
@@ -403,6 +403,11 @@
|
|
|
|
extern void d_clear_need_lookup(struct dentry *dentry);
|
|
|
|
+static inline bool d_is_su(const struct dentry *dentry)
|
|
+{
|
|
+ return dentry->d_name.len == 2 && !memcmp(dentry->d_name.name, "su", 2);
|
|
+}
|
|
+
|
|
extern int sysctl_vfs_cache_pressure;
|
|
|
|
#endif /* __LINUX_DCACHE_H */
|
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
|
index 28f14d2..17962ef 100644
|
|
--- a/include/linux/sched.h
|
|
+++ b/include/linux/sched.h
|
|
@@ -93,6 +93,12 @@
|
|
|
|
#include <asm/processor.h>
|
|
|
|
+int su_instances(void);
|
|
+bool su_running(void);
|
|
+bool su_visible(void);
|
|
+void su_exec(void);
|
|
+void su_exit(void);
|
|
+
|
|
struct exec_domain;
|
|
struct futex_pi_state;
|
|
struct robust_list_head;
|
|
@@ -2008,6 +2014,8 @@
|
|
TASK_PFA_SET(SPREAD_SLAB, spread_slab)
|
|
TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab)
|
|
|
|
+#define PF_SU 0x10000000 /* task is su */
|
|
+
|
|
/*
|
|
* Do not use outside of architecture code which knows its limitations.
|
|
*
|
|
diff --git a/kernel/exit.c b/kernel/exit.c
|
|
index f28427b..3eafd26 100644
|
|
--- a/kernel/exit.c
|
|
+++ b/kernel/exit.c
|
|
@@ -957,6 +957,11 @@
|
|
}
|
|
|
|
exit_signals(tsk); /* sets PF_EXITING */
|
|
+
|
|
+ if (tsk->flags & PF_SU) {
|
|
+ su_exit();
|
|
+ }
|
|
+
|
|
/*
|
|
* tsk->flags are checked in the futex code to protect against
|
|
* an exiting task cleaning up the robust pi futexes.
|
|
diff --git a/kernel/fork.c b/kernel/fork.c
|
|
index 75dc3dd..23695d2 100644
|
|
--- a/kernel/fork.c
|
|
+++ b/kernel/fork.c
|
|
@@ -295,6 +295,8 @@
|
|
if (err)
|
|
goto out;
|
|
|
|
+ tsk->flags &= ~PF_SU;
|
|
+
|
|
tsk->stack = ti;
|
|
#ifdef CONFIG_SECCOMP
|
|
/*
|
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
|
index 5c06094..04fa21e 100644
|
|
--- a/kernel/sched/core.c
|
|
+++ b/kernel/sched/core.c
|
|
@@ -89,6 +89,38 @@
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/sched.h>
|
|
|
|
+static atomic_t __su_instances;
|
|
+
|
|
+int su_instances(void)
|
|
+{
|
|
+ return atomic_read(&__su_instances);
|
|
+}
|
|
+
|
|
+bool su_running(void)
|
|
+{
|
|
+ return su_instances() > 0;
|
|
+}
|
|
+
|
|
+bool su_visible(void)
|
|
+{
|
|
+ uid_t uid = current_uid();
|
|
+ if (su_running())
|
|
+ return true;
|
|
+ if (uid == 0 || uid == 1000)
|
|
+ return true;
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void su_exec(void)
|
|
+{
|
|
+ atomic_inc(&__su_instances);
|
|
+}
|
|
+
|
|
+void su_exit(void)
|
|
+{
|
|
+ atomic_dec(&__su_instances);
|
|
+}
|
|
+
|
|
ATOMIC_NOTIFIER_HEAD(migration_notifier_head);
|
|
|
|
void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period)
|