From 99a26ce784f9a4a9db1785a071fc9f5036353d5a Mon Sep 17 00:00:00 2001 From: jinqian Date: Mon, 13 Apr 2015 14:12:47 -0700 Subject: [PATCH 01/11] power: validate wakeup source before activating it. A rogue wakeup source not registered in wakeup_sources list is not visible from wakeup_sources_stats_show. Check if the wakeup source is registered properly by looking at the timer struct. Signed-off-by: jinqian Change-Id: Id4b2fdb3cf7fecb2fe7576b2305cd337974665c9 --- drivers/base/power/wakeup.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 4b35cc08c3b6..6686e5ff6041 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -343,6 +343,20 @@ int device_set_wakeup_enable(struct device *dev, bool enable) } EXPORT_SYMBOL_GPL(device_set_wakeup_enable); +/** + * wakeup_source_not_registered - validate the given wakeup source. + * @ws: Wakeup source to be validated. + */ +static bool wakeup_source_not_registered(struct wakeup_source *ws) +{ + /* + * Use timer struct to check if the given source is initialized + * by wakeup_source_add. + */ + return ws->timer.function != pm_wakeup_timer_fn || + ws->timer.data != (unsigned long)ws; +} + /* * The functions below use the observation that each wakeup event starts a * period in which the system should not be suspended. The moment this period @@ -383,6 +397,10 @@ static void wakeup_source_activate(struct wakeup_source *ws) { unsigned int cec; + if (WARN(wakeup_source_not_registered(ws), + "unregistered wakeup source\n")) + return; + /* * active wakeup source should bring the system * out of PM_SUSPEND_FREEZE state From 9b14142be776019ef0c0f88ddf2e14b7721bae3d Mon Sep 17 00:00:00 2001 From: jinqian Date: Tue, 14 Apr 2015 13:47:35 -0700 Subject: [PATCH 02/11] power: increment wakeup_count when save_wakeup_count failed. user-space aborts suspend attempt if writing wakeup_count failed. Count the write failure towards wakeup_count. Signed-off-by: jinqian Change-Id: Ic0123ac7ef31564700b1f6b5f2234275ac104244 --- drivers/base/power/wakeup.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 6686e5ff6041..ebe6c7310c85 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -54,6 +54,8 @@ static LIST_HEAD(wakeup_sources); static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue); +static ktime_t last_read_time; + /** * wakeup_source_prepare - Prepare a new wakeup source for initialization. * @ws: Wakeup source to prepare. @@ -778,10 +780,15 @@ bool pm_wakeup_pending(void) bool pm_get_wakeup_count(unsigned int *count, bool block) { unsigned int cnt, inpr; + unsigned long flags; if (block) { DEFINE_WAIT(wait); + spin_lock_irqsave(&events_lock, flags); + last_read_time = ktime_get(); + spin_unlock_irqrestore(&events_lock, flags); + for (;;) { prepare_to_wait(&wakeup_count_wait_queue, &wait, TASK_INTERRUPTIBLE); @@ -813,6 +820,7 @@ bool pm_save_wakeup_count(unsigned int count) { unsigned int cnt, inpr; unsigned long flags; + struct wakeup_source *ws; events_check_enabled = false; spin_lock_irqsave(&events_lock, flags); @@ -820,6 +828,15 @@ bool pm_save_wakeup_count(unsigned int count) if (cnt == count && inpr == 0) { saved_count = count; events_check_enabled = true; + } else { + rcu_read_lock(); + list_for_each_entry_rcu(ws, &wakeup_sources, entry) { + if (ws->active || + ktime_compare(ws->last_time, last_read_time) > 0) { + ws->wakeup_count++; + } + } + rcu_read_unlock(); } spin_unlock_irqrestore(&events_lock, flags); return events_check_enabled; From ba6f1652e0c153aae45ff3c6259e1c91378b9cfe Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Mon, 11 May 2015 17:57:52 -0700 Subject: [PATCH 03/11] proc: uid_cputime: fix show_uid_stat permission Change-Id: Ice9084e39da599261df0be6dc305b817b50cfbbf Signed-off-by: Jin Qian --- drivers/misc/uid_cputime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/uid_cputime.c b/drivers/misc/uid_cputime.c index acd7046ce497..c3f5bda9241d 100644 --- a/drivers/misc/uid_cputime.c +++ b/drivers/misc/uid_cputime.c @@ -226,7 +226,7 @@ static int __init proc_uid_cputime_init(void) proc_create_data("remove_uid_range", S_IWUGO, parent, &uid_remove_fops, NULL); - proc_create_data("show_uid_stat", S_IWUGO, parent, &uid_stat_fops, + proc_create_data("show_uid_stat", S_IRUGO, parent, &uid_stat_fops, NULL); profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block); From 6e9c6582376ac3c430bf7c89647313b2e685a597 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 7 May 2015 10:18:55 -0700 Subject: [PATCH 04/11] suspend: Return error when pending wakeup source is found. If a wakeup source is found to be pending in the last stage of suspend after syscore suspend then the device doesn't suspend but the error is not propogated which causes an error in the accounting for the number of suspend aborts and successful suspends. Change-Id: Ib63b4ead755127eaf03e3b303aab3c782ad02ed1 Signed-off-by: Ruchi Kandoi --- kernel/power/suspend.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 7c53fea31cba..221037af99af 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -232,10 +232,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (!(suspend_test(TEST_CORE) || *wakeup)) { error = suspend_ops->enter(state); events_check_enabled = false; - } else { + } else if (*wakeup) { pm_get_active_wakeup_sources(suspend_abort, MAX_SUSPEND_ABORT_LEN); log_suspend_abort_reason(suspend_abort); + error = -EBUSY; } syscore_resume(); } From 00a6e4dfa128c20861fbcd8adf3f28a8bf3a673e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 14 May 2015 18:37:30 -0400 Subject: [PATCH 05/11] ext4: don't save the error information if the block device is read-only Google-Bug-Id: 20939131 Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 48c8af5fe91d..fece245c796f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -305,6 +305,8 @@ static void __save_error_info(struct super_block *sb, const char *func, struct ext4_super_block *es = EXT4_SB(sb)->s_es; EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + if (bdev_read_only(sb->s_bdev)) + return; es->s_state |= cpu_to_le16(EXT4_ERROR_FS); es->s_last_error_time = cpu_to_le32(get_seconds()); strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func)); From 21a63f6526836f811e0ddbcb716bd4572c211b21 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 19 May 2015 13:59:12 -0400 Subject: [PATCH 06/11] selinux: enable per-file labeling for debugfs files. upstream commit 6f29997f4a3117169eeabd41dbea4c1bd94a739c Add support for per-file labeling of debugfs files so that we can distinguish them in policy. This is particularly important in Android where certain debugfs files have to be writable by apps and therefore the debugfs directory tree can be read and searched by all. Since debugfs is entirely kernel-generated, the directory tree is immutable by userspace, and the inodes are pinned in memory, we can simply use the same approach as with proc and label the inodes from policy based on pathname from the root of the debugfs filesystem. Generalize the existing labeling support used for proc and reuse it for debugfs too. [sds: Back-ported to 3.10. superblock_security_struct flags field is only unsigned char in 3.10 so we have to redefine SE_SBGENFS. However, this definition is kernel-private, not exposed to userspace or stored anywhere persistent.] Change-Id: I6460fbed6bb6bd36eb8554ac8c4fdd574edf3b07 Signed-off-by: Stephen Smalley --- security/selinux/hooks.c | 43 ++++++++++++++--------------- security/selinux/include/security.h | 1 + 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c8b85ea44cfd..69e6e80b9782 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -698,7 +698,10 @@ static int selinux_set_mnt_opts(struct super_block *sb, } if (strcmp(sb->s_type->name, "proc") == 0) - sbsec->flags |= SE_SBPROC; + sbsec->flags |= SE_SBPROC | SE_SBGENFS; + + if (strcmp(sb->s_type->name, "debugfs") == 0) + sbsec->flags |= SE_SBGENFS; /* Determine the labeling behavior to use for this filesystem type. */ rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); @@ -1183,12 +1186,13 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_SOCKET; } -#ifdef CONFIG_PROC_FS -static int selinux_proc_get_sid(struct dentry *dentry, - u16 tclass, - u32 *sid) +static int selinux_genfs_get_sid(struct dentry *dentry, + u16 tclass, + u16 flags, + u32 *sid) { int rc; + struct super_block *sb = dentry->d_inode->i_sb; char *buffer, *path; buffer = (char *)__get_free_page(GFP_KERNEL); @@ -1199,26 +1203,20 @@ static int selinux_proc_get_sid(struct dentry *dentry, if (IS_ERR(path)) rc = PTR_ERR(path); else { - /* each process gets a /proc/PID/ entry. Strip off the - * PID part to get a valid selinux labeling. - * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ - while (path[1] >= '0' && path[1] <= '9') { - path[1] = '/'; - path++; + if (flags & SE_SBPROC) { + /* each process gets a /proc/PID/ entry. Strip off the + * PID part to get a valid selinux labeling. + * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ + while (path[1] >= '0' && path[1] <= '9') { + path[1] = '/'; + path++; + } } - rc = security_genfs_sid("proc", path, tclass, sid); + rc = security_genfs_sid(sb->s_type->name, path, tclass, sid); } free_page((unsigned long)buffer); return rc; } -#else -static int selinux_proc_get_sid(struct dentry *dentry, - u16 tclass, - u32 *sid) -{ - return -EINVAL; -} -#endif /* The inode's security attributes must be initialized before first use. */ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) @@ -1373,7 +1371,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent /* Default to the fs superblock SID. */ isec->sid = sbsec->sid; - if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { + if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) { /* We must have a dentry to determine the label on * procfs inodes */ if (opt_dentry) @@ -1396,7 +1394,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent if (!dentry) goto out_unlock; isec->sclass = inode_mode_to_security_class(inode->i_mode); - rc = selinux_proc_get_sid(dentry, isec->sclass, &sid); + rc = selinux_genfs_get_sid(dentry, isec->sclass, + sbsec->flags, &sid); dput(dentry); if (rc) goto out_unlock; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index e72d8de93725..b73ec2a71a7c 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -55,6 +55,7 @@ #define SE_SBINITIALIZED 0x10 #define SE_SBPROC 0x20 #define SE_SBLABELSUPP 0x40 +#define SE_SBGENFS 0x80 #define CONTEXT_STR "context=" #define FSCONTEXT_STR "fscontext=" From 6f4f0dc1bc18de691668acf4bfeb9420507e2aa5 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 20 May 2015 12:33:16 -0400 Subject: [PATCH 07/11] selinux: enable genfscon labeling for sysfs and pstore files Support per-file labeling of sysfs and pstore files based on genfscon policy entries. This is safe because the sysfs and pstore directory tree cannot be manipulated by userspace, except to unlink pstore entries. This provides an alternative method of assigning per-file labeling to sysfs or pstore files without needing to set the labels from userspace on each boot. The advantages of this approach are that the labels are assigned as soon as the dentry is first instantiated and userspace does not need to walk the sysfs or pstore tree and set the labels on each boot. The limitations of this approach are that the labels can only be assigned based on pathname prefix matching. You can initially assign labels using this mechanism and then change them at runtime via setxattr if allowed to do so by policy. Change-Id: If5999785fdc1d24d869b23ae35cd302311e94562 Signed-off-by: Stephen Smalley Suggested-by: Dominick Grift --- security/selinux/hooks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 69e6e80b9782..899b29e3d60a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -700,7 +700,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, if (strcmp(sb->s_type->name, "proc") == 0) sbsec->flags |= SE_SBPROC | SE_SBGENFS; - if (strcmp(sb->s_type->name, "debugfs") == 0) + if (!strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore")) sbsec->flags |= SE_SBGENFS; /* Determine the labeling behavior to use for this filesystem type. */ From 7449299aa1e791d60abc5556f2ecf7f1ba039be9 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Thu, 21 May 2015 09:25:02 -0700 Subject: [PATCH 08/11] net/unix: sk_socket can disappear when state is unlocked got a rare NULL pointer dereference in clear_bit Signed-off-by: Mark Salyzyn Bug: 21252747 Change-Id: I27e70f2543034097c8a590a212c2c6fa846fe695 --- net/caif/caif_socket.c | 8 ++++++++ net/unix/af_unix.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 05a41c7ec304..955e83af1f3a 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -334,6 +334,10 @@ static long caif_stream_data_wait(struct sock *sk, long timeo) release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); + + if (sock_flag(sk, SOCK_DEAD)) + break; + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } @@ -380,6 +384,10 @@ static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; lock_sock(sk); + if (sock_flag(sk, SOCK_DEAD)) { + err = -ECONNRESET; + goto unlock; + } skb = skb_dequeue(&sk->sk_receive_queue); caif_check_flow_release(sk); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c4ce243824bb..53e062a2eee0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1882,6 +1882,10 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, unix_state_unlock(sk); timeo = freezable_schedule_timeout(timeo); unix_state_lock(sk); + + if (sock_flag(sk, SOCK_DEAD)) + break; + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } @@ -1939,6 +1943,10 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb, *last; unix_state_lock(sk); + if (sock_flag(sg, SOCK_DEAD)) { + err = -ECONNRESET; + goto unlock; + } last = skb = skb_peek(&sk->sk_receive_queue); again: if (skb == NULL) { From 9de69da198f3ae80ab10eeb564a0783e45a2c8c3 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 27 May 2015 11:08:16 -0700 Subject: [PATCH 09/11] New Build Breakage in branch: kernel-m-dev-tegra-flounder-3.10 @ 1960706 Signed-off-by: Mark Salyzyn Change-Id: I5682198bce94e66ff3de52989c7e361ffc25ba51 --- net/unix/af_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 53e062a2eee0..c3a13a77ff17 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1943,7 +1943,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb, *last; unix_state_lock(sk); - if (sock_flag(sg, SOCK_DEAD)) { + if (sock_flag(sk, SOCK_DEAD)) { err = -ECONNRESET; goto unlock; } From e4a6d6ba5a9e9e1796bbe6efe4f20ce7072df667 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Mon, 18 May 2015 19:44:41 +0900 Subject: [PATCH 10/11] neigh: Better handling of transition to NUD_PROBE state [1] When entering NUD_PROBE state via neigh_update(), perhaps received from userspace, correctly (re)initialize the probes count to zero. This is useful for forcing revalidation of a neighbor (for example if the host is attempting to do DNA [IPv4 4436, IPv6 6059]). [2] Notify listeners when a neighbor goes into NUD_PROBE state. By sending notifications on entry to NUD_PROBE state listeners get more timely warnings of imminent connectivity issues. The current notifications on entry to NUD_STALE have somewhat limited usefulness: NUD_STALE is a perfectly normal state, as is NUD_DELAY, whereas notifications on entry to NUD_FAILURE come after a neighbor reachability problem has been confirmed (typically after three probes). Change-Id: I1d01d40ef3bc4753b0eaa79da2b27235425b1934 Signed-off-by: Erik Kline Acked-By: Lorenzo Colitti Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/core/neighbour.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 5c56b217b999..703cd2ac5f29 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -926,6 +926,7 @@ static void neigh_timer_handler(unsigned long arg) neigh->nud_state = NUD_PROBE; neigh->updated = jiffies; atomic_set(&neigh->probes, 0); + notify = 1; next = now + neigh->parms->retrans_time; } } else { @@ -1153,6 +1154,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, if (new != old) { neigh_del_timer(neigh); + if (new & NUD_PROBE) + atomic_set(&neigh->probes, 0); if (new & NUD_IN_TIMER) neigh_add_timer(neigh, (jiffies + ((new & NUD_REACHABLE) ? From 67680c141957991b9350269a8eaf30baf1c85427 Mon Sep 17 00:00:00 2001 From: Riley Andrews Date: Thu, 28 May 2015 12:10:05 -0700 Subject: [PATCH 11/11] android: drivers: workaround debugfs race in binder If a /d/binder/proc/[pid] entry is kept open after linux has torn down the associated process, binder_proc_show can deference an invalid binder_proc that has been stashed in the debugfs inode. Validate that the binder_proc ptr passed into binder_proc_show has not been freed by looking for it within the global process list whilst the global lock is held. If the ptr is not valid, print nothing. Bug 19587483 Change-Id: Ice878c171db51ef9a4879c2f9299a2deb873d255 Signed-off-by: Riley Andrews --- drivers/android/binder.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index c048624fc6b7..383aa21a0e2a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3598,13 +3598,24 @@ static int binder_transactions_show(struct seq_file *m, void *unused) static int binder_proc_show(struct seq_file *m, void *unused) { + struct binder_proc *itr; struct binder_proc *proc = m->private; int do_lock = !binder_debug_no_lock; + bool valid_proc = false; if (do_lock) binder_lock(__func__); - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, proc, 1); + + hlist_for_each_entry(itr, &binder_procs, proc_node) { + if (itr == proc) { + valid_proc = true; + break; + } + } + if (valid_proc) { + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, proc, 1); + } if (do_lock) binder_unlock(__func__); return 0;