diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-05 13:06:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-05 13:06:23 -0500 |
commit | 6a5e05a47b6cb8e59bfad351444322b1e4012326 (patch) | |
tree | 3387834d1084fbd53d86dcc4c23097db0d51f45b | |
parent | 1fbd55c0ccd842a976d16431b57121b7892ed8ce (diff) | |
parent | 66bc5df31110652a31c91f14b4e23f7c51e5328e (diff) |
Merge tag 'char-misc-4.15-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc fixes from Greg KH:
"Here are some small misc driver fixes for 4.15-rc3 to resolve reported
issues. Specifically these are:
- binder fix for a memory leak
- vpd driver fixes for a number of reported problems
- hyperv driver fix for memory accesses where it shouldn't be.
All of these have been in linux-next for a while. There's also one
more MAINTAINERS file update that came in today to get the Android
developer's emails correct, which is also in this pull request, that
was not in linux-next, but should not be an issue"
* tag 'char-misc-4.15-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
MAINTAINERS: update Android driver maintainers.
firmware: vpd: Fix platform driver and device registration/unregistration
firmware: vpd: Tie firmware kobject to device lifetime
firmware: vpd: Destroy vpd sections in remove function
hv: kvp: Avoid reading past allocated blocks from KVP file
Drivers: hv: vmbus: Fix a rescind issue
ANDROID: binder: fix transaction leak.
-rw-r--r-- | MAINTAINERS | 3 | ||||
-rw-r--r-- | drivers/android/binder.c | 40 | ||||
-rw-r--r-- | drivers/firmware/google/vpd.c | 48 | ||||
-rw-r--r-- | drivers/hv/channel.c | 10 | ||||
-rw-r--r-- | drivers/hv/channel_mgmt.c | 7 | ||||
-rw-r--r-- | include/linux/hyperv.h | 1 | ||||
-rw-r--r-- | tools/hv/hv_kvp_daemon.c | 70 |
7 files changed, 95 insertions, 84 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 745337ed01f6..64c1ceaef4be 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -859,7 +859,8 @@ F: kernel/configs/android* | |||
859 | ANDROID DRIVERS | 859 | ANDROID DRIVERS |
860 | M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 860 | M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
861 | M: Arve Hjønnevåg <arve@android.com> | 861 | M: Arve Hjønnevåg <arve@android.com> |
862 | M: Riley Andrews <riandrews@android.com> | 862 | M: Todd Kjos <tkjos@android.com> |
863 | M: Martijn Coenen <maco@android.com> | ||
863 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git | 864 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git |
864 | L: devel@driverdev.osuosl.org | 865 | L: devel@driverdev.osuosl.org |
865 | S: Supported | 866 | S: Supported |
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index a73596a4f804..bccec9de0533 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c | |||
@@ -1948,6 +1948,26 @@ static void binder_send_failed_reply(struct binder_transaction *t, | |||
1948 | } | 1948 | } |
1949 | 1949 | ||
1950 | /** | 1950 | /** |
1951 | * binder_cleanup_transaction() - cleans up undelivered transaction | ||
1952 | * @t: transaction that needs to be cleaned up | ||
1953 | * @reason: reason the transaction wasn't delivered | ||
1954 | * @error_code: error to return to caller (if synchronous call) | ||
1955 | */ | ||
1956 | static void binder_cleanup_transaction(struct binder_transaction *t, | ||
1957 | const char *reason, | ||
1958 | uint32_t error_code) | ||
1959 | { | ||
1960 | if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) { | ||
1961 | binder_send_failed_reply(t, error_code); | ||
1962 | } else { | ||
1963 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | ||
1964 | "undelivered transaction %d, %s\n", | ||
1965 | t->debug_id, reason); | ||
1966 | binder_free_transaction(t); | ||
1967 | } | ||
1968 | } | ||
1969 | |||
1970 | /** | ||
1951 | * binder_validate_object() - checks for a valid metadata object in a buffer. | 1971 | * binder_validate_object() - checks for a valid metadata object in a buffer. |
1952 | * @buffer: binder_buffer that we're parsing. | 1972 | * @buffer: binder_buffer that we're parsing. |
1953 | * @offset: offset in the buffer at which to validate an object. | 1973 | * @offset: offset in the buffer at which to validate an object. |
@@ -4015,12 +4035,20 @@ retry: | |||
4015 | if (put_user(cmd, (uint32_t __user *)ptr)) { | 4035 | if (put_user(cmd, (uint32_t __user *)ptr)) { |
4016 | if (t_from) | 4036 | if (t_from) |
4017 | binder_thread_dec_tmpref(t_from); | 4037 | binder_thread_dec_tmpref(t_from); |
4038 | |||
4039 | binder_cleanup_transaction(t, "put_user failed", | ||
4040 | BR_FAILED_REPLY); | ||
4041 | |||
4018 | return -EFAULT; | 4042 | return -EFAULT; |
4019 | } | 4043 | } |
4020 | ptr += sizeof(uint32_t); | 4044 | ptr += sizeof(uint32_t); |
4021 | if (copy_to_user(ptr, &tr, sizeof(tr))) { | 4045 | if (copy_to_user(ptr, &tr, sizeof(tr))) { |
4022 | if (t_from) | 4046 | if (t_from) |
4023 | binder_thread_dec_tmpref(t_from); | 4047 | binder_thread_dec_tmpref(t_from); |
4048 | |||
4049 | binder_cleanup_transaction(t, "copy_to_user failed", | ||
4050 | BR_FAILED_REPLY); | ||
4051 | |||
4024 | return -EFAULT; | 4052 | return -EFAULT; |
4025 | } | 4053 | } |
4026 | ptr += sizeof(tr); | 4054 | ptr += sizeof(tr); |
@@ -4090,15 +4118,9 @@ static void binder_release_work(struct binder_proc *proc, | |||
4090 | struct binder_transaction *t; | 4118 | struct binder_transaction *t; |
4091 | 4119 | ||
4092 | t = container_of(w, struct binder_transaction, work); | 4120 | t = container_of(w, struct binder_transaction, work); |
4093 | if (t->buffer->target_node && | 4121 | |
4094 | !(t->flags & TF_ONE_WAY)) { | 4122 | binder_cleanup_transaction(t, "process died.", |
4095 | binder_send_failed_reply(t, BR_DEAD_REPLY); | 4123 | BR_DEAD_REPLY); |
4096 | } else { | ||
4097 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | ||
4098 | "undelivered transaction %d\n", | ||
4099 | t->debug_id); | ||
4100 | binder_free_transaction(t); | ||
4101 | } | ||
4102 | } break; | 4124 | } break; |
4103 | case BINDER_WORK_RETURN_ERROR: { | 4125 | case BINDER_WORK_RETURN_ERROR: { |
4104 | struct binder_error *e = container_of( | 4126 | struct binder_error *e = container_of( |
diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index 35e553b3b190..e4b40f2b4627 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c | |||
@@ -295,38 +295,60 @@ static int vpd_probe(struct platform_device *pdev) | |||
295 | if (ret) | 295 | if (ret) |
296 | return ret; | 296 | return ret; |
297 | 297 | ||
298 | return vpd_sections_init(entry.cbmem_addr); | 298 | vpd_kobj = kobject_create_and_add("vpd", firmware_kobj); |
299 | if (!vpd_kobj) | ||
300 | return -ENOMEM; | ||
301 | |||
302 | ret = vpd_sections_init(entry.cbmem_addr); | ||
303 | if (ret) { | ||
304 | kobject_put(vpd_kobj); | ||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static int vpd_remove(struct platform_device *pdev) | ||
312 | { | ||
313 | vpd_section_destroy(&ro_vpd); | ||
314 | vpd_section_destroy(&rw_vpd); | ||
315 | |||
316 | kobject_put(vpd_kobj); | ||
317 | |||
318 | return 0; | ||
299 | } | 319 | } |
300 | 320 | ||
301 | static struct platform_driver vpd_driver = { | 321 | static struct platform_driver vpd_driver = { |
302 | .probe = vpd_probe, | 322 | .probe = vpd_probe, |
323 | .remove = vpd_remove, | ||
303 | .driver = { | 324 | .driver = { |
304 | .name = "vpd", | 325 | .name = "vpd", |
305 | }, | 326 | }, |
306 | }; | 327 | }; |
307 | 328 | ||
329 | static struct platform_device *vpd_pdev; | ||
330 | |||
308 | static int __init vpd_platform_init(void) | 331 | static int __init vpd_platform_init(void) |
309 | { | 332 | { |
310 | struct platform_device *pdev; | 333 | int ret; |
311 | |||
312 | pdev = platform_device_register_simple("vpd", -1, NULL, 0); | ||
313 | if (IS_ERR(pdev)) | ||
314 | return PTR_ERR(pdev); | ||
315 | 334 | ||
316 | vpd_kobj = kobject_create_and_add("vpd", firmware_kobj); | 335 | ret = platform_driver_register(&vpd_driver); |
317 | if (!vpd_kobj) | 336 | if (ret) |
318 | return -ENOMEM; | 337 | return ret; |
319 | 338 | ||
320 | platform_driver_register(&vpd_driver); | 339 | vpd_pdev = platform_device_register_simple("vpd", -1, NULL, 0); |
340 | if (IS_ERR(vpd_pdev)) { | ||
341 | platform_driver_unregister(&vpd_driver); | ||
342 | return PTR_ERR(vpd_pdev); | ||
343 | } | ||
321 | 344 | ||
322 | return 0; | 345 | return 0; |
323 | } | 346 | } |
324 | 347 | ||
325 | static void __exit vpd_platform_exit(void) | 348 | static void __exit vpd_platform_exit(void) |
326 | { | 349 | { |
327 | vpd_section_destroy(&ro_vpd); | 350 | platform_device_unregister(vpd_pdev); |
328 | vpd_section_destroy(&rw_vpd); | 351 | platform_driver_unregister(&vpd_driver); |
329 | kobject_put(vpd_kobj); | ||
330 | } | 352 | } |
331 | 353 | ||
332 | module_init(vpd_platform_init); | 354 | module_init(vpd_platform_init); |
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 19f0cf37e0ed..ba0a092ae085 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
@@ -659,22 +659,28 @@ void vmbus_close(struct vmbus_channel *channel) | |||
659 | */ | 659 | */ |
660 | return; | 660 | return; |
661 | } | 661 | } |
662 | mutex_lock(&vmbus_connection.channel_mutex); | ||
663 | /* | 662 | /* |
664 | * Close all the sub-channels first and then close the | 663 | * Close all the sub-channels first and then close the |
665 | * primary channel. | 664 | * primary channel. |
666 | */ | 665 | */ |
667 | list_for_each_safe(cur, tmp, &channel->sc_list) { | 666 | list_for_each_safe(cur, tmp, &channel->sc_list) { |
668 | cur_channel = list_entry(cur, struct vmbus_channel, sc_list); | 667 | cur_channel = list_entry(cur, struct vmbus_channel, sc_list); |
669 | vmbus_close_internal(cur_channel); | ||
670 | if (cur_channel->rescind) { | 668 | if (cur_channel->rescind) { |
669 | wait_for_completion(&cur_channel->rescind_event); | ||
670 | mutex_lock(&vmbus_connection.channel_mutex); | ||
671 | vmbus_close_internal(cur_channel); | ||
671 | hv_process_channel_removal( | 672 | hv_process_channel_removal( |
672 | cur_channel->offermsg.child_relid); | 673 | cur_channel->offermsg.child_relid); |
674 | } else { | ||
675 | mutex_lock(&vmbus_connection.channel_mutex); | ||
676 | vmbus_close_internal(cur_channel); | ||
673 | } | 677 | } |
678 | mutex_unlock(&vmbus_connection.channel_mutex); | ||
674 | } | 679 | } |
675 | /* | 680 | /* |
676 | * Now close the primary. | 681 | * Now close the primary. |
677 | */ | 682 | */ |
683 | mutex_lock(&vmbus_connection.channel_mutex); | ||
678 | vmbus_close_internal(channel); | 684 | vmbus_close_internal(channel); |
679 | mutex_unlock(&vmbus_connection.channel_mutex); | 685 | mutex_unlock(&vmbus_connection.channel_mutex); |
680 | } | 686 | } |
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index ec5454f3f4a6..c21020b69114 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -333,6 +333,7 @@ static struct vmbus_channel *alloc_channel(void) | |||
333 | return NULL; | 333 | return NULL; |
334 | 334 | ||
335 | spin_lock_init(&channel->lock); | 335 | spin_lock_init(&channel->lock); |
336 | init_completion(&channel->rescind_event); | ||
336 | 337 | ||
337 | INIT_LIST_HEAD(&channel->sc_list); | 338 | INIT_LIST_HEAD(&channel->sc_list); |
338 | INIT_LIST_HEAD(&channel->percpu_list); | 339 | INIT_LIST_HEAD(&channel->percpu_list); |
@@ -898,6 +899,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) | |||
898 | /* | 899 | /* |
899 | * Now wait for offer handling to complete. | 900 | * Now wait for offer handling to complete. |
900 | */ | 901 | */ |
902 | vmbus_rescind_cleanup(channel); | ||
901 | while (READ_ONCE(channel->probe_done) == false) { | 903 | while (READ_ONCE(channel->probe_done) == false) { |
902 | /* | 904 | /* |
903 | * We wait here until any channel offer is currently | 905 | * We wait here until any channel offer is currently |
@@ -913,7 +915,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) | |||
913 | if (channel->device_obj) { | 915 | if (channel->device_obj) { |
914 | if (channel->chn_rescind_callback) { | 916 | if (channel->chn_rescind_callback) { |
915 | channel->chn_rescind_callback(channel); | 917 | channel->chn_rescind_callback(channel); |
916 | vmbus_rescind_cleanup(channel); | ||
917 | return; | 918 | return; |
918 | } | 919 | } |
919 | /* | 920 | /* |
@@ -922,7 +923,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) | |||
922 | */ | 923 | */ |
923 | dev = get_device(&channel->device_obj->device); | 924 | dev = get_device(&channel->device_obj->device); |
924 | if (dev) { | 925 | if (dev) { |
925 | vmbus_rescind_cleanup(channel); | ||
926 | vmbus_device_unregister(channel->device_obj); | 926 | vmbus_device_unregister(channel->device_obj); |
927 | put_device(dev); | 927 | put_device(dev); |
928 | } | 928 | } |
@@ -936,13 +936,14 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) | |||
936 | * 2. Then close the primary channel. | 936 | * 2. Then close the primary channel. |
937 | */ | 937 | */ |
938 | mutex_lock(&vmbus_connection.channel_mutex); | 938 | mutex_lock(&vmbus_connection.channel_mutex); |
939 | vmbus_rescind_cleanup(channel); | ||
940 | if (channel->state == CHANNEL_OPEN_STATE) { | 939 | if (channel->state == CHANNEL_OPEN_STATE) { |
941 | /* | 940 | /* |
942 | * The channel is currently not open; | 941 | * The channel is currently not open; |
943 | * it is safe for us to cleanup the channel. | 942 | * it is safe for us to cleanup the channel. |
944 | */ | 943 | */ |
945 | hv_process_channel_removal(rescind->child_relid); | 944 | hv_process_channel_removal(rescind->child_relid); |
945 | } else { | ||
946 | complete(&channel->rescind_event); | ||
946 | } | 947 | } |
947 | mutex_unlock(&vmbus_connection.channel_mutex); | 948 | mutex_unlock(&vmbus_connection.channel_mutex); |
948 | } | 949 | } |
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index f3e97c5f94c9..6c9336626592 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h | |||
@@ -708,6 +708,7 @@ struct vmbus_channel { | |||
708 | u8 monitor_bit; | 708 | u8 monitor_bit; |
709 | 709 | ||
710 | bool rescind; /* got rescind msg */ | 710 | bool rescind; /* got rescind msg */ |
711 | struct completion rescind_event; | ||
711 | 712 | ||
712 | u32 ringbuffer_gpadlhandle; | 713 | u32 ringbuffer_gpadlhandle; |
713 | 714 | ||
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index eaa3bec273c8..4c99c57736ce 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -193,11 +193,14 @@ static void kvp_update_mem_state(int pool) | |||
193 | for (;;) { | 193 | for (;;) { |
194 | readp = &record[records_read]; | 194 | readp = &record[records_read]; |
195 | records_read += fread(readp, sizeof(struct kvp_record), | 195 | records_read += fread(readp, sizeof(struct kvp_record), |
196 | ENTRIES_PER_BLOCK * num_blocks, | 196 | ENTRIES_PER_BLOCK * num_blocks - records_read, |
197 | filep); | 197 | filep); |
198 | 198 | ||
199 | if (ferror(filep)) { | 199 | if (ferror(filep)) { |
200 | syslog(LOG_ERR, "Failed to read file, pool: %d", pool); | 200 | syslog(LOG_ERR, |
201 | "Failed to read file, pool: %d; error: %d %s", | ||
202 | pool, errno, strerror(errno)); | ||
203 | kvp_release_lock(pool); | ||
201 | exit(EXIT_FAILURE); | 204 | exit(EXIT_FAILURE); |
202 | } | 205 | } |
203 | 206 | ||
@@ -210,6 +213,7 @@ static void kvp_update_mem_state(int pool) | |||
210 | 213 | ||
211 | if (record == NULL) { | 214 | if (record == NULL) { |
212 | syslog(LOG_ERR, "malloc failed"); | 215 | syslog(LOG_ERR, "malloc failed"); |
216 | kvp_release_lock(pool); | ||
213 | exit(EXIT_FAILURE); | 217 | exit(EXIT_FAILURE); |
214 | } | 218 | } |
215 | continue; | 219 | continue; |
@@ -224,15 +228,11 @@ static void kvp_update_mem_state(int pool) | |||
224 | fclose(filep); | 228 | fclose(filep); |
225 | kvp_release_lock(pool); | 229 | kvp_release_lock(pool); |
226 | } | 230 | } |
231 | |||
227 | static int kvp_file_init(void) | 232 | static int kvp_file_init(void) |
228 | { | 233 | { |
229 | int fd; | 234 | int fd; |
230 | FILE *filep; | ||
231 | size_t records_read; | ||
232 | char *fname; | 235 | char *fname; |
233 | struct kvp_record *record; | ||
234 | struct kvp_record *readp; | ||
235 | int num_blocks; | ||
236 | int i; | 236 | int i; |
237 | int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; | 237 | int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; |
238 | 238 | ||
@@ -246,61 +246,19 @@ static int kvp_file_init(void) | |||
246 | 246 | ||
247 | for (i = 0; i < KVP_POOL_COUNT; i++) { | 247 | for (i = 0; i < KVP_POOL_COUNT; i++) { |
248 | fname = kvp_file_info[i].fname; | 248 | fname = kvp_file_info[i].fname; |
249 | records_read = 0; | ||
250 | num_blocks = 1; | ||
251 | sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); | 249 | sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); |
252 | fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); | 250 | fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); |
253 | 251 | ||
254 | if (fd == -1) | 252 | if (fd == -1) |
255 | return 1; | 253 | return 1; |
256 | 254 | ||
257 | |||
258 | filep = fopen(fname, "re"); | ||
259 | if (!filep) { | ||
260 | close(fd); | ||
261 | return 1; | ||
262 | } | ||
263 | |||
264 | record = malloc(alloc_unit * num_blocks); | ||
265 | if (record == NULL) { | ||
266 | fclose(filep); | ||
267 | close(fd); | ||
268 | return 1; | ||
269 | } | ||
270 | for (;;) { | ||
271 | readp = &record[records_read]; | ||
272 | records_read += fread(readp, sizeof(struct kvp_record), | ||
273 | ENTRIES_PER_BLOCK, | ||
274 | filep); | ||
275 | |||
276 | if (ferror(filep)) { | ||
277 | syslog(LOG_ERR, "Failed to read file, pool: %d", | ||
278 | i); | ||
279 | exit(EXIT_FAILURE); | ||
280 | } | ||
281 | |||
282 | if (!feof(filep)) { | ||
283 | /* | ||
284 | * We have more data to read. | ||
285 | */ | ||
286 | num_blocks++; | ||
287 | record = realloc(record, alloc_unit * | ||
288 | num_blocks); | ||
289 | if (record == NULL) { | ||
290 | fclose(filep); | ||
291 | close(fd); | ||
292 | return 1; | ||
293 | } | ||
294 | continue; | ||
295 | } | ||
296 | break; | ||
297 | } | ||
298 | kvp_file_info[i].fd = fd; | 255 | kvp_file_info[i].fd = fd; |
299 | kvp_file_info[i].num_blocks = num_blocks; | 256 | kvp_file_info[i].num_blocks = 1; |
300 | kvp_file_info[i].records = record; | 257 | kvp_file_info[i].records = malloc(alloc_unit); |
301 | kvp_file_info[i].num_records = records_read; | 258 | if (kvp_file_info[i].records == NULL) |
302 | fclose(filep); | 259 | return 1; |
303 | 260 | kvp_file_info[i].num_records = 0; | |
261 | kvp_update_mem_state(i); | ||
304 | } | 262 | } |
305 | 263 | ||
306 | return 0; | 264 | return 0; |