aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Marshall <tdm.code@gmail.com>2017-01-25 18:01:03 +0100
committerRygebin <kaankulahli@gmail.com>2017-06-20 14:27:34 +0000
commitf7b238365fe609ddf0135b141c04129f21f85ce8 (patch)
tree59c16c7e6b3c7e0caba47b57f357af13396ea197
parent0bae66f5e65578b8a828bea67d9b1925ca5fd5ff (diff)
shamrock: Only expose su when daemon is running
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: I79716c72f74d0b7af34ec3a8054896c6559a181d
-rw-r--r--fs/exec.c5
-rw-r--r--fs/namei.c8
-rw-r--r--fs/readdir.c15
-rw-r--r--include/linux/dcache.h7
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/sched.h8
-rw-r--r--include/linux/uidgid.h3
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/sched/core.c32
10 files changed, 85 insertions, 0 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 4e56961debb..b5aa63511f9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1564,6 +1564,11 @@ static int do_execve_common(const char *filename,
if (retval < 0)
goto out;
+ if (d_is_su(file->f_dentry) && capable(CAP_SYS_ADMIN)) {
+ 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 9b9f6756e3d..8ff0915a934 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1984,6 +1984,14 @@ static int path_lookupat(int dfd, const char *name,
}
}
+ if (!err) {
+ struct super_block *sb = nd->inode->i_sb;
+ if (sb->s_flags & MS_RDONLY) {
+ 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 d46eca8567a..d52d18d9887 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -39,6 +39,7 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
if (!IS_DEADDIR(inode)) {
if (file->f_op->iterate) {
ctx->pos = file->f_pos;
+ ctx->romnt = (inode->i_sb->s_flags & MS_RDONLY);
res = file->f_op->iterate(file, ctx);
file->f_pos = ctx->pos;
} else {
@@ -53,6 +54,14 @@ out:
}
EXPORT_SYMBOL(iterate_dir);
+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..
*
@@ -91,6 +100,8 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset
buf->result = -EOVERFLOW;
return -EOVERFLOW;
}
+ if (hide_name(name, namlen) && buf->ctx.romnt)
+ return 0;
buf->result++;
dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent,
@@ -168,6 +179,8 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
buf->error = -EOVERFLOW;
return -EOVERFLOW;
}
+ if (hide_name(name, namlen) && buf->ctx.romnt)
+ return 0;
dirent = buf->previous;
if (dirent) {
if (__put_user(offset, &dirent->d_off))
@@ -246,6 +259,8 @@ static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ if (hide_name(name, namlen) && buf->ctx.romnt)
+ 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 05d917f3eba..cd8584f93a3 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -412,6 +412,13 @@ static inline bool d_mountpoint(struct dentry *dentry)
return dentry->d_flags & DCACHE_MOUNTED;
}
+static inline bool d_is_su(const struct dentry *dentry)
+{
+ return dentry &&
+ 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/fs.h b/include/linux/fs.h
index 8fa3bc09f84..dd632e7b6b4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1514,6 +1514,7 @@ typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
struct dir_context {
const filldir_t actor;
loff_t pos;
+ bool romnt;
};
static inline bool dir_emit(struct dir_context *ctx,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index abd6f7662e3..c03848dfb21 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -56,6 +56,12 @@ struct sched_param {
#include <asm/processor.h>
+int su_instances(void);
+bool su_running(void);
+bool su_visible(void);
+void su_exec(void);
+void su_exit(void);
+
#define SCHED_ATTR_SIZE_VER0 48 /* sizeof first published struct */
/*
@@ -1850,6 +1856,8 @@ static inline void sched_set_io_is_busy(int val) {};
#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */
#define PF_WAKE_UP_IDLE 0x80000000 /* try to wake up on an idle CPU */
+#define PF_SU 0x00000002 /* task is su */
+
/*
* Only the _current_ task can read/write to tsk->flags, but other
* tasks can access tsk->flags in readonly mode for example
diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h
index 8e522cbcef2..cb4c867a523 100644
--- a/include/linux/uidgid.h
+++ b/include/linux/uidgid.h
@@ -64,6 +64,9 @@ static inline gid_t __kgid_val(kgid_t gid)
#define GLOBAL_ROOT_UID KUIDT_INIT(0)
#define GLOBAL_ROOT_GID KGIDT_INIT(0)
+#define GLOBAL_SYSTEM_UID KUIDT_INIT(1000)
+#define GLOBAL_SYSTEM_GID KGIDT_INIT(1000)
+
#define INVALID_UID KUIDT_INIT(-1)
#define INVALID_GID KGIDT_INIT(-1)
diff --git a/kernel/exit.c b/kernel/exit.c
index 540bad43812..e58c525cbc3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -777,6 +777,10 @@ void do_exit(long code)
sched_exit(tsk);
+ 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 830502025e2..9f3f8512850 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -326,6 +326,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
if (err)
goto free_ti;
+ tsk->flags &= ~PF_SU;
+
tsk->stack = ti;
#ifdef CONFIG_SECCOMP
/*
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index aeb41cf4636..39bc6dedc61 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -114,6 +114,38 @@ do { \
local_irq_restore(dflags); \
} while (0)
+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)
+{
+ kuid_t uid = current_uid();
+ if (su_running())
+ return true;
+ if (uid_eq(uid, GLOBAL_ROOT_UID) || uid_eq(uid, GLOBAL_SYSTEM_UID))
+ return true;
+ return false;
+}
+
+void su_exec(void)
+{
+ atomic_inc(&__su_instances);
+}
+
+void su_exit(void)
+{
+ atomic_dec(&__su_instances);
+}
+
const char *task_event_names[] = {"PUT_PREV_TASK", "PICK_NEXT_TASK",
"TASK_WAKE", "TASK_MIGRATE", "TASK_UPDATE",
"IRQ_UPDATE"};