diff --git a/config-debug b/config-debug index ca1ba2b59..15a9aade2 100644 --- a/config-debug +++ b/config-debug @@ -110,3 +110,6 @@ CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=1024 # CONFIG_DEBUG_KMEMLEAK_TEST is not set CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_MAC80211_MESSAGE_TRACING=y + +CONFIG_EDAC_DEBUG=y diff --git a/config-generic b/config-generic index dc9441e34..afb70799b 100644 --- a/config-generic +++ b/config-generic @@ -455,6 +455,8 @@ CONFIG_VMXNET3=m CONFIG_HW_RANDOM_VIRTIO=m CONFIG_VIRTIO_CONSOLE=y CONFIG_VHOST_NET=m +# CONFIG_TCM_VHOST is not set + # # SCSI device support @@ -824,6 +826,7 @@ CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y CONFIG_ARPD=y CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -905,6 +908,7 @@ CONFIG_NF_CONNTRACK=m CONFIG_NETFILTER_NETLINK=m CONFIG_NETFILTER_NETLINK_ACCT=m CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_QUEUE_CT=y CONFIG_NETFILTER_NETLINK_LOG=m CONFIG_NETFILTER_TPROXY=m CONFIG_NETFILTER_XTABLES=y @@ -1010,6 +1014,7 @@ CONFIG_NF_CT_PROTO_DCCP=m CONFIG_NF_CT_PROTO_SCTP=m CONFIG_NF_CT_NETLINK=m # CONFIG_NF_CT_NETLINK_TIMEOUT is not set +CONFIG_NF_CT_NETLINK_HELPER=m CONFIG_NF_CT_PROTO_UDPLITE=m CONFIG_IP_NF_MATCH_AH=m @@ -1198,6 +1203,7 @@ CONFIG_NET_EMATCH_META=m CONFIG_NET_EMATCH_NBYTE=m CONFIG_NET_EMATCH_STACK=32 CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_IPSET=m CONFIG_NET_EMATCH_U32=m CONFIG_NET_ACT_CSUM=m @@ -1212,6 +1218,7 @@ CONFIG_NET_ACT_SIMP=m CONFIG_NET_ACT_SKBEDIT=m CONFIG_DCB=y +CONFIG_DNS_RESOLVER=m CONFIG_OPENVSWITCH=m CONFIG_NETPRIO_CGROUP=m @@ -1234,6 +1241,7 @@ CONFIG_NET_TEAM=m CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_NET_TEAM_MODE_BROADCAST=m CONFIG_DUMMY=m CONFIG_BONDING=m CONFIG_MACVLAN=m @@ -1499,6 +1507,7 @@ CONFIG_PCMCIA_XIRC2PS=m CONFIG_PHYLIB=y CONFIG_AMD_PHY=m CONFIG_BROADCOM_PHY=m +CONFIG_BCM87XX_PHY=m CONFIG_CICADA_PHY=m CONFIG_DAVICOM_PHY=m CONFIG_FIXED_PHY=y @@ -1727,6 +1736,7 @@ CONFIG_RT2500PCI=m CONFIG_RT61PCI=m CONFIG_RT2500USB=m CONFIG_RT2800USB=m +CONFIG_RT2800PCI_RT3290=y CONFIG_RT2800USB_RT33XX=y CONFIG_RT2800USB_RT35XX=y CONFIG_RT2800USB_RT53XX=y @@ -1878,6 +1888,7 @@ CONFIG_BT_HCIUART=m CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_3WIRE=y CONFIG_BT_HCIDTL1=m CONFIG_BT_HCIBT3C=m CONFIG_BT_HCIBLUECARD=m @@ -2145,6 +2156,7 @@ CONFIG_TOUCHSCREEN_AD7879_I2C=m # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set # CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set CONFIG_TOUCHSCREEN_DYNAPRO=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m CONFIG_TOUCHSCREEN_EETI=m CONFIG_TOUCHSCREEN_EGALAX=m CONFIG_TOUCHSCREEN_ELO=m @@ -2154,6 +2166,7 @@ CONFIG_TOUCHSCREEN_GUNZE=m CONFIG_TOUCHSCREEN_HTCPEN=m CONFIG_TOUCHSCREEN_INEXIO=m CONFIG_TOUCHSCREEN_ILI210X=m +CONFIG_TOUCHSCREEN_MMS114=m CONFIG_TOUCHSCREEN_MTOUCH=m CONFIG_TOUCHSCREEN_MCS5000=m CONFIG_TOUCHSCREEN_MK712=m @@ -2362,6 +2375,7 @@ CONFIG_SENSORS_G760A=m CONFIG_SENSORS_GL518SM=m CONFIG_SENSORS_GL520SM=m CONFIG_SENSORS_HDAPS=m +# CONFIG_SENSORS_HIH6130 is not set # CONFIG_SENSORS_I5K_AMB is not set # FIXME: IBMAEM x86 only? CONFIG_SENSORS_IBMAEM=m @@ -2627,6 +2641,7 @@ CONFIG_DRM_I2C_CH7006=m CONFIG_DRM_I2C_SIL164=m # CONFIG_DRM_UDL is not set CONFIG_DRM_VMWGFX=m +# CONFIG_DRM_VMWGFX_FBCON is not set # # PCMCIA character devices @@ -2645,6 +2660,11 @@ CONFIG_HANGCHECK_TIMER=m # Multimedia devices # CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_DEV=m # CONFIG_VIDEO_ADV_DEBUG is not set @@ -2741,6 +2761,8 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # Radio Adapters # CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m CONFIG_RADIO_WL1273=m CONFIG_RADIO_WL128X=m @@ -2847,8 +2869,11 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y # CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set CONFIG_RC_CORE=m +CONFIG_RC_DECODERS=y +CONFIG_LIRC=m CONFIG_RC_LOOPBACK=m CONFIG_RC_MAP=m +CONFIG_RC_DEVICES=y CONFIG_RC_ATI_REMOTE=m CONFIG_IR_NEC_DECODER=m CONFIG_IR_RC5_DECODER=m @@ -2868,6 +2893,7 @@ CONFIG_IR_REDRAT3=m CONFIG_IR_ENE=m CONFIG_IR_STREAMZAP=m CONFIG_IR_WINBOND_CIR=m +CONFIG_IR_IGUANA=m CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set @@ -3225,6 +3251,7 @@ CONFIG_HID=ym CONFIG_HID_BATTERY_STRENGTH=y # debugging default is y upstream now CONFIG_HIDRAW=y +CONFIG_UHID=m CONFIG_HID_PID=y CONFIG_LOGITECH_FF=y CONFIG_HID_LOGITECH_DJ=m @@ -3277,6 +3304,7 @@ CONFIG_HID_ACRUX=m CONFIG_HID_ACRUX_FF=y CONFIG_HID_KEYTOUCH=m CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO_TPKBD=m CONFIG_HID_ROCCAT_ARVO=m CONFIG_HID_ROCCAT_KOVAPLUS=m CONFIG_HID_HOLTEK=m @@ -3599,6 +3627,8 @@ CONFIG_MFD_WM8400=m # CONFIG_MFD_TPS65217 is not set # CONFIG_MFD_LM3533 is not set # CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_ARIZONA is not set +# CONFIG_MFD_ARIZONA_I2C is not set # # File systems @@ -3741,6 +3771,7 @@ CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFS_V4_1=y CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +# CONFIG_NFS_SWAP is not set CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V3_ACL=y @@ -3901,6 +3932,7 @@ CONFIG_FRAME_POINTER=y # CONFIG_DEBUG_DRIVER is not set CONFIG_HEADERS_CHECK=y # CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set # CONFIG_READABLE_ASM is not set # CONFIG_RT_MUTEX_TESTER is not set @@ -4121,10 +4153,11 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_SCHED=y -CONFIG_CGROUP_MEM_RES_CTLR=y -CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y # XXX disabled by default, pass 'swapaccount' -# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set -CONFIG_CGROUP_MEM_RES_CTLR_KMEM=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y # XXX disabled by default, pass 'swapaccount' +# CONFIG_MEMCG_SWAP_ENABLED is not set +CONFIG_MEMCG_KMEM=y +# CONFIG_CGROUP_HUGETLB is not set CONFIG_CGROUP_PERF=y CONFIG_BLK_CGROUP=y @@ -4303,6 +4336,7 @@ CONFIG_LEDS_DELL_NETBOOKS=m # CONFIG_LEDS_OT200 is not set CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m CONFIG_LEDS_TRIGGER_IDE_DISK=y CONFIG_LEDS_TRIGGER_HEARTBEAT=m CONFIG_LEDS_TRIGGER_BACKLIGHT=m @@ -4312,6 +4346,8 @@ CONFIG_LEDS_ALIX2=m CONFIG_LEDS_CLEVO_MAIL=m CONFIG_LEDS_INTEL_SS4200=m CONFIG_LEDS_LM3530=m +CONFIG_LEDS_LM3556=m +CONFIG_LEDS_BLINKM=m CONFIG_LEDS_LP3944=m CONFIG_LEDS_LP5521=m CONFIG_LEDS_LP5523=m @@ -4404,7 +4440,7 @@ CONFIG_UIO_SERCOS3=m CONFIG_UIO_PCI_GENERIC=m # CONFIG_UIO_NETX is not set - +# CONFIG_VFIO is not set # LIRC CONFIG_LIRC_STAGING=y @@ -4557,6 +4593,7 @@ CONFIG_ALTERA_STAPL=m # CONFIG_USB_WPAN_HCD is not set # CONFIG_WIMAX_GDM72XX is not set # CONFIG_IPACK_BUS is not set +# CONFIG_CSR_WIFI is not set # # END OF STAGING @@ -4573,6 +4610,7 @@ CONFIG_IMA_AUDIT=y CONFIG_IMA_LSM_RULES=y # CONFIG_EVM is not set +# CONFIG_PWM is not set CONFIG_LSM_MMAP_MIN_ADDR=65536 @@ -4647,6 +4685,7 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_VX855 is not set # CONFIG_GPIO_PCH is not set # CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_AMD8111 is not set # CONFIG_GPIO_SX150X is not set @@ -4656,6 +4695,8 @@ CONFIG_EVENT_POWER_TRACING_DEPRECATED=y CONFIG_TEST_KSTRTOX=y # CONFIG_XZ_DEC_TEST is not set +# CONFIG_POWER_AVS is not set + CONFIG_TARGET_CORE=m CONFIG_ISCSI_TARGET=m CONFIG_LOOPBACK_TARGET=m @@ -4669,6 +4710,8 @@ CONFIG_HWSPINLOCK=m CONFIG_PSTORE=y CONFIG_PSTORE_RAM=m +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_FTRACE is not set # CONFIG_AVERAGE is not set @@ -4680,6 +4723,7 @@ CONFIG_BCMA=m CONFIG_BCMA_BLOCKIO=y CONFIG_BCMA_HOST_PCI_POSSIBLE=y CONFIG_BCMA_HOST_PCI=y +CONFIG_BCMA_DRIVER_GMAC_CMN=y # CONFIG_BCMA_DEBUG is not set # CONFIG_GOOGLE_FIRMWARE is not set diff --git a/config-nodebug b/config-nodebug index 43b70d774..516a45e4a 100644 --- a/config-nodebug +++ b/config-nodebug @@ -104,3 +104,7 @@ CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 # CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set # CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set + +# CONFIG_MAC80211_MESSAGE_TRACING is not set + +# CONFIG_EDAC_DEBUG is not set diff --git a/config-powerpc-generic b/config-powerpc-generic index 1b82cf499..90120de7c 100644 --- a/config-powerpc-generic +++ b/config-powerpc-generic @@ -181,6 +181,7 @@ CONFIG_EDAC_MM_EDAC=m CONFIG_EDAC_PASEMI=m CONFIG_EDAC_AMD8131=m CONFIG_EDAC_AMD8111=m +CONFIG_EDAC_LEGACY_SYSFS=y # CONFIG_AXON_RAM is not set # CONFIG_OPROFILE_CELL is not set @@ -367,3 +368,5 @@ CONFIG_RCU_FANOUT_LEAF=16 # CONFIG_MPIC_MSGR is not set # CONFIG_FA_DUMP is not set # CONFIG_MDIO_BUS_MUX_GPIO is not set + +# CONFIG_FAIL_IOMMU is not set diff --git a/config-sparc64-generic b/config-sparc64-generic index a2b72dfe6..a27e0b44b 100644 --- a/config-sparc64-generic +++ b/config-sparc64-generic @@ -199,3 +199,4 @@ CONFIG_CRYPTO_DEV_NIAGARA2=y # CONFIG_OF_SELFTEST is not set CONFIG_BPF_JIT=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set diff --git a/config-x86-generic b/config-x86-generic index c5fb4d815..de4fbd5cf 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -167,6 +167,7 @@ CONFIG_EDAC_R82600=m CONFIG_EDAC_X38=m CONFIG_EDAC_MCE_INJ=m CONFIG_EDAC_DECODE_MCE=m +CONFIG_EDAC_LEGACY_SYSFS=y CONFIG_SCHED_MC=y @@ -312,6 +313,7 @@ CONFIG_STRICT_DEVMEM=y # CONFIG_NO_BOOTMEM is not set # CONFIG_MEMTEST is not set +# CONFIG_DEBUG_TLBFLUSH is not set # CONFIG_MAXSMP is not set @@ -376,6 +378,8 @@ CONFIG_VIDEO_VIA_CAMERA=m CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_X86_RESERVE_LOW=64 +# CONFIG_IRQ_DOMAIN_DEBUG is not set + CONFIG_PCH_GBE=m CONFIG_PCH_PHUB=m diff --git a/config-x86_64-generic b/config-x86_64-generic index 0b01f9f44..8d300df57 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -52,6 +52,8 @@ CONFIG_CRYPTO_SHA1_SSSE3=m CONFIG_CRYPTO_BLOWFISH_X86_64=m CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m CONFIG_CRYPTO_CAMELLIA_X86_64=m +CONFIG_CRYPTO_SERPENT_AVX_X86_64=m +CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m # CONFIG_I2C_ALI1535 is not set # CONFIG_I2C_ALI1563 is not set @@ -92,6 +94,7 @@ CONFIG_XEN_MAX_DOMAIN_MEMORY=128 # CONFIG_XEN_BALLOON_MEMORY_HOTPLUG is not set CONFIG_XEN_DEV_EVTCHN=m CONFIG_XEN_SYS_HYPERVISOR=y +# CONFIG_XEN_MCE_LOG is not set CONFIG_PROVIDE_OHCI1394_DMA_INIT=y diff --git a/crypto-aesni-intel-fix-wrong-kfree-pointer.patch b/crypto-aesni-intel-fix-wrong-kfree-pointer.patch deleted file mode 100644 index e9942c06f..000000000 --- a/crypto-aesni-intel-fix-wrong-kfree-pointer.patch +++ /dev/null @@ -1,45 +0,0 @@ -From bf084d8f6eb4ded3f90a6ab79bb682db00ebfbd4 Mon Sep 17 00:00:00 2001 -From: Milan Broz -Date: Thu, 28 Jun 2012 17:26:02 +0200 -Subject: [PATCH] crypto: aesni-intel - fix wrong kfree pointer - -kfree(new_key_mem) in rfc4106_set_key() should be called on malloced pointer, -not on aligned one, otherwise it can cause invalid pointer on free. - -(Seen at least once when running tcrypt tests with debug kernel.) - -Signed-off-by: Milan Broz -Signed-off-by: Herbert Xu ---- - arch/x86/crypto/aesni-intel_glue.c | 8 ++++---- - 1 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c -index d662615..34fdcff 100644 ---- a/arch/x86/crypto/aesni-intel_glue.c -+++ b/arch/x86/crypto/aesni-intel_glue.c -@@ -529,7 +529,7 @@ static int rfc4106_set_key(struct crypto_aead *parent, const u8 *key, - struct crypto_aead *cryptd_child = cryptd_aead_child(ctx->cryptd_tfm); - struct aesni_rfc4106_gcm_ctx *child_ctx = - aesni_rfc4106_gcm_ctx_get(cryptd_child); -- u8 *new_key_mem = NULL; -+ u8 *new_key_align, *new_key_mem = NULL; - - if (key_len < 4) { - crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); -@@ -553,9 +553,9 @@ static int rfc4106_set_key(struct crypto_aead *parent, const u8 *key, - if (!new_key_mem) - return -ENOMEM; - -- new_key_mem = PTR_ALIGN(new_key_mem, AESNI_ALIGN); -- memcpy(new_key_mem, key, key_len); -- key = new_key_mem; -+ new_key_align = PTR_ALIGN(new_key_mem, AESNI_ALIGN); -+ memcpy(new_key_align, key, key_len); -+ key = new_key_align; - } - - if (!irq_fpu_usable()) --- -1.7.6.5 - diff --git a/crypto-testmgr-allow-aesni-intel-and-ghash_clmulni-intel.patch b/crypto-testmgr-allow-aesni-intel-and-ghash_clmulni-intel.patch deleted file mode 100644 index 9aef14c52..000000000 --- a/crypto-testmgr-allow-aesni-intel-and-ghash_clmulni-intel.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 6c79294f44fd7d1122cbaabff3b9815b074c0dd0 Mon Sep 17 00:00:00 2001 -From: Milan Broz -Date: Fri, 29 Jun 2012 22:08:09 +0200 -Subject: [PATCH] crypto: testmgr - allow aesni-intel and ghash_clmulni-intel - in fips mode - -Patch 863b557a88f8c033f7419fabafef4712a5055f85 added NULL entries -for intel accelerated drivers but did not marked these fips allowed. -This cause panic if running tests with fips=1. - -For ghash, fips_allowed flag was added in patch -18c0ebd2d8194cce4b3f67e2903fa01bea892cbc. - -Without patch, "modprobe tcrypt" fails with - alg: skcipher: Failed to load transform for cbc-aes-aesni: -2 - cbc-aes-aesni: cbc(aes) alg self test failed in fips mode! - (panic) - -Also add missing cryptd(__driver-cbc-aes-aesni) and -cryptd(__driver-gcm-aes-aesni) test to complement -null tests above, otherwise system complains with - alg: No test for __cbc-aes-aesni (cryptd(__driver-cbc-aes-aesni)) - alg: No test for __gcm-aes-aesni (cryptd(__driver-gcm-aes-aesni)) - -Signed-off-by: Milan Broz -Signed-off-by: Paul Wouters -Signed-off-by: Herbert Xu ---- - crypto/testmgr.c | 38 ++++++++++++++++++++++++++++++++++++++ - 1 files changed, 38 insertions(+), 0 deletions(-) - -diff --git a/crypto/testmgr.c b/crypto/testmgr.c -index 36748a5..4308a11 100644 ---- a/crypto/testmgr.c -+++ b/crypto/testmgr.c -@@ -1581,6 +1581,7 @@ static const struct alg_test_desc alg_test_descs[] = { - }, { - .alg = "__driver-cbc-aes-aesni", - .test = alg_test_null, -+ .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { -@@ -1641,6 +1642,7 @@ static const struct alg_test_desc alg_test_descs[] = { - }, { - .alg = "__driver-ecb-aes-aesni", - .test = alg_test_null, -+ .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { -@@ -1701,6 +1703,7 @@ static const struct alg_test_desc alg_test_descs[] = { - }, { - .alg = "__ghash-pclmulqdqni", - .test = alg_test_null, -+ .fips_allowed = 1, - .suite = { - .hash = { - .vecs = NULL, -@@ -1866,8 +1869,25 @@ static const struct alg_test_desc alg_test_descs[] = { - } - } - }, { -+ .alg = "cryptd(__driver-cbc-aes-aesni)", -+ .test = alg_test_null, -+ .fips_allowed = 1, -+ .suite = { -+ .cipher = { -+ .enc = { -+ .vecs = NULL, -+ .count = 0 -+ }, -+ .dec = { -+ .vecs = NULL, -+ .count = 0 -+ } -+ } -+ } -+ }, { - .alg = "cryptd(__driver-ecb-aes-aesni)", - .test = alg_test_null, -+ .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { -@@ -1926,8 +1946,25 @@ static const struct alg_test_desc alg_test_descs[] = { - } - } - }, { -+ .alg = "cryptd(__driver-gcm-aes-aesni)", -+ .test = alg_test_null, -+ .fips_allowed = 1, -+ .suite = { -+ .cipher = { -+ .enc = { -+ .vecs = NULL, -+ .count = 0 -+ }, -+ .dec = { -+ .vecs = NULL, -+ .count = 0 -+ } -+ } -+ } -+ }, { - .alg = "cryptd(__ghash-pclmulqdqni)", - .test = alg_test_null, -+ .fips_allowed = 1, - .suite = { - .hash = { - .vecs = NULL, -@@ -2043,6 +2080,7 @@ static const struct alg_test_desc alg_test_descs[] = { - }, { - .alg = "ecb(__aes-aesni)", - .test = alg_test_null, -+ .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { --- -1.7.6.5 - diff --git a/kernel.spec b/kernel.spec index b588c141a..1124dbddf 100644 --- a/kernel.spec +++ b/kernel.spec @@ -60,13 +60,13 @@ Summary: The Linux kernel # base_sublevel is the kernel version we're starting with and patching # on top of -- for example, 2.6.22-rc7-git1 starts with a 2.6.21 base, # which yields a base_sublevel of 21. -%define base_sublevel 5 +%define base_sublevel 6 ## If this is a released kernel ## %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 7 +%define stable_update 0 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly @@ -668,9 +668,6 @@ Patch14010: lis3-improve-handling-of-null-rate.patch Patch19000: ips-noirq.patch -# Uprobes (rhbz 832083) -Patch20000: uprobes-backport.patch - #rhbz 769766 Patch21072: mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch @@ -688,10 +685,6 @@ Patch21306: shlib_base_randomize.patch Patch30000: weird-root-dentry-name-debug.patch Patch30010: debug-808990.patch -#Fix FIPS for aesni hardare -Patch22055: crypto-testmgr-allow-aesni-intel-and-ghash_clmulni-intel.patch -Patch22056: crypto-aesni-intel-fix-wrong-kfree-pointer.patch - # END OF PATCH DEFINITIONS %endif @@ -1285,9 +1278,6 @@ ApplyPatch ips-noirq.patch #ApplyPatch pci-crs-blacklist.patch -# Uprobes (rhbz 832083) -ApplyPatch uprobes-backport.patch - #rhbz 754518 #ApplyPatch scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch @@ -1297,10 +1287,6 @@ ApplyPatch unhandled-irqs-switch-to-polling.patch ApplyPatch weird-root-dentry-name-debug.patch ApplyPatch debug-808990.patch -#Fix FIPS for aesni hardare -ApplyPatch crypto-testmgr-allow-aesni-intel-and-ghash_clmulni-intel.patch -ApplyPatch crypto-aesni-intel-fix-wrong-kfree-pointer.patch - # END OF PATCH APPLICATIONS %endif @@ -2001,6 +1987,9 @@ fi # and build. %changelog +* Tue Oct 16 2012 Dave Jones +- Linux 3.6 + * Tue Oct 16 2012 Dave Jones 3.5.7-1 - Linux 3.5.7 diff --git a/uprobes-backport.patch b/uprobes-backport.patch deleted file mode 100644 index 5f2bacfc0..000000000 --- a/uprobes-backport.patch +++ /dev/null @@ -1,1742 +0,0 @@ -Hello, - -Test build: http://koji.fedoraproject.org/koji/taskinfo?taskID=4490824 -This also fixes: https://bugzilla.redhat.com/show_bug.cgi?id=849364 - -The split-out series is available in the git repository at: - http://fedorapeople.org/cgit/aarapov/public_git/kernel-uprobes.git/log/?h=f17_uprobes_out - (Just @jistone's patch is not upstream that exports functions.) - -Ananth N Mavinakayanahalli (1): - uprobes: Pass probed vaddr to arch_uprobe_analyze_insn() - -Josh Stone (1): - uprobes: add exports necessary for uprobes use by modules - -Oleg Nesterov (52): - uprobes: Optimize is_swbp_at_addr() for current->mm - uprobes: Change read_opcode() to use FOLL_FORCE - uprobes: Introduce find_active_uprobe() helper - uprobes: Teach find_active_uprobe() to provide the "is_swbp" info - uprobes: Change register_for_each_vma() to take mm->mmap_sem for writing - uprobes: Teach handle_swbp() to rely on "is_swbp" rather than uprobes_srcu - uprobes: Kill uprobes_srcu/uprobe_srcu_id - uprobes: Valid_vma() should reject VM_HUGETLB - uprobes: __copy_insn() should ensure a_ops->readpage != NULL - uprobes: Write_opcode()->__replace_page() can race with try_to_unmap() - uprobes: Install_breakpoint() should fail if is_swbp_insn() == T - uprobes: Rework register_for_each_vma() to make it O(n) - uprobes: Change build_map_info() to try kmalloc(GFP_NOWAIT) first - uprobes: Copy_insn() shouldn't depend on mm/vma/vaddr - uprobes: Copy_insn() should not return -ENOMEM if __copy_insn() fails - uprobes: No need to re-check vma_address() in write_opcode() - uprobes: Move BUG_ON(UPROBE_SWBP_INSN_SIZE) from write_opcode() to install_breakpoint() - uprobes: Simplify the usage of uprobe->pending_list - uprobes: Don't use loff_t for the valid virtual address - uprobes: __copy_insn() needs "loff_t offset" - uprobes: Remove the unnecessary initialization in add_utask() - uprobes: Don't recheck vma/f_mapping in write_opcode() - uprobes: __replace_page() should not use page_address_in_vma() - uprobes: Kill write_opcode()->lock_page(new_page) - uprobes: Clean up and document write_opcode()->lock_page(old_page) - uprobes: Uprobe_mmap/munmap needs list_for_each_entry_safe() - uprobes: Suppress uprobe_munmap() from mmput() - uprobes: Fix overflow in vma_address()/find_active_uprobe() - uprobes: Remove copy_vma()->uprobe_mmap() - uprobes: Remove insert_vm_struct()->uprobe_mmap() - uprobes: Teach build_probe_list() to consider the range - uprobes: Introduce vaddr_to_offset(vma, vaddr) - uprobes: Fix register_for_each_vma()->vma_address() check - uprobes: Rename vma_address() and make it return "unsigned long" - uprobes: __replace_page() needs munlock_vma_page() - uprobes: Fix mmap_region()'s mm->mm_rb corruption if uprobe_mmap() fails - uprobes: Kill uprobes_state->count - uprobes: Kill dup_mmap()->uprobe_mmap(), simplify uprobe_mmap/munmap - uprobes: Change uprobe_mmap() to ignore the errors but check fatal_signal_pending() - uprobes: Do not use -EEXIST in install_breakpoint() paths - uprobes: Introduce MMF_HAS_UPROBES - uprobes: Fold uprobe_reset_state() into uprobe_dup_mmap() - uprobes: Remove "verify" argument from set_orig_insn() - uprobes: uprobes_treelock should not disable irqs - uprobes: Introduce MMF_RECALC_UPROBES - uprobes: Teach find_active_uprobe() to clear MMF_HAS_UPROBES - ptrace/x86: Introduce set_task_blockstep() helper - ptrace/x86: Partly fix set_task_blockstep()->update_debugctlmsr() logic - uprobes/x86: Do not (ab)use TIF_SINGLESTEP/user_*_single_step() for single-stepping - uprobes/x86: Xol should send SIGTRAP if X86_EFLAGS_TF was set - uprobes/x86: Fix arch_uprobe_disable_step() && UTASK_SSTEP_TRAPPED interaction - uprobes: Make arch_uprobe_task->saved_trap_nr "unsigned int" - -Peter Zijlstra (1): - uprobes: Document uprobe_register() vs uprobe_mmap() race - -Sebastian Andrzej Siewior (4): - uprobes: Remove check for uprobe variable in handle_swbp() - uprobes: Don't put NULL pointer in uprobe_register() - uprobes: Introduce arch_uprobe_enable/disable_step() - uprobes/x86: Implement x86 specific arch_uprobe_*_step - -Srikar Dronamraju (1): - uprobes: Remove redundant lock_page/unlock_page - -Signed-off-by: Anton Arapov ---- - arch/x86/include/asm/processor.h | 2 + - arch/x86/include/asm/uprobes.h | 5 +- - arch/x86/kernel/step.c | 53 ++- - arch/x86/kernel/uprobes.c | 55 ++- - include/linux/sched.h | 4 +- - include/linux/uprobes.h | 15 +- - kernel/events/uprobes.c | 819 +++++++++++++++++++-------------------- - kernel/fork.c | 6 +- - kernel/ptrace.c | 6 + - mm/mmap.c | 11 +- - 10 files changed, 505 insertions(+), 471 deletions(-) - -diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h -index 39bc577..2f9f8ca 100644 ---- a/arch/x86/include/asm/processor.h -+++ b/arch/x86/include/asm/processor.h -@@ -746,6 +746,8 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr) - wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); - } - -+extern void set_task_blockstep(struct task_struct *task, bool on); -+ - /* - * from system description table in BIOS. Mostly for MCA use, but - * others may find it useful: -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index 1e9bed1..8ff8be7 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -42,13 +42,14 @@ struct arch_uprobe { - }; - - struct arch_uprobe_task { -- unsigned long saved_trap_nr; - #ifdef CONFIG_X86_64 - unsigned long saved_scratch_register; - #endif -+ unsigned int saved_trap_nr; -+ unsigned int saved_tf; - }; - --extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm); -+extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); - extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); - extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); - extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); -diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c -index c346d11..cd3b243 100644 ---- a/arch/x86/kernel/step.c -+++ b/arch/x86/kernel/step.c -@@ -157,6 +157,33 @@ static int enable_single_step(struct task_struct *child) - return 1; - } - -+void set_task_blockstep(struct task_struct *task, bool on) -+{ -+ unsigned long debugctl; -+ -+ /* -+ * Ensure irq/preemption can't change debugctl in between. -+ * Note also that both TIF_BLOCKSTEP and debugctl should -+ * be changed atomically wrt preemption. -+ * FIXME: this means that set/clear TIF_BLOCKSTEP is simply -+ * wrong if task != current, SIGKILL can wakeup the stopped -+ * tracee and set/clear can play with the running task, this -+ * can confuse the next __switch_to_xtra(). -+ */ -+ local_irq_disable(); -+ debugctl = get_debugctlmsr(); -+ if (on) { -+ debugctl |= DEBUGCTLMSR_BTF; -+ set_tsk_thread_flag(task, TIF_BLOCKSTEP); -+ } else { -+ debugctl &= ~DEBUGCTLMSR_BTF; -+ clear_tsk_thread_flag(task, TIF_BLOCKSTEP); -+ } -+ if (task == current) -+ update_debugctlmsr(debugctl); -+ local_irq_enable(); -+} -+ - /* - * Enable single or block step. - */ -@@ -169,19 +196,10 @@ static void enable_step(struct task_struct *child, bool block) - * So no one should try to use debugger block stepping in a program - * that uses user-mode single stepping itself. - */ -- if (enable_single_step(child) && block) { -- unsigned long debugctl = get_debugctlmsr(); -- -- debugctl |= DEBUGCTLMSR_BTF; -- update_debugctlmsr(debugctl); -- set_tsk_thread_flag(child, TIF_BLOCKSTEP); -- } else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { -- unsigned long debugctl = get_debugctlmsr(); -- -- debugctl &= ~DEBUGCTLMSR_BTF; -- update_debugctlmsr(debugctl); -- clear_tsk_thread_flag(child, TIF_BLOCKSTEP); -- } -+ if (enable_single_step(child) && block) -+ set_task_blockstep(child, true); -+ else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) -+ set_task_blockstep(child, false); - } - - void user_enable_single_step(struct task_struct *child) -@@ -199,13 +217,8 @@ void user_disable_single_step(struct task_struct *child) - /* - * Make sure block stepping (BTF) is disabled. - */ -- if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { -- unsigned long debugctl = get_debugctlmsr(); -- -- debugctl &= ~DEBUGCTLMSR_BTF; -- update_debugctlmsr(debugctl); -- clear_tsk_thread_flag(child, TIF_BLOCKSTEP); -- } -+ if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) -+ set_task_blockstep(child, false); - - /* Always clear TIF_SINGLESTEP... */ - clear_tsk_thread_flag(child, TIF_SINGLESTEP); -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index dc4e910..9538f00 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -41,6 +41,9 @@ - /* Adjust the return address of a call insn */ - #define UPROBE_FIX_CALL 0x2 - -+/* Instruction will modify TF, don't change it */ -+#define UPROBE_FIX_SETF 0x4 -+ - #define UPROBE_FIX_RIP_AX 0x8000 - #define UPROBE_FIX_RIP_CX 0x4000 - -@@ -239,6 +242,10 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) - insn_get_opcode(insn); /* should be a nop */ - - switch (OPCODE1(insn)) { -+ case 0x9d: -+ /* popf */ -+ auprobe->fixups |= UPROBE_FIX_SETF; -+ break; - case 0xc3: /* ret/lret */ - case 0xcb: - case 0xc2: -@@ -409,9 +416,10 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, - * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. - * @mm: the probed address space. - * @arch_uprobe: the probepoint information. -+ * @addr: virtual address at which to install the probepoint - * Return 0 on success or a -ve number on error. - */ --int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm) -+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) - { - int ret; - struct insn insn; -@@ -645,7 +653,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) - * Skip these instructions as per the currently known x86 ISA. - * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } - */ --bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) -+static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) - { - int i; - -@@ -672,3 +680,46 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) - } - return false; - } -+ -+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ bool ret = __skip_sstep(auprobe, regs); -+ if (ret && (regs->flags & X86_EFLAGS_TF)) -+ send_sig(SIGTRAP, current, 0); -+ return ret; -+} -+ -+void arch_uprobe_enable_step(struct arch_uprobe *auprobe) -+{ -+ struct task_struct *task = current; -+ struct arch_uprobe_task *autask = &task->utask->autask; -+ struct pt_regs *regs = task_pt_regs(task); -+ -+ autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); -+ -+ regs->flags |= X86_EFLAGS_TF; -+ if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) -+ set_task_blockstep(task, false); -+} -+ -+void arch_uprobe_disable_step(struct arch_uprobe *auprobe) -+{ -+ struct task_struct *task = current; -+ struct arch_uprobe_task *autask = &task->utask->autask; -+ bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED); -+ struct pt_regs *regs = task_pt_regs(task); -+ /* -+ * The state of TIF_BLOCKSTEP was not saved so we can get an extra -+ * SIGTRAP if we do not clear TF. We need to examine the opcode to -+ * make it right. -+ */ -+ if (unlikely(trapped)) { -+ if (!autask->saved_tf) -+ regs->flags &= ~X86_EFLAGS_TF; -+ } else { -+ if (autask->saved_tf) -+ send_sig(SIGTRAP, task, 0); -+ else if (!(auprobe->fixups & UPROBE_FIX_SETF)) -+ regs->flags &= ~X86_EFLAGS_TF; -+ } -+} -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 4a1f493..864054f 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -441,6 +441,9 @@ extern int get_dumpable(struct mm_struct *mm); - #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ - #define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ - -+#define MMF_HAS_UPROBES 19 /* has uprobes */ -+#define MMF_RECALC_UPROBES 20 /* MMF_HAS_UPROBES can be wrong */ -+ - #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) - - struct sighand_struct { -@@ -1581,7 +1584,6 @@ struct task_struct { - #endif - #ifdef CONFIG_UPROBES - struct uprobe_task *utask; -- int uprobe_srcu_id; - #endif - }; - -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index efe4b33..e6f0331 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -99,25 +99,27 @@ struct xol_area { - - struct uprobes_state { - struct xol_area *xol_area; -- atomic_t count; - }; -+ - extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); --extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify); -+extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); - extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); - extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern int uprobe_mmap(struct vm_area_struct *vma); - extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); -+extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); - extern void uprobe_free_utask(struct task_struct *t); - extern void uprobe_copy_process(struct task_struct *t); - extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); -+extern void __weak arch_uprobe_enable_step(struct arch_uprobe *arch); -+extern void __weak arch_uprobe_disable_step(struct arch_uprobe *arch); - extern int uprobe_post_sstep_notifier(struct pt_regs *regs); - extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); - extern void uprobe_notify_resume(struct pt_regs *regs); - extern bool uprobe_deny_signal(void); - extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); - extern void uprobe_clear_state(struct mm_struct *mm); --extern void uprobe_reset_state(struct mm_struct *mm); - #else /* !CONFIG_UPROBES */ - struct uprobes_state { - }; -@@ -138,6 +140,10 @@ static inline void - uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) - { - } -+static inline void -+uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) -+{ -+} - static inline void uprobe_notify_resume(struct pt_regs *regs) - { - } -@@ -158,8 +164,5 @@ static inline void uprobe_copy_process(struct task_struct *t) - static inline void uprobe_clear_state(struct mm_struct *mm) - { - } --static inline void uprobe_reset_state(struct mm_struct *mm) --{ --} - #endif /* !CONFIG_UPROBES */ - #endif /* _LINUX_UPROBES_H */ -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 985be4d..f8a97e7 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -27,24 +27,42 @@ - #include /* read_mapping_page */ - #include - #include -+#include - #include /* anon_vma_prepare */ - #include /* set_pte_at_notify */ - #include /* try_to_free_swap */ - #include /* user_enable_single_step */ - #include /* notifier mechanism */ -+#include "../../mm/internal.h" /* munlock_vma_page */ - - #include - - #define UINSNS_PER_PAGE (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES) - #define MAX_UPROBE_XOL_SLOTS UINSNS_PER_PAGE - --static struct srcu_struct uprobes_srcu; - static struct rb_root uprobes_tree = RB_ROOT; - - static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ - - #define UPROBES_HASH_SZ 13 - -+/* -+ * We need separate register/unregister and mmap/munmap lock hashes because -+ * of mmap_sem nesting. -+ * -+ * uprobe_register() needs to install probes on (potentially) all processes -+ * and thus needs to acquire multiple mmap_sems (consequtively, not -+ * concurrently), whereas uprobe_mmap() is called while holding mmap_sem -+ * for the particular process doing the mmap. -+ * -+ * uprobe_register()->register_for_each_vma() needs to drop/acquire mmap_sem -+ * because of lock order against i_mmap_mutex. This means there's a hole in -+ * the register vma iteration where a mmap() can happen. -+ * -+ * Thus uprobe_register() can race with uprobe_mmap() and we can try and -+ * install a probe where one is already installed. -+ */ -+ - /* serialize (un)register */ - static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; - -@@ -61,17 +79,6 @@ static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; - */ - static atomic_t uprobe_events = ATOMIC_INIT(0); - --/* -- * Maintain a temporary per vma info that can be used to search if a vma -- * has already been handled. This structure is introduced since extending -- * vm_area_struct wasnt recommended. -- */ --struct vma_info { -- struct list_head probe_list; -- struct mm_struct *mm; -- loff_t vaddr; --}; -- - struct uprobe { - struct rb_node rb_node; /* node in the rb tree */ - atomic_t ref; -@@ -100,20 +107,21 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register) - if (!is_register) - return true; - -- if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC)) -+ if ((vma->vm_flags & (VM_HUGETLB|VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) -+ == (VM_READ|VM_EXEC)) - return true; - - return false; - } - --static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) -+static unsigned long offset_to_vaddr(struct vm_area_struct *vma, loff_t offset) - { -- loff_t vaddr; -- -- vaddr = vma->vm_start + offset; -- vaddr -= vma->vm_pgoff << PAGE_SHIFT; -+ return vma->vm_start + offset - ((loff_t)vma->vm_pgoff << PAGE_SHIFT); -+} - -- return vaddr; -+static loff_t vaddr_to_offset(struct vm_area_struct *vma, unsigned long vaddr) -+{ -+ return ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (vaddr - vma->vm_start); - } - - /** -@@ -121,41 +129,27 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) - * based on replace_page in mm/ksm.c - * - * @vma: vma that holds the pte pointing to page -+ * @addr: address the old @page is mapped at - * @page: the cowed page we are replacing by kpage - * @kpage: the modified page we replace page by - * - * Returns 0 on success, -EFAULT on failure. - */ --static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage) -+static int __replace_page(struct vm_area_struct *vma, unsigned long addr, -+ struct page *page, struct page *kpage) - { - struct mm_struct *mm = vma->vm_mm; -- pgd_t *pgd; -- pud_t *pud; -- pmd_t *pmd; -- pte_t *ptep; - spinlock_t *ptl; -- unsigned long addr; -- int err = -EFAULT; -- -- addr = page_address_in_vma(page, vma); -- if (addr == -EFAULT) -- goto out; -- -- pgd = pgd_offset(mm, addr); -- if (!pgd_present(*pgd)) -- goto out; -- -- pud = pud_offset(pgd, addr); -- if (!pud_present(*pud)) -- goto out; -+ pte_t *ptep; -+ int err; - -- pmd = pmd_offset(pud, addr); -- if (!pmd_present(*pmd)) -- goto out; -+ /* For try_to_free_swap() and munlock_vma_page() below */ -+ lock_page(page); - -- ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); -+ err = -EAGAIN; -+ ptep = page_check_address(page, mm, addr, &ptl, 0); - if (!ptep) -- goto out; -+ goto unlock; - - get_page(kpage); - page_add_new_anon_rmap(kpage, vma, addr); -@@ -172,11 +166,15 @@ static int __replace_page(struct vm_area_struct *vma, struct page *page, struct - page_remove_rmap(page); - if (!page_mapped(page)) - try_to_free_swap(page); -- put_page(page); - pte_unmap_unlock(ptep, ptl); -- err = 0; - --out: -+ if (vma->vm_flags & VM_LOCKED) -+ munlock_vma_page(page); -+ put_page(page); -+ -+ err = 0; -+ unlock: -+ unlock_page(page); - return err; - } - -@@ -218,79 +216,46 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, - unsigned long vaddr, uprobe_opcode_t opcode) - { - struct page *old_page, *new_page; -- struct address_space *mapping; - void *vaddr_old, *vaddr_new; - struct vm_area_struct *vma; -- struct uprobe *uprobe; -- loff_t addr; - int ret; - -+retry: - /* Read the page with vaddr into memory */ - ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); - if (ret <= 0) - return ret; - -- ret = -EINVAL; -- -- /* -- * We are interested in text pages only. Our pages of interest -- * should be mapped for read and execute only. We desist from -- * adding probes in write mapped pages since the breakpoints -- * might end up in the file copy. -- */ -- if (!valid_vma(vma, is_swbp_insn(&opcode))) -- goto put_out; -- -- uprobe = container_of(auprobe, struct uprobe, arch); -- mapping = uprobe->inode->i_mapping; -- if (mapping != vma->vm_file->f_mapping) -- goto put_out; -- -- addr = vma_address(vma, uprobe->offset); -- if (vaddr != (unsigned long)addr) -- goto put_out; -- - ret = -ENOMEM; - new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); - if (!new_page) -- goto put_out; -+ goto put_old; - - __SetPageUptodate(new_page); - -- /* -- * lock page will serialize against do_wp_page()'s -- * PageAnon() handling -- */ -- lock_page(old_page); - /* copy the page now that we've got it stable */ - vaddr_old = kmap_atomic(old_page); - vaddr_new = kmap_atomic(new_page); - - memcpy(vaddr_new, vaddr_old, PAGE_SIZE); -- -- /* poke the new insn in, ASSUMES we don't cross page boundary */ -- vaddr &= ~PAGE_MASK; -- BUG_ON(vaddr + UPROBE_SWBP_INSN_SIZE > PAGE_SIZE); -- memcpy(vaddr_new + vaddr, &opcode, UPROBE_SWBP_INSN_SIZE); -+ memcpy(vaddr_new + (vaddr & ~PAGE_MASK), &opcode, UPROBE_SWBP_INSN_SIZE); - - kunmap_atomic(vaddr_new); - kunmap_atomic(vaddr_old); - - ret = anon_vma_prepare(vma); - if (ret) -- goto unlock_out; -+ goto put_new; - -- lock_page(new_page); -- ret = __replace_page(vma, old_page, new_page); -- unlock_page(new_page); -+ ret = __replace_page(vma, vaddr, old_page, new_page); - --unlock_out: -- unlock_page(old_page); -+put_new: - page_cache_release(new_page); -- --put_out: -+put_old: - put_page(old_page); - -+ if (unlikely(ret == -EAGAIN)) -+ goto retry; - return ret; - } - -@@ -312,16 +277,14 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_ - void *vaddr_new; - int ret; - -- ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL); -+ ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); - if (ret <= 0) - return ret; - -- lock_page(page); - vaddr_new = kmap_atomic(page); - vaddr &= ~PAGE_MASK; - memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE); - kunmap_atomic(vaddr_new); -- unlock_page(page); - - put_page(page); - -@@ -333,10 +296,20 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) - uprobe_opcode_t opcode; - int result; - -+ if (current->mm == mm) { -+ pagefault_disable(); -+ result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr, -+ sizeof(opcode)); -+ pagefault_enable(); -+ -+ if (likely(result == 0)) -+ goto out; -+ } -+ - result = read_opcode(mm, vaddr, &opcode); - if (result) - return result; -- -+out: - if (is_swbp_insn(&opcode)) - return 1; - -@@ -355,10 +328,12 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) - int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) - { - int result; -- -+ /* -+ * See the comment near uprobes_hash(). -+ */ - result = is_swbp_at_addr(mm, vaddr); - if (result == 1) -- return -EEXIST; -+ return 0; - - if (result) - return result; -@@ -371,24 +346,22 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned - * @mm: the probed process address space. - * @auprobe: arch specific probepoint information. - * @vaddr: the virtual address to insert the opcode. -- * @verify: if true, verify existance of breakpoint instruction. - * - * For mm @mm, restore the original opcode (opcode) at @vaddr. - * Return 0 (success) or a negative errno. - */ - int __weak --set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr, bool verify) -+set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) - { -- if (verify) { -- int result; -+ int result; - -- result = is_swbp_at_addr(mm, vaddr); -- if (!result) -- return -EINVAL; -+ result = is_swbp_at_addr(mm, vaddr); -+ if (!result) -+ return -EINVAL; -+ -+ if (result != 1) -+ return result; - -- if (result != 1) -- return result; -- } - return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); - } - -@@ -439,11 +412,10 @@ static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset) - static struct uprobe *find_uprobe(struct inode *inode, loff_t offset) - { - struct uprobe *uprobe; -- unsigned long flags; - -- spin_lock_irqsave(&uprobes_treelock, flags); -+ spin_lock(&uprobes_treelock); - uprobe = __find_uprobe(inode, offset); -- spin_unlock_irqrestore(&uprobes_treelock, flags); -+ spin_unlock(&uprobes_treelock); - - return uprobe; - } -@@ -490,12 +462,11 @@ static struct uprobe *__insert_uprobe(struct uprobe *uprobe) - */ - static struct uprobe *insert_uprobe(struct uprobe *uprobe) - { -- unsigned long flags; - struct uprobe *u; - -- spin_lock_irqsave(&uprobes_treelock, flags); -+ spin_lock(&uprobes_treelock); - u = __insert_uprobe(uprobe); -- spin_unlock_irqrestore(&uprobes_treelock, flags); -+ spin_unlock(&uprobes_treelock); - - /* For now assume that the instruction need not be single-stepped */ - uprobe->flags |= UPROBE_SKIP_SSTEP; -@@ -520,7 +491,6 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) - uprobe->inode = igrab(inode); - uprobe->offset = offset; - init_rwsem(&uprobe->consumer_rwsem); -- INIT_LIST_HEAD(&uprobe->pending_list); - - /* add to uprobes_tree, sorted on inode:offset */ - cur_uprobe = insert_uprobe(uprobe); -@@ -588,20 +558,22 @@ static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc) - } - - static int --__copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *insn, -- unsigned long nbytes, unsigned long offset) -+__copy_insn(struct address_space *mapping, struct file *filp, char *insn, -+ unsigned long nbytes, loff_t offset) - { -- struct file *filp = vma->vm_file; - struct page *page; - void *vaddr; -- unsigned long off1; -- unsigned long idx; -+ unsigned long off; -+ pgoff_t idx; - - if (!filp) - return -EINVAL; - -- idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT); -- off1 = offset &= ~PAGE_MASK; -+ if (!mapping->a_ops->readpage) -+ return -EIO; -+ -+ idx = offset >> PAGE_CACHE_SHIFT; -+ off = offset & ~PAGE_MASK; - - /* - * Ensure that the page that has the original instruction is -@@ -612,22 +584,20 @@ __copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *ins - return PTR_ERR(page); - - vaddr = kmap_atomic(page); -- memcpy(insn, vaddr + off1, nbytes); -+ memcpy(insn, vaddr + off, nbytes); - kunmap_atomic(vaddr); - page_cache_release(page); - - return 0; - } - --static int --copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) -+static int copy_insn(struct uprobe *uprobe, struct file *filp) - { - struct address_space *mapping; - unsigned long nbytes; - int bytes; - -- addr &= ~PAGE_MASK; -- nbytes = PAGE_SIZE - addr; -+ nbytes = PAGE_SIZE - (uprobe->offset & ~PAGE_MASK); - mapping = uprobe->inode->i_mapping; - - /* Instruction at end of binary; copy only available bytes */ -@@ -638,13 +608,13 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) - - /* Instruction at the page-boundary; copy bytes in second page */ - if (nbytes < bytes) { -- if (__copy_insn(mapping, vma, uprobe->arch.insn + nbytes, -- bytes - nbytes, uprobe->offset + nbytes)) -- return -ENOMEM; -- -+ int err = __copy_insn(mapping, filp, uprobe->arch.insn + nbytes, -+ bytes - nbytes, uprobe->offset + nbytes); -+ if (err) -+ return err; - bytes = nbytes; - } -- return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset); -+ return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset); - } - - /* -@@ -672,9 +642,9 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) - */ - static int - install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, -- struct vm_area_struct *vma, loff_t vaddr) -+ struct vm_area_struct *vma, unsigned long vaddr) - { -- unsigned long addr; -+ bool first_uprobe; - int ret; - - /* -@@ -685,204 +655,194 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - * Hence behave as if probe already existed. - */ - if (!uprobe->consumers) -- return -EEXIST; -- -- addr = (unsigned long)vaddr; -+ return 0; - - if (!(uprobe->flags & UPROBE_COPY_INSN)) { -- ret = copy_insn(uprobe, vma, addr); -+ ret = copy_insn(uprobe, vma->vm_file); - if (ret) - return ret; - - if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) -- return -EEXIST; -+ return -ENOTSUPP; - -- ret = arch_uprobe_analyze_insn(&uprobe->arch, mm); -+ ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); - if (ret) - return ret; - -+ /* write_opcode() assumes we don't cross page boundary */ -+ BUG_ON((uprobe->offset & ~PAGE_MASK) + -+ UPROBE_SWBP_INSN_SIZE > PAGE_SIZE); -+ - uprobe->flags |= UPROBE_COPY_INSN; - } - - /* -- * Ideally, should be updating the probe count after the breakpoint -- * has been successfully inserted. However a thread could hit the -- * breakpoint we just inserted even before the probe count is -- * incremented. If this is the first breakpoint placed, breakpoint -- * notifier might ignore uprobes and pass the trap to the thread. -- * Hence increment before and decrement on failure. -+ * set MMF_HAS_UPROBES in advance for uprobe_pre_sstep_notifier(), -+ * the task can hit this breakpoint right after __replace_page(). - */ -- atomic_inc(&mm->uprobes_state.count); -- ret = set_swbp(&uprobe->arch, mm, addr); -- if (ret) -- atomic_dec(&mm->uprobes_state.count); -+ first_uprobe = !test_bit(MMF_HAS_UPROBES, &mm->flags); -+ if (first_uprobe) -+ set_bit(MMF_HAS_UPROBES, &mm->flags); -+ -+ ret = set_swbp(&uprobe->arch, mm, vaddr); -+ if (!ret) -+ clear_bit(MMF_RECALC_UPROBES, &mm->flags); -+ else if (first_uprobe) -+ clear_bit(MMF_HAS_UPROBES, &mm->flags); - - return ret; - } - - static void --remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr) -+remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) - { -- if (!set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true)) -- atomic_dec(&mm->uprobes_state.count); -+ /* can happen if uprobe_register() fails */ -+ if (!test_bit(MMF_HAS_UPROBES, &mm->flags)) -+ return; -+ -+ set_bit(MMF_RECALC_UPROBES, &mm->flags); -+ set_orig_insn(&uprobe->arch, mm, vaddr); - } - - /* -- * There could be threads that have hit the breakpoint and are entering the -- * notifier code and trying to acquire the uprobes_treelock. The thread -- * calling delete_uprobe() that is removing the uprobe from the rb_tree can -- * race with these threads and might acquire the uprobes_treelock compared -- * to some of the breakpoint hit threads. In such a case, the breakpoint -- * hit threads will not find the uprobe. The current unregistering thread -- * waits till all other threads have hit a breakpoint, to acquire the -- * uprobes_treelock before the uprobe is removed from the rbtree. -+ * There could be threads that have already hit the breakpoint. They -+ * will recheck the current insn and restart if find_uprobe() fails. -+ * See find_active_uprobe(). - */ - static void delete_uprobe(struct uprobe *uprobe) - { -- unsigned long flags; -- -- synchronize_srcu(&uprobes_srcu); -- spin_lock_irqsave(&uprobes_treelock, flags); -+ spin_lock(&uprobes_treelock); - rb_erase(&uprobe->rb_node, &uprobes_tree); -- spin_unlock_irqrestore(&uprobes_treelock, flags); -+ spin_unlock(&uprobes_treelock); - iput(uprobe->inode); - put_uprobe(uprobe); - atomic_dec(&uprobe_events); - } - --static struct vma_info * --__find_next_vma_info(struct address_space *mapping, struct list_head *head, -- struct vma_info *vi, loff_t offset, bool is_register) -+struct map_info { -+ struct map_info *next; -+ struct mm_struct *mm; -+ unsigned long vaddr; -+}; -+ -+static inline struct map_info *free_map_info(struct map_info *info) -+{ -+ struct map_info *next = info->next; -+ kfree(info); -+ return next; -+} -+ -+static struct map_info * -+build_map_info(struct address_space *mapping, loff_t offset, bool is_register) - { -+ unsigned long pgoff = offset >> PAGE_SHIFT; - struct prio_tree_iter iter; - struct vm_area_struct *vma; -- struct vma_info *tmpvi; -- unsigned long pgoff; -- int existing_vma; -- loff_t vaddr; -- -- pgoff = offset >> PAGE_SHIFT; -+ struct map_info *curr = NULL; -+ struct map_info *prev = NULL; -+ struct map_info *info; -+ int more = 0; - -+ again: -+ mutex_lock(&mapping->i_mmap_mutex); - vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { - if (!valid_vma(vma, is_register)) - continue; - -- existing_vma = 0; -- vaddr = vma_address(vma, offset); -- -- list_for_each_entry(tmpvi, head, probe_list) { -- if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) { -- existing_vma = 1; -- break; -- } -+ if (!prev && !more) { -+ /* -+ * Needs GFP_NOWAIT to avoid i_mmap_mutex recursion through -+ * reclaim. This is optimistic, no harm done if it fails. -+ */ -+ prev = kmalloc(sizeof(struct map_info), -+ GFP_NOWAIT | __GFP_NOMEMALLOC | __GFP_NOWARN); -+ if (prev) -+ prev->next = NULL; - } -- -- /* -- * Another vma needs a probe to be installed. However skip -- * installing the probe if the vma is about to be unlinked. -- */ -- if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) { -- vi->mm = vma->vm_mm; -- vi->vaddr = vaddr; -- list_add(&vi->probe_list, head); -- -- return vi; -+ if (!prev) { -+ more++; -+ continue; - } -- } -- -- return NULL; --} - --/* -- * Iterate in the rmap prio tree and find a vma where a probe has not -- * yet been inserted. -- */ --static struct vma_info * --find_next_vma_info(struct address_space *mapping, struct list_head *head, -- loff_t offset, bool is_register) --{ -- struct vma_info *vi, *retvi; -+ if (!atomic_inc_not_zero(&vma->vm_mm->mm_users)) -+ continue; - -- vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL); -- if (!vi) -- return ERR_PTR(-ENOMEM); -+ info = prev; -+ prev = prev->next; -+ info->next = curr; -+ curr = info; - -- mutex_lock(&mapping->i_mmap_mutex); -- retvi = __find_next_vma_info(mapping, head, vi, offset, is_register); -+ info->mm = vma->vm_mm; -+ info->vaddr = offset_to_vaddr(vma, offset); -+ } - mutex_unlock(&mapping->i_mmap_mutex); - -- if (!retvi) -- kfree(vi); -+ if (!more) -+ goto out; -+ -+ prev = curr; -+ while (curr) { -+ mmput(curr->mm); -+ curr = curr->next; -+ } - -- return retvi; -+ do { -+ info = kmalloc(sizeof(struct map_info), GFP_KERNEL); -+ if (!info) { -+ curr = ERR_PTR(-ENOMEM); -+ goto out; -+ } -+ info->next = prev; -+ prev = info; -+ } while (--more); -+ -+ goto again; -+ out: -+ while (prev) -+ prev = free_map_info(prev); -+ return curr; - } - - static int register_for_each_vma(struct uprobe *uprobe, bool is_register) - { -- struct list_head try_list; -- struct vm_area_struct *vma; -- struct address_space *mapping; -- struct vma_info *vi, *tmpvi; -- struct mm_struct *mm; -- loff_t vaddr; -- int ret; -+ struct map_info *info; -+ int err = 0; - -- mapping = uprobe->inode->i_mapping; -- INIT_LIST_HEAD(&try_list); -+ info = build_map_info(uprobe->inode->i_mapping, -+ uprobe->offset, is_register); -+ if (IS_ERR(info)) -+ return PTR_ERR(info); - -- ret = 0; -+ while (info) { -+ struct mm_struct *mm = info->mm; -+ struct vm_area_struct *vma; - -- for (;;) { -- vi = find_next_vma_info(mapping, &try_list, uprobe->offset, is_register); -- if (!vi) -- break; -+ if (err) -+ goto free; - -- if (IS_ERR(vi)) { -- ret = PTR_ERR(vi); -- break; -- } -+ down_write(&mm->mmap_sem); -+ vma = find_vma(mm, info->vaddr); -+ if (!vma || !valid_vma(vma, is_register) || -+ vma->vm_file->f_mapping->host != uprobe->inode) -+ goto unlock; - -- mm = vi->mm; -- down_read(&mm->mmap_sem); -- vma = find_vma(mm, (unsigned long)vi->vaddr); -- if (!vma || !valid_vma(vma, is_register)) { -- list_del(&vi->probe_list); -- kfree(vi); -- up_read(&mm->mmap_sem); -- mmput(mm); -- continue; -- } -- vaddr = vma_address(vma, uprobe->offset); -- if (vma->vm_file->f_mapping->host != uprobe->inode || -- vaddr != vi->vaddr) { -- list_del(&vi->probe_list); -- kfree(vi); -- up_read(&mm->mmap_sem); -- mmput(mm); -- continue; -- } -+ if (vma->vm_start > info->vaddr || -+ vaddr_to_offset(vma, info->vaddr) != uprobe->offset) -+ goto unlock; - - if (is_register) -- ret = install_breakpoint(uprobe, mm, vma, vi->vaddr); -+ err = install_breakpoint(uprobe, mm, vma, info->vaddr); - else -- remove_breakpoint(uprobe, mm, vi->vaddr); -+ remove_breakpoint(uprobe, mm, info->vaddr); - -- up_read(&mm->mmap_sem); -+ unlock: -+ up_write(&mm->mmap_sem); -+ free: - mmput(mm); -- if (is_register) { -- if (ret && ret == -EEXIST) -- ret = 0; -- if (ret) -- break; -- } -- } -- -- list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { -- list_del(&vi->probe_list); -- kfree(vi); -+ info = free_map_info(info); - } - -- return ret; -+ return err; - } - - static int __uprobe_register(struct uprobe *uprobe) -@@ -941,10 +901,12 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * - } - - mutex_unlock(uprobes_hash(inode)); -- put_uprobe(uprobe); -+ if (uprobe) -+ put_uprobe(uprobe); - - return ret; - } -+EXPORT_SYMBOL_GPL(uprobe_register); - - /* - * uprobe_unregister - unregister a already registered probe. -@@ -976,81 +938,81 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume - if (uprobe) - put_uprobe(uprobe); - } -+EXPORT_SYMBOL_GPL(uprobe_unregister); - --/* -- * Of all the nodes that correspond to the given inode, return the node -- * with the least offset. -- */ --static struct rb_node *find_least_offset_node(struct inode *inode) -+static struct rb_node * -+find_node_in_range(struct inode *inode, loff_t min, loff_t max) - { -- struct uprobe u = { .inode = inode, .offset = 0}; - struct rb_node *n = uprobes_tree.rb_node; -- struct rb_node *close_node = NULL; -- struct uprobe *uprobe; -- int match; - - while (n) { -- uprobe = rb_entry(n, struct uprobe, rb_node); -- match = match_uprobe(&u, uprobe); -- -- if (uprobe->inode == inode) -- close_node = n; -- -- if (!match) -- return close_node; -+ struct uprobe *u = rb_entry(n, struct uprobe, rb_node); - -- if (match < 0) -+ if (inode < u->inode) { - n = n->rb_left; -- else -+ } else if (inode > u->inode) { - n = n->rb_right; -+ } else { -+ if (max < u->offset) -+ n = n->rb_left; -+ else if (min > u->offset) -+ n = n->rb_right; -+ else -+ break; -+ } - } - -- return close_node; -+ return n; - } - - /* -- * For a given inode, build a list of probes that need to be inserted. -+ * For a given range in vma, build a list of probes that need to be inserted. - */ --static void build_probe_list(struct inode *inode, struct list_head *head) -+static void build_probe_list(struct inode *inode, -+ struct vm_area_struct *vma, -+ unsigned long start, unsigned long end, -+ struct list_head *head) - { -- struct uprobe *uprobe; -- unsigned long flags; -- struct rb_node *n; -- -- spin_lock_irqsave(&uprobes_treelock, flags); -- -- n = find_least_offset_node(inode); -+ loff_t min, max; -+ struct rb_node *n, *t; -+ struct uprobe *u; - -- for (; n; n = rb_next(n)) { -- uprobe = rb_entry(n, struct uprobe, rb_node); -- if (uprobe->inode != inode) -- break; -+ INIT_LIST_HEAD(head); -+ min = vaddr_to_offset(vma, start); -+ max = min + (end - start) - 1; - -- list_add(&uprobe->pending_list, head); -- atomic_inc(&uprobe->ref); -+ spin_lock(&uprobes_treelock); -+ n = find_node_in_range(inode, min, max); -+ if (n) { -+ for (t = n; t; t = rb_prev(t)) { -+ u = rb_entry(t, struct uprobe, rb_node); -+ if (u->inode != inode || u->offset < min) -+ break; -+ list_add(&u->pending_list, head); -+ atomic_inc(&u->ref); -+ } -+ for (t = n; (t = rb_next(t)); ) { -+ u = rb_entry(t, struct uprobe, rb_node); -+ if (u->inode != inode || u->offset > max) -+ break; -+ list_add(&u->pending_list, head); -+ atomic_inc(&u->ref); -+ } - } -- -- spin_unlock_irqrestore(&uprobes_treelock, flags); -+ spin_unlock(&uprobes_treelock); - } - - /* -- * Called from mmap_region. -- * called with mm->mmap_sem acquired. -- * -- * Return -ve no if we fail to insert probes and we cannot -- * bail-out. -- * Return 0 otherwise. i.e: -+ * Called from mmap_region/vma_adjust with mm->mmap_sem acquired. - * -- * - successful insertion of probes -- * - (or) no possible probes to be inserted. -- * - (or) insertion of probes failed but we can bail-out. -+ * Currently we ignore all errors and always return 0, the callers -+ * can't handle the failure anyway. - */ - int uprobe_mmap(struct vm_area_struct *vma) - { - struct list_head tmp_list; - struct uprobe *uprobe, *u; - struct inode *inode; -- int ret, count; - - if (!atomic_read(&uprobe_events) || !valid_vma(vma, true)) - return 0; -@@ -1059,54 +1021,38 @@ int uprobe_mmap(struct vm_area_struct *vma) - if (!inode) - return 0; - -- INIT_LIST_HEAD(&tmp_list); - mutex_lock(uprobes_mmap_hash(inode)); -- build_probe_list(inode, &tmp_list); -- -- ret = 0; -- count = 0; -+ build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list); - - list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { -- loff_t vaddr; -- -- list_del(&uprobe->pending_list); -- if (!ret) { -- vaddr = vma_address(vma, uprobe->offset); -- -- if (vaddr < vma->vm_start || vaddr >= vma->vm_end) { -- put_uprobe(uprobe); -- continue; -- } -- -- ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); -- -- /* Ignore double add: */ -- if (ret == -EEXIST) { -- ret = 0; -- -- if (!is_swbp_at_addr(vma->vm_mm, vaddr)) -- continue; -- -- /* -- * Unable to insert a breakpoint, but -- * breakpoint lies underneath. Increment the -- * probe count. -- */ -- atomic_inc(&vma->vm_mm->uprobes_state.count); -- } -- -- if (!ret) -- count++; -+ if (!fatal_signal_pending(current)) { -+ unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); -+ install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); - } - put_uprobe(uprobe); - } -- - mutex_unlock(uprobes_mmap_hash(inode)); - -- if (ret) -- atomic_sub(count, &vma->vm_mm->uprobes_state.count); -+ return 0; -+} - -- return ret; -+static bool -+vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long end) -+{ -+ loff_t min, max; -+ struct inode *inode; -+ struct rb_node *n; -+ -+ inode = vma->vm_file->f_mapping->host; -+ -+ min = vaddr_to_offset(vma, start); -+ max = min + (end - start) - 1; -+ -+ spin_lock(&uprobes_treelock); -+ n = find_node_in_range(inode, min, max); -+ spin_unlock(&uprobes_treelock); -+ -+ return !!n; - } - - /* -@@ -1114,41 +1060,18 @@ int uprobe_mmap(struct vm_area_struct *vma) - */ - void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) - { -- struct list_head tmp_list; -- struct uprobe *uprobe, *u; -- struct inode *inode; -- - if (!atomic_read(&uprobe_events) || !valid_vma(vma, false)) - return; - -- if (!atomic_read(&vma->vm_mm->uprobes_state.count)) -+ if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */ - return; - -- inode = vma->vm_file->f_mapping->host; -- if (!inode) -+ if (!test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags) || -+ test_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags)) - return; - -- INIT_LIST_HEAD(&tmp_list); -- mutex_lock(uprobes_mmap_hash(inode)); -- build_probe_list(inode, &tmp_list); -- -- list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { -- loff_t vaddr; -- -- list_del(&uprobe->pending_list); -- vaddr = vma_address(vma, uprobe->offset); -- -- if (vaddr >= start && vaddr < end) { -- /* -- * An unregister could have removed the probe before -- * unmap. So check before we decrement the count. -- */ -- if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1) -- atomic_dec(&vma->vm_mm->uprobes_state.count); -- } -- put_uprobe(uprobe); -- } -- mutex_unlock(uprobes_mmap_hash(inode)); -+ if (vma_has_uprobes(vma, start, end)) -+ set_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags); - } - - /* Slot allocation for XOL */ -@@ -1250,13 +1173,15 @@ void uprobe_clear_state(struct mm_struct *mm) - kfree(area); - } - --/* -- * uprobe_reset_state - Free the area allocated for slots. -- */ --void uprobe_reset_state(struct mm_struct *mm) -+void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) - { -- mm->uprobes_state.xol_area = NULL; -- atomic_set(&mm->uprobes_state.count, 0); -+ newmm->uprobes_state.xol_area = NULL; -+ -+ if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) { -+ set_bit(MMF_HAS_UPROBES, &newmm->flags); -+ /* unconditionally, dup_mmap() skips VM_DONTCOPY vmas */ -+ set_bit(MMF_RECALC_UPROBES, &newmm->flags); -+ } - } - - /* -@@ -1378,9 +1303,6 @@ void uprobe_free_utask(struct task_struct *t) - { - struct uprobe_task *utask = t->utask; - -- if (t->uprobe_srcu_id != -1) -- srcu_read_unlock_raw(&uprobes_srcu, t->uprobe_srcu_id); -- - if (!utask) - return; - -@@ -1398,7 +1320,6 @@ void uprobe_free_utask(struct task_struct *t) - void uprobe_copy_process(struct task_struct *t) - { - t->utask = NULL; -- t->uprobe_srcu_id = -1; - } - - /* -@@ -1417,7 +1338,6 @@ static struct uprobe_task *add_utask(void) - if (unlikely(!utask)) - return NULL; - -- utask->active_uprobe = NULL; - current->utask = utask; - return utask; - } -@@ -1479,41 +1399,93 @@ static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) - return false; - } - -+static void mmf_recalc_uprobes(struct mm_struct *mm) -+{ -+ struct vm_area_struct *vma; -+ -+ for (vma = mm->mmap; vma; vma = vma->vm_next) { -+ if (!valid_vma(vma, false)) -+ continue; -+ /* -+ * This is not strictly accurate, we can race with -+ * uprobe_unregister() and see the already removed -+ * uprobe if delete_uprobe() was not yet called. -+ */ -+ if (vma_has_uprobes(vma, vma->vm_start, vma->vm_end)) -+ return; -+ } -+ -+ clear_bit(MMF_HAS_UPROBES, &mm->flags); -+} -+ -+static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) -+{ -+ struct mm_struct *mm = current->mm; -+ struct uprobe *uprobe = NULL; -+ struct vm_area_struct *vma; -+ -+ down_read(&mm->mmap_sem); -+ vma = find_vma(mm, bp_vaddr); -+ if (vma && vma->vm_start <= bp_vaddr) { -+ if (valid_vma(vma, false)) { -+ struct inode *inode = vma->vm_file->f_mapping->host; -+ loff_t offset = vaddr_to_offset(vma, bp_vaddr); -+ -+ uprobe = find_uprobe(inode, offset); -+ } -+ -+ if (!uprobe) -+ *is_swbp = is_swbp_at_addr(mm, bp_vaddr); -+ } else { -+ *is_swbp = -EFAULT; -+ } -+ -+ if (!uprobe && test_and_clear_bit(MMF_RECALC_UPROBES, &mm->flags)) -+ mmf_recalc_uprobes(mm); -+ up_read(&mm->mmap_sem); -+ -+ return uprobe; -+} -+ -+void __weak arch_uprobe_enable_step(struct arch_uprobe *arch) -+{ -+ user_enable_single_step(current); -+} -+ -+void __weak arch_uprobe_disable_step(struct arch_uprobe *arch) -+{ -+ user_disable_single_step(current); -+} -+ - /* - * Run handler and ask thread to singlestep. - * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. - */ - static void handle_swbp(struct pt_regs *regs) - { -- struct vm_area_struct *vma; - struct uprobe_task *utask; - struct uprobe *uprobe; -- struct mm_struct *mm; - unsigned long bp_vaddr; -+ int uninitialized_var(is_swbp); - -- uprobe = NULL; - bp_vaddr = uprobe_get_swbp_addr(regs); -- mm = current->mm; -- down_read(&mm->mmap_sem); -- vma = find_vma(mm, bp_vaddr); -- -- if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) { -- struct inode *inode; -- loff_t offset; -- -- inode = vma->vm_file->f_mapping->host; -- offset = bp_vaddr - vma->vm_start; -- offset += (vma->vm_pgoff << PAGE_SHIFT); -- uprobe = find_uprobe(inode, offset); -- } -- -- srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id); -- current->uprobe_srcu_id = -1; -- up_read(&mm->mmap_sem); -+ uprobe = find_active_uprobe(bp_vaddr, &is_swbp); - - if (!uprobe) { -- /* No matching uprobe; signal SIGTRAP. */ -- send_sig(SIGTRAP, current, 0); -+ if (is_swbp > 0) { -+ /* No matching uprobe; signal SIGTRAP. */ -+ send_sig(SIGTRAP, current, 0); -+ } else { -+ /* -+ * Either we raced with uprobe_unregister() or we can't -+ * access this memory. The latter is only possible if -+ * another thread plays with our ->mm. In both cases -+ * we can simply restart. If this vma was unmapped we -+ * can pretend this insn was not executed yet and get -+ * the (correct) SIGSEGV after restart. -+ */ -+ instruction_pointer_set(regs, bp_vaddr); -+ } - return; - } - -@@ -1531,7 +1503,7 @@ static void handle_swbp(struct pt_regs *regs) - - utask->state = UTASK_SSTEP; - if (!pre_ssout(uprobe, regs, bp_vaddr)) { -- user_enable_single_step(current); -+ arch_uprobe_enable_step(&uprobe->arch); - return; - } - -@@ -1540,17 +1512,15 @@ cleanup_ret: - utask->active_uprobe = NULL; - utask->state = UTASK_RUNNING; - } -- if (uprobe) { -- if (!(uprobe->flags & UPROBE_SKIP_SSTEP)) -+ if (!(uprobe->flags & UPROBE_SKIP_SSTEP)) - -- /* -- * cannot singlestep; cannot skip instruction; -- * re-execute the instruction. -- */ -- instruction_pointer_set(regs, bp_vaddr); -+ /* -+ * cannot singlestep; cannot skip instruction; -+ * re-execute the instruction. -+ */ -+ instruction_pointer_set(regs, bp_vaddr); - -- put_uprobe(uprobe); -- } -+ put_uprobe(uprobe); - } - - /* -@@ -1569,10 +1539,10 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) - else - WARN_ON_ONCE(1); - -+ arch_uprobe_disable_step(&uprobe->arch); - put_uprobe(uprobe); - utask->active_uprobe = NULL; - utask->state = UTASK_RUNNING; -- user_disable_single_step(current); - xol_free_insn_slot(current); - - spin_lock_irq(¤t->sighand->siglock); -@@ -1611,8 +1581,7 @@ int uprobe_pre_sstep_notifier(struct pt_regs *regs) - { - struct uprobe_task *utask; - -- if (!current->mm || !atomic_read(¤t->mm->uprobes_state.count)) -- /* task is currently not uprobed */ -+ if (!current->mm || !test_bit(MMF_HAS_UPROBES, ¤t->mm->flags)) - return 0; - - utask = current->utask; -@@ -1620,7 +1589,6 @@ int uprobe_pre_sstep_notifier(struct pt_regs *regs) - utask->state = UTASK_BP_HIT; - - set_thread_flag(TIF_UPROBE); -- current->uprobe_srcu_id = srcu_read_lock_raw(&uprobes_srcu); - - return 1; - } -@@ -1655,7 +1623,6 @@ static int __init init_uprobes(void) - mutex_init(&uprobes_mutex[i]); - mutex_init(&uprobes_mmap_mutex[i]); - } -- init_srcu_struct(&uprobes_srcu); - - return register_die_notifier(&uprobe_exception_nb); - } -diff --git a/kernel/fork.c b/kernel/fork.c -index 7a1d634..5d0137c 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -355,6 +355,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) - - down_write(&oldmm->mmap_sem); - flush_cache_dup_mm(oldmm); -+ uprobe_dup_mmap(oldmm, mm); - /* - * Not linked in yet - no deadlock potential: - */ -@@ -843,8 +841,6 @@ struct mm_struct *dup_mm(struct task_struct *tsk) - #ifdef CONFIG_TRANSPARENT_HUGEPAGE - mm->pmd_huge_pte = NULL; - #endif -- uprobe_reset_state(mm); -- - if (!mm_init(mm, tsk)) - goto fail_nomem; - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index a232bb5..764fcd1 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -33,6 +33,12 @@ static int ptrace_trapping_sleep_fn(void *flags) - } - - /* -+ * This is declared in linux/regset.h and defined in machine-dependent -+ * code. We put the export here to ensure no machine forgets it. -+ */ -+EXPORT_SYMBOL_GPL(task_user_regset_view); -+ -+/* - * ptrace a task: make the debugger its new parent and - * move it to the ptrace list. - * -diff --git a/mm/mmap.c b/mm/mmap.c -index 3edfcdf..f25fd3f 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -2345,9 +2344,6 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) - security_vm_enough_memory_mm(mm, vma_pages(vma))) - return -ENOMEM; - -- if (vma->vm_file && uprobe_mmap(vma)) -- return -EINVAL; -- - vma_link(mm, vma, prev, rb_link, rb_parent); - return 0; - } -@@ -2418,9 +2414,6 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, - if (new_vma->vm_file) { - get_file(new_vma->vm_file); - -- if (uprobe_mmap(new_vma)) -- goto out_free_mempol; -- - if (vma->vm_flags & VM_EXECUTABLE) - added_exe_file_vma(mm); - } -_______________________________________________ -kernel mailing list -kernel@lists.fedoraproject.org -https://admin.fedoraproject.org/mailman/listinfo/kernel