diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fork.c | 9 | ||||
| -rw-r--r-- | kernel/kexec.c | 59 | ||||
| -rw-r--r-- | kernel/ksysfs.c | 21 | ||||
| -rw-r--r-- | kernel/pid.c | 12 | ||||
| -rw-r--r-- | kernel/relay.c | 2 | ||||
| -rw-r--r-- | kernel/signal.c | 38 | ||||
| -rw-r--r-- | kernel/time/timecompare.c | 2 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 4 |
8 files changed, 117 insertions, 30 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 9bd91447e052..202a0ba63d3c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1127,6 +1127,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1127 | #ifdef CONFIG_DEBUG_MUTEXES | 1127 | #ifdef CONFIG_DEBUG_MUTEXES |
| 1128 | p->blocked_on = NULL; /* not blocked yet */ | 1128 | p->blocked_on = NULL; /* not blocked yet */ |
| 1129 | #endif | 1129 | #endif |
| 1130 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR | ||
| 1131 | p->memcg_batch.do_batch = 0; | ||
| 1132 | p->memcg_batch.memcg = NULL; | ||
| 1133 | #endif | ||
| 1130 | 1134 | ||
| 1131 | p->bts = NULL; | 1135 | p->bts = NULL; |
| 1132 | 1136 | ||
| @@ -1206,9 +1210,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1206 | p->sas_ss_sp = p->sas_ss_size = 0; | 1210 | p->sas_ss_sp = p->sas_ss_size = 0; |
| 1207 | 1211 | ||
| 1208 | /* | 1212 | /* |
| 1209 | * Syscall tracing should be turned off in the child regardless | 1213 | * Syscall tracing and stepping should be turned off in the |
| 1210 | * of CLONE_PTRACE. | 1214 | * child regardless of CLONE_PTRACE. |
| 1211 | */ | 1215 | */ |
| 1216 | user_disable_single_step(p); | ||
| 1212 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); | 1217 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); |
| 1213 | #ifdef TIF_SYSCALL_EMU | 1218 | #ifdef TIF_SYSCALL_EMU |
| 1214 | clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); | 1219 | clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); |
diff --git a/kernel/kexec.c b/kernel/kexec.c index f336e2107f98..433e9fcc1fc5 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/cpu.h> | 31 | #include <linux/cpu.h> |
| 32 | #include <linux/console.h> | 32 | #include <linux/console.h> |
| 33 | #include <linux/vmalloc.h> | 33 | #include <linux/vmalloc.h> |
| 34 | #include <linux/swap.h> | ||
| 34 | 35 | ||
| 35 | #include <asm/page.h> | 36 | #include <asm/page.h> |
| 36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
| @@ -1082,6 +1083,64 @@ void crash_kexec(struct pt_regs *regs) | |||
| 1082 | } | 1083 | } |
| 1083 | } | 1084 | } |
| 1084 | 1085 | ||
| 1086 | size_t crash_get_memory_size(void) | ||
| 1087 | { | ||
| 1088 | size_t size; | ||
| 1089 | mutex_lock(&kexec_mutex); | ||
| 1090 | size = crashk_res.end - crashk_res.start + 1; | ||
| 1091 | mutex_unlock(&kexec_mutex); | ||
| 1092 | return size; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | static void free_reserved_phys_range(unsigned long begin, unsigned long end) | ||
| 1096 | { | ||
| 1097 | unsigned long addr; | ||
| 1098 | |||
| 1099 | for (addr = begin; addr < end; addr += PAGE_SIZE) { | ||
| 1100 | ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT)); | ||
| 1101 | init_page_count(pfn_to_page(addr >> PAGE_SHIFT)); | ||
| 1102 | free_page((unsigned long)__va(addr)); | ||
| 1103 | totalram_pages++; | ||
| 1104 | } | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | int crash_shrink_memory(unsigned long new_size) | ||
| 1108 | { | ||
| 1109 | int ret = 0; | ||
| 1110 | unsigned long start, end; | ||
| 1111 | |||
| 1112 | mutex_lock(&kexec_mutex); | ||
| 1113 | |||
| 1114 | if (kexec_crash_image) { | ||
| 1115 | ret = -ENOENT; | ||
| 1116 | goto unlock; | ||
| 1117 | } | ||
| 1118 | start = crashk_res.start; | ||
| 1119 | end = crashk_res.end; | ||
| 1120 | |||
| 1121 | if (new_size >= end - start + 1) { | ||
| 1122 | ret = -EINVAL; | ||
| 1123 | if (new_size == end - start + 1) | ||
| 1124 | ret = 0; | ||
| 1125 | goto unlock; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | start = roundup(start, PAGE_SIZE); | ||
| 1129 | end = roundup(start + new_size, PAGE_SIZE); | ||
| 1130 | |||
| 1131 | free_reserved_phys_range(end, crashk_res.end); | ||
| 1132 | |||
| 1133 | if (start == end) { | ||
| 1134 | crashk_res.end = end; | ||
| 1135 | release_resource(&crashk_res); | ||
| 1136 | } else | ||
| 1137 | crashk_res.end = end - 1; | ||
| 1138 | |||
| 1139 | unlock: | ||
| 1140 | mutex_unlock(&kexec_mutex); | ||
| 1141 | return ret; | ||
| 1142 | } | ||
| 1143 | |||
| 1085 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | 1144 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, |
| 1086 | size_t data_len) | 1145 | size_t data_len) |
| 1087 | { | 1146 | { |
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 528dd78e7e7e..3feaf5a74514 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c | |||
| @@ -100,6 +100,26 @@ static ssize_t kexec_crash_loaded_show(struct kobject *kobj, | |||
| 100 | } | 100 | } |
| 101 | KERNEL_ATTR_RO(kexec_crash_loaded); | 101 | KERNEL_ATTR_RO(kexec_crash_loaded); |
| 102 | 102 | ||
| 103 | static ssize_t kexec_crash_size_show(struct kobject *kobj, | ||
| 104 | struct kobj_attribute *attr, char *buf) | ||
| 105 | { | ||
| 106 | return sprintf(buf, "%zu\n", crash_get_memory_size()); | ||
| 107 | } | ||
| 108 | static ssize_t kexec_crash_size_store(struct kobject *kobj, | ||
| 109 | struct kobj_attribute *attr, | ||
| 110 | const char *buf, size_t count) | ||
| 111 | { | ||
| 112 | unsigned long cnt; | ||
| 113 | int ret; | ||
| 114 | |||
| 115 | if (strict_strtoul(buf, 0, &cnt)) | ||
| 116 | return -EINVAL; | ||
| 117 | |||
| 118 | ret = crash_shrink_memory(cnt); | ||
| 119 | return ret < 0 ? ret : count; | ||
| 120 | } | ||
| 121 | KERNEL_ATTR_RW(kexec_crash_size); | ||
| 122 | |||
| 103 | static ssize_t vmcoreinfo_show(struct kobject *kobj, | 123 | static ssize_t vmcoreinfo_show(struct kobject *kobj, |
| 104 | struct kobj_attribute *attr, char *buf) | 124 | struct kobj_attribute *attr, char *buf) |
| 105 | { | 125 | { |
| @@ -147,6 +167,7 @@ static struct attribute * kernel_attrs[] = { | |||
| 147 | #ifdef CONFIG_KEXEC | 167 | #ifdef CONFIG_KEXEC |
| 148 | &kexec_loaded_attr.attr, | 168 | &kexec_loaded_attr.attr, |
| 149 | &kexec_crash_loaded_attr.attr, | 169 | &kexec_crash_loaded_attr.attr, |
| 170 | &kexec_crash_size_attr.attr, | ||
| 150 | &vmcoreinfo_attr.attr, | 171 | &vmcoreinfo_attr.attr, |
| 151 | #endif | 172 | #endif |
| 152 | NULL | 173 | NULL |
diff --git a/kernel/pid.c b/kernel/pid.c index d3f722d20f9c..2e17c9c92cbe 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
| @@ -141,11 +141,12 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) | |||
| 141 | * installing it: | 141 | * installing it: |
| 142 | */ | 142 | */ |
| 143 | spin_lock_irq(&pidmap_lock); | 143 | spin_lock_irq(&pidmap_lock); |
| 144 | if (map->page) | 144 | if (!map->page) { |
| 145 | kfree(page); | ||
| 146 | else | ||
| 147 | map->page = page; | 145 | map->page = page; |
| 146 | page = NULL; | ||
| 147 | } | ||
| 148 | spin_unlock_irq(&pidmap_lock); | 148 | spin_unlock_irq(&pidmap_lock); |
| 149 | kfree(page); | ||
| 149 | if (unlikely(!map->page)) | 150 | if (unlikely(!map->page)) |
| 150 | break; | 151 | break; |
| 151 | } | 152 | } |
| @@ -268,12 +269,11 @@ struct pid *alloc_pid(struct pid_namespace *ns) | |||
| 268 | for (type = 0; type < PIDTYPE_MAX; ++type) | 269 | for (type = 0; type < PIDTYPE_MAX; ++type) |
| 269 | INIT_HLIST_HEAD(&pid->tasks[type]); | 270 | INIT_HLIST_HEAD(&pid->tasks[type]); |
| 270 | 271 | ||
| 272 | upid = pid->numbers + ns->level; | ||
| 271 | spin_lock_irq(&pidmap_lock); | 273 | spin_lock_irq(&pidmap_lock); |
| 272 | for (i = ns->level; i >= 0; i--) { | 274 | for ( ; upid >= pid->numbers; --upid) |
| 273 | upid = &pid->numbers[i]; | ||
| 274 | hlist_add_head_rcu(&upid->pid_chain, | 275 | hlist_add_head_rcu(&upid->pid_chain, |
| 275 | &pid_hash[pid_hashfn(upid->nr, upid->ns)]); | 276 | &pid_hash[pid_hashfn(upid->nr, upid->ns)]); |
| 276 | } | ||
| 277 | spin_unlock_irq(&pidmap_lock); | 277 | spin_unlock_irq(&pidmap_lock); |
| 278 | 278 | ||
| 279 | out: | 279 | out: |
diff --git a/kernel/relay.c b/kernel/relay.c index 760c26209a3c..c705a41b4ba3 100644 --- a/kernel/relay.c +++ b/kernel/relay.c | |||
| @@ -1198,7 +1198,7 @@ static void relay_pipe_buf_release(struct pipe_inode_info *pipe, | |||
| 1198 | relay_consume_bytes(rbuf, buf->private); | 1198 | relay_consume_bytes(rbuf, buf->private); |
| 1199 | } | 1199 | } |
| 1200 | 1200 | ||
| 1201 | static struct pipe_buf_operations relay_pipe_buf_ops = { | 1201 | static const struct pipe_buf_operations relay_pipe_buf_ops = { |
| 1202 | .can_merge = 0, | 1202 | .can_merge = 0, |
| 1203 | .map = generic_pipe_buf_map, | 1203 | .map = generic_pipe_buf_map, |
| 1204 | .unmap = generic_pipe_buf_unmap, | 1204 | .unmap = generic_pipe_buf_unmap, |
diff --git a/kernel/signal.c b/kernel/signal.c index 6b982f2cf524..1814e68e4de3 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -423,7 +423,7 @@ still_pending: | |||
| 423 | */ | 423 | */ |
| 424 | info->si_signo = sig; | 424 | info->si_signo = sig; |
| 425 | info->si_errno = 0; | 425 | info->si_errno = 0; |
| 426 | info->si_code = 0; | 426 | info->si_code = SI_USER; |
| 427 | info->si_pid = 0; | 427 | info->si_pid = 0; |
| 428 | info->si_uid = 0; | 428 | info->si_uid = 0; |
| 429 | } | 429 | } |
| @@ -607,6 +607,17 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s) | |||
| 607 | return 1; | 607 | return 1; |
| 608 | } | 608 | } |
| 609 | 609 | ||
| 610 | static inline int is_si_special(const struct siginfo *info) | ||
| 611 | { | ||
| 612 | return info <= SEND_SIG_FORCED; | ||
| 613 | } | ||
| 614 | |||
| 615 | static inline bool si_fromuser(const struct siginfo *info) | ||
| 616 | { | ||
| 617 | return info == SEND_SIG_NOINFO || | ||
| 618 | (!is_si_special(info) && SI_FROMUSER(info)); | ||
| 619 | } | ||
| 620 | |||
| 610 | /* | 621 | /* |
| 611 | * Bad permissions for sending the signal | 622 | * Bad permissions for sending the signal |
| 612 | * - the caller must hold at least the RCU read lock | 623 | * - the caller must hold at least the RCU read lock |
| @@ -621,7 +632,7 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
| 621 | if (!valid_signal(sig)) | 632 | if (!valid_signal(sig)) |
| 622 | return -EINVAL; | 633 | return -EINVAL; |
| 623 | 634 | ||
| 624 | if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) | 635 | if (!si_fromuser(info)) |
| 625 | return 0; | 636 | return 0; |
| 626 | 637 | ||
| 627 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ | 638 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ |
| @@ -949,9 +960,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
| 949 | int from_ancestor_ns = 0; | 960 | int from_ancestor_ns = 0; |
| 950 | 961 | ||
| 951 | #ifdef CONFIG_PID_NS | 962 | #ifdef CONFIG_PID_NS |
| 952 | if (!is_si_special(info) && SI_FROMUSER(info) && | 963 | from_ancestor_ns = si_fromuser(info) && |
| 953 | task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0) | 964 | !task_pid_nr_ns(current, task_active_pid_ns(t)); |
| 954 | from_ancestor_ns = 1; | ||
| 955 | #endif | 965 | #endif |
| 956 | 966 | ||
| 957 | return __send_signal(sig, info, t, group, from_ancestor_ns); | 967 | return __send_signal(sig, info, t, group, from_ancestor_ns); |
| @@ -1052,12 +1062,6 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t) | |||
| 1052 | return ret; | 1062 | return ret; |
| 1053 | } | 1063 | } |
| 1054 | 1064 | ||
| 1055 | void | ||
| 1056 | force_sig_specific(int sig, struct task_struct *t) | ||
| 1057 | { | ||
| 1058 | force_sig_info(sig, SEND_SIG_FORCED, t); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | /* | 1065 | /* |
| 1062 | * Nuke all other threads in the group. | 1066 | * Nuke all other threads in the group. |
| 1063 | */ | 1067 | */ |
| @@ -1186,8 +1190,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
| 1186 | goto out_unlock; | 1190 | goto out_unlock; |
| 1187 | } | 1191 | } |
| 1188 | pcred = __task_cred(p); | 1192 | pcred = __task_cred(p); |
| 1189 | if ((info == SEND_SIG_NOINFO || | 1193 | if (si_fromuser(info) && |
| 1190 | (!is_si_special(info) && SI_FROMUSER(info))) && | ||
| 1191 | euid != pcred->suid && euid != pcred->uid && | 1194 | euid != pcred->suid && euid != pcred->uid && |
| 1192 | uid != pcred->suid && uid != pcred->uid) { | 1195 | uid != pcred->suid && uid != pcred->uid) { |
| 1193 | ret = -EPERM; | 1196 | ret = -EPERM; |
| @@ -1837,11 +1840,6 @@ relock: | |||
| 1837 | 1840 | ||
| 1838 | for (;;) { | 1841 | for (;;) { |
| 1839 | struct k_sigaction *ka; | 1842 | struct k_sigaction *ka; |
| 1840 | |||
| 1841 | if (unlikely(signal->group_stop_count > 0) && | ||
| 1842 | do_signal_stop(0)) | ||
| 1843 | goto relock; | ||
| 1844 | |||
| 1845 | /* | 1843 | /* |
| 1846 | * Tracing can induce an artifical signal and choose sigaction. | 1844 | * Tracing can induce an artifical signal and choose sigaction. |
| 1847 | * The return value in @signr determines the default action, | 1845 | * The return value in @signr determines the default action, |
| @@ -1853,6 +1851,10 @@ relock: | |||
| 1853 | if (unlikely(signr != 0)) | 1851 | if (unlikely(signr != 0)) |
| 1854 | ka = return_ka; | 1852 | ka = return_ka; |
| 1855 | else { | 1853 | else { |
| 1854 | if (unlikely(signal->group_stop_count > 0) && | ||
| 1855 | do_signal_stop(0)) | ||
| 1856 | goto relock; | ||
| 1857 | |||
| 1856 | signr = dequeue_signal(current, ¤t->blocked, | 1858 | signr = dequeue_signal(current, ¤t->blocked, |
| 1857 | info); | 1859 | info); |
| 1858 | 1860 | ||
diff --git a/kernel/time/timecompare.c b/kernel/time/timecompare.c index 96ff643a5a59..12f5c55090be 100644 --- a/kernel/time/timecompare.c +++ b/kernel/time/timecompare.c | |||
| @@ -89,7 +89,7 @@ int timecompare_offset(struct timecompare *sync, | |||
| 89 | * source time | 89 | * source time |
| 90 | */ | 90 | */ |
| 91 | sample.offset = | 91 | sample.offset = |
| 92 | ktime_to_ns(ktime_add(end, start)) / 2 - | 92 | (ktime_to_ns(end) + ktime_to_ns(start)) / 2 - |
| 93 | ts; | 93 | ts; |
| 94 | 94 | ||
| 95 | /* simple insertion sort based on duration */ | 95 | /* simple insertion sort based on duration */ |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index bb6b5e7fa2a2..31118ae16f03 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -3133,7 +3133,7 @@ static void tracing_spd_release_pipe(struct splice_pipe_desc *spd, | |||
| 3133 | __free_page(spd->pages[idx]); | 3133 | __free_page(spd->pages[idx]); |
| 3134 | } | 3134 | } |
| 3135 | 3135 | ||
| 3136 | static struct pipe_buf_operations tracing_pipe_buf_ops = { | 3136 | static const struct pipe_buf_operations tracing_pipe_buf_ops = { |
| 3137 | .can_merge = 0, | 3137 | .can_merge = 0, |
| 3138 | .map = generic_pipe_buf_map, | 3138 | .map = generic_pipe_buf_map, |
| 3139 | .unmap = generic_pipe_buf_unmap, | 3139 | .unmap = generic_pipe_buf_unmap, |
| @@ -3617,7 +3617,7 @@ static void buffer_pipe_buf_get(struct pipe_inode_info *pipe, | |||
| 3617 | } | 3617 | } |
| 3618 | 3618 | ||
| 3619 | /* Pipe buffer operations for a buffer. */ | 3619 | /* Pipe buffer operations for a buffer. */ |
| 3620 | static struct pipe_buf_operations buffer_pipe_buf_ops = { | 3620 | static const struct pipe_buf_operations buffer_pipe_buf_ops = { |
| 3621 | .can_merge = 0, | 3621 | .can_merge = 0, |
| 3622 | .map = generic_pipe_buf_map, | 3622 | .map = generic_pipe_buf_map, |
| 3623 | .unmap = generic_pipe_buf_unmap, | 3623 | .unmap = generic_pipe_buf_unmap, |
