diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 4db22f6491e0..85a4a033bae7 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -445,3 +445,6 @@ object doesn't exist. It's remote/distributed ones that might care... [mandatory] FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate() in your dentry operations instead. +-- +[mandatory] + vfs_readdir() is gone; switch to iterate_dir() instead diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index b81fca90f7fe..c7539eced626 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -42,6 +42,8 @@ Currently, these files are in /proc/sys/vm: - min_slab_ratio - min_unmapped_ratio - mmap_min_addr +- mmap_rnd_bits +- mmap_rnd_compat_bits - nr_hugepages - nr_overcommit_hugepages - nr_trim_pages (only if CONFIG_MMU=n) @@ -455,6 +457,33 @@ against future potential kernel bugs. ============================================================== +mmap_rnd_bits: + +This value can be used to select the number of bits to use to +determine the random offset to the base address of vma regions +resulting from mmap allocations on architectures which support +tuning address space randomization. This value will be bounded +by the architecture's minimum and maximum supported values. + +This value can be changed after boot using the +/proc/sys/vm/mmap_rnd_bits tunable + +============================================================== + +mmap_rnd_compat_bits: + +This value can be used to select the number of bits to use to +determine the random offset to the base address of vma regions +resulting from mmap allocations for applications run in +compatibility mode on architectures which support tuning address +space randomization. This value will be bounded by the +architecture's minimum and maximum supported values. + +This value can be changed after boot using the +/proc/sys/vm/mmap_rnd_compat_bits tunable + +============================================================== + nr_hugepages Change the minimum size of the hugepage pool. diff --git a/arch/Kconfig b/arch/Kconfig index dd6811e8f80b..0a70b38dab1d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -454,6 +454,74 @@ config HAVE_UNDERSCORE_SYMBOL_PREFIX Some architectures generate an _ in front of C symbols; things like module loading and assembly files need to know about this. +config HAVE_ARCH_MMAP_RND_BITS + bool + help + An arch should select this symbol if it supports setting a variable + number of bits for use in establishing the base address for mmap + allocations, has MMU enabled and provides values for both: + - ARCH_MMAP_RND_BITS_MIN + - ARCH_MMAP_RND_BITS_MAX + +config ARCH_MMAP_RND_BITS_MIN + int + +config ARCH_MMAP_RND_BITS_MAX + int + +config ARCH_MMAP_RND_BITS_DEFAULT + int + +config ARCH_MMAP_RND_BITS + int "Number of bits to use for ASLR of mmap base address" if EXPERT + range ARCH_MMAP_RND_BITS_MIN ARCH_MMAP_RND_BITS_MAX + default ARCH_MMAP_RND_BITS_DEFAULT if ARCH_MMAP_RND_BITS_DEFAULT + default ARCH_MMAP_RND_BITS_MIN + depends on HAVE_ARCH_MMAP_RND_BITS + help + This value can be used to select the number of bits to use to + determine the random offset to the base address of vma regions + resulting from mmap allocations. This value will be bounded + by the architecture's minimum and maximum supported values. + + This value can be changed after boot using the + /proc/sys/vm/mmap_rnd_bits tunable + +config HAVE_ARCH_MMAP_RND_COMPAT_BITS + bool + help + An arch should select this symbol if it supports running applications + in compatibility mode, supports setting a variable number of bits for + use in establishing the base address for mmap allocations, has MMU + enabled and provides values for both: + - ARCH_MMAP_RND_COMPAT_BITS_MIN + - ARCH_MMAP_RND_COMPAT_BITS_MAX + +config ARCH_MMAP_RND_COMPAT_BITS_MIN + int + +config ARCH_MMAP_RND_COMPAT_BITS_MAX + int + +config ARCH_MMAP_RND_COMPAT_BITS_DEFAULT + int + +config ARCH_MMAP_RND_COMPAT_BITS + int "Number of bits to use for ASLR of mmap base address for compatible applications" if EXPERT + range ARCH_MMAP_RND_COMPAT_BITS_MIN ARCH_MMAP_RND_COMPAT_BITS_MAX + default ARCH_MMAP_RND_COMPAT_BITS_DEFAULT if ARCH_MMAP_RND_COMPAT_BITS_DEFAULT + default ARCH_MMAP_RND_COMPAT_BITS_MIN + depends on HAVE_ARCH_MMAP_RND_COMPAT_BITS + help + This value can be used to select the number of bits to use to + determine the random offset to the base address of vma regions + resulting from mmap allocations for compatible applications This + value will be bounded by the architecture's minimum and maximum + supported values. + + This value can be changed after boot using the + /proc/sys/vm/mmap_rnd_compat_bits tunable + # # ABI hall of shame # diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index b9e37ad6fa19..1402fcc11c2c 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -96,6 +96,7 @@ struct osf_dirent { }; struct osf_dirent_callback { + struct dir_context ctx; struct osf_dirent __user *dirent; long __user *basep; unsigned int count; @@ -146,17 +147,17 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, { int error; struct fd arg = fdget(fd); - struct osf_dirent_callback buf; + struct osf_dirent_callback buf = { + .ctx.actor = osf_filldir, + .dirent = dirent, + .basep = basep, + .count = count + }; if (!arg.file) return -EBADF; - buf.dirent = dirent; - buf.basep = basep; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(arg.file, osf_filldir, &buf); + error = iterate_dir(arg.file, &buf.ctx); if (error >= 0) error = buf.error; if (count != buf.count) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 468c72c23ae6..f636eab6bf6e 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -23,6 +23,7 @@ config ARM select HARDIRQS_SW_RESEND select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_KGDB + select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_BPF_JIT @@ -301,6 +302,14 @@ config MMU Select if you want MMU-based virtualised addressing space support by paged memory management. If unsure, say 'Y'. +config ARCH_MMAP_RND_BITS_MIN + default 8 + +config ARCH_MMAP_RND_BITS_MAX + default 14 if PAGE_OFFSET=0x40000000 + default 15 if PAGE_OFFSET=0x80000000 + default 16 + # # The "ARM system type" choice list is ordered alphabetically by option # text. Please add new entries in the option alphabetic order. diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index b577c340b806..c77658b4d164 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -14,9 +14,8 @@ ifneq ($(MACHINE),) include $(srctree)/$(MACHINE)/Makefile.boot endif -include $(srctree)/arch/arm/boot/dts/Makefile -include $(srctree)/arch/arm/boot/dts/Makefile +include $(srctree)/arch/arm/boot/dts/qcom/Makefile ifneq ($(DTSSUBDIR),) DTSSUBDIR_INCS=$(foreach DIR, $(DTSSUBDIR), $(addsuffix /Makefile, $(addprefix $(srctree)/arch/arm/boot/dts/, $(DIR)))) include $(DTSSUBDIR_INCS) diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 6dea4038a440..921b535435cf 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -208,12 +208,6 @@ dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ wm8850-w70v2.dtb dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb -DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES)) -ifneq ($(DTB_NAMES),) -DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) -else -DTB_LIST := $(dtb-y) -endif targets += dtbs targets += $(DTB_LIST) diff --git a/arch/arm/configs/msm8909-1gb-LMT-perf_defconfig b/arch/arm/configs/msm8909-1gb-LMT-perf_defconfig index 20d76faeb7df..826eae9b7a47 100644 --- a/arch/arm/configs/msm8909-1gb-LMT-perf_defconfig +++ b/arch/arm/configs/msm8909-1gb-LMT-perf_defconfig @@ -574,3 +574,4 @@ CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm/configs/msm8909-1gb-perf_defconfig b/arch/arm/configs/msm8909-1gb-perf_defconfig index 81da900acffb..ff920d4b114b 100644 --- a/arch/arm/configs/msm8909-1gb-perf_defconfig +++ b/arch/arm/configs/msm8909-1gb-perf_defconfig @@ -58,6 +58,7 @@ CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_HIGHMEM=y CONFIG_CC_STACKPROTECTOR_REGULAR=y @@ -314,6 +315,7 @@ CONFIG_SENSORS_LTR553=y CONFIG_SENSORS_MPU6050=y CONFIG_SENSORS_MMC3416X=y CONFIG_SENSORS_AKM8963=y +CONFIG_SENSORS_AKM09911=y CONFIG_SENSORS_BMA2X2=y CONFIG_SENSORS_AP3426=y CONFIG_SENSORS_HALL=y @@ -342,6 +344,7 @@ CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB358_CHARGER=y CONFIG_SMB135X_CHARGER=y CONFIG_SMB1360_CHARGER_FG=y CONFIG_BATTERY_BCL=y @@ -566,7 +569,7 @@ CONFIG_QMI_ENCDEC=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_RADIO_IRIS=y -CONFIG_RADIO_IRIS_TRANSPORT=m +CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=n CONFIG_DEVFREQ_SPDM=y @@ -575,3 +578,4 @@ CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm/configs/msm8909-1gb_defconfig b/arch/arm/configs/msm8909-1gb_defconfig index 8ff4053bae58..72b5171e6f2d 100644 --- a/arch/arm/configs/msm8909-1gb_defconfig +++ b/arch/arm/configs/msm8909-1gb_defconfig @@ -61,6 +61,7 @@ CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_HIGHMEM=y CONFIG_CC_STACKPROTECTOR_REGULAR=y @@ -321,6 +322,7 @@ CONFIG_SENSORS_LTR553=y CONFIG_SENSORS_MPU6050=y CONFIG_SENSORS_MMC3416X=y CONFIG_SENSORS_AKM8963=y +CONFIG_SENSORS_AKM09911=y CONFIG_SENSORS_BMA2X2=y CONFIG_SENSORS_AP3426=y CONFIG_SENSORS_HALL=y @@ -349,6 +351,7 @@ CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB358_CHARGER=y CONFIG_SMB135X_CHARGER=y CONFIG_SMB1360_CHARGER_FG=y CONFIG_BATTERY_BCL=y @@ -605,7 +608,7 @@ CONFIG_QMI_ENCDEC=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_RADIO_IRIS=y -CONFIG_RADIO_IRIS_TRANSPORT=m +CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=n CONFIG_DEVFREQ_SPDM=y @@ -614,3 +617,4 @@ CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 5a967771449c..3153802e7dfc 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -328,6 +328,7 @@ CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB358_CHARGER=y CONFIG_SMB135X_CHARGER=y CONFIG_SMB1360_CHARGER_FG=y CONFIG_BATTERY_BCL=y @@ -557,3 +558,4 @@ CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm/configs/msm8909-y560-u23_defconfig b/arch/arm/configs/msm8909-y560-u23_defconfig index b42c658a389f..a545e0659973 100644 --- a/arch/arm/configs/msm8909-y560-u23_defconfig +++ b/arch/arm/configs/msm8909-y560-u23_defconfig @@ -205,6 +205,10 @@ CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y CONFIG_MODULES_USE_ELF_REL=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_CLONE_BACKWARDS=y CONFIG_OLD_SIGSUSPEND3=y CONFIG_OLD_SIGACTION=y @@ -663,6 +667,7 @@ CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_INET_UDP_DIAG is not set +CONFIG_INET_DIAG_DESTROY=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" @@ -842,7 +847,7 @@ CONFIG_NF_CONNTRACK_PROC_COMPAT=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y -# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_RPFILTER=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y @@ -879,7 +884,7 @@ CONFIG_IP6_NF_IPTABLES=y # CONFIG_IP6_NF_MATCH_HL is not set # CONFIG_IP6_NF_MATCH_IPV6HEADER is not set # CONFIG_IP6_NF_MATCH_MH is not set -# CONFIG_IP6_NF_MATCH_RPFILTER is not set +CONFIG_IP6_NF_MATCH_RPFILTER=y # CONFIG_IP6_NF_MATCH_RT is not set # CONFIG_IP6_NF_TARGET_HL is not set CONFIG_IP6_NF_FILTER=y @@ -3438,6 +3443,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_ECRYPT_FS is not set +CONFIG_SDCARD_FS=y # CONFIG_HFS_FS is not set # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set diff --git a/arch/arm/configs/msm8909-y560_defconfig b/arch/arm/configs/msm8909-y560_defconfig index e636a65f42d0..f5c5e7ad9f89 100644 --- a/arch/arm/configs/msm8909-y560_defconfig +++ b/arch/arm/configs/msm8909-y560_defconfig @@ -205,6 +205,10 @@ CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_MOD_ARCH_SPECIFIC=y CONFIG_MODULES_USE_ELF_REL=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS=16 CONFIG_CLONE_BACKWARDS=y CONFIG_OLD_SIGSUSPEND3=y CONFIG_OLD_SIGACTION=y @@ -663,6 +667,7 @@ CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_INET_UDP_DIAG is not set +CONFIG_INET_DIAG_DESTROY=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" @@ -842,7 +847,7 @@ CONFIG_NF_CONNTRACK_PROC_COMPAT=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y -# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_RPFILTER=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y @@ -879,7 +884,7 @@ CONFIG_IP6_NF_IPTABLES=y # CONFIG_IP6_NF_MATCH_HL is not set # CONFIG_IP6_NF_MATCH_IPV6HEADER is not set # CONFIG_IP6_NF_MATCH_MH is not set -# CONFIG_IP6_NF_MATCH_RPFILTER is not set +CONFIG_IP6_NF_MATCH_RPFILTER=y # CONFIG_IP6_NF_MATCH_RT is not set # CONFIG_IP6_NF_TARGET_HL is not set CONFIG_IP6_NF_FILTER=y @@ -3438,6 +3443,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_ECRYPT_FS is not set +CONFIG_SDCARD_FS=y # CONFIG_HFS_FS is not set # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 78f3b8b505c3..26e974a245e9 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -62,6 +62,7 @@ CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_KSM=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_CP_ACCESS=y @@ -342,6 +343,7 @@ CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB358_CHARGER=y CONFIG_SMB135X_CHARGER=y CONFIG_SMB1360_CHARGER_FG=y CONFIG_BATTERY_BCL=y @@ -598,7 +600,7 @@ CONFIG_QMI_ENCDEC=y CONFIG_MSM_BUSPM_DEV=m CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_RADIO_IRIS=y -CONFIG_RADIO_IRIS_TRANSPORT=m +CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=n CONFIG_DEVFREQ_SPDM=y @@ -607,3 +609,4 @@ CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig old mode 100644 new mode 100755 similarity index 77% rename from arch/arm64/configs/msm-perf_defconfig rename to arch/arm/configs/msm8909w-perf_defconfig index 74a023742d7e..f9146bbc427b --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -1,4 +1,3 @@ -CONFIG_LOCALVERSION="-perf" CONFIG_SYSVIPC=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -7,6 +6,7 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y CONFIG_RESOURCE_COUNTERS=y @@ -27,52 +27,78 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_PANIC_TIMEOUT=5 CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MSM=y -CONFIG_ARCH_MSM8916=y +CONFIG_ARCH_MSM8909=y CONFIG_LEDS_MSM_GPIO_FLASH=y +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_CPU_HAS_L2_PMU=y +CONFIG_MSM_SMCMOD=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_MSM_AVTIMER=y +CONFIG_MSM_BUS_SCALING=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MSM_DLOAD_MODE=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_SENSORS_ADSP=y +CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_XPU_ERR_FATAL=y +CONFIG_STRICT_MEMORY_RWX=y CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y -CONFIG_ARMV7_COMPAT=y +CONFIG_AEABI=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_HIGHMEM=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_PROCESS_RECLAIM=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=0 -CONFIG_PM_RUNTIME=y -CONFIG_SUSPEND_TIME=y -CONFIG_CPU_FREQ=y +CONFIG_CP_ACCESS=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_RUNTIME=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM=y CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y CONFIG_INET=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y -CONFIG_INET_AH=y -CONFIG_INET_ESP=y -CONFIG_INET_XFRM_TUNNEL=y CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_IPCOMP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set CONFIG_IPV6=y @@ -87,7 +113,12 @@ CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_NETLINK_LOG=y CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CT_PROTO_DCCP=y @@ -104,25 +135,26 @@ CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CONNTRACK_TFTP=y CONFIG_NF_CT_NETLINK=y CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y -CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y CONFIG_NETFILTER_XT_MATCH_DSCP=y -CONFIG_NETFILTER_XT_MATCH_ESP=y CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y CONFIG_NETFILTER_XT_MATCH_HELPER=y CONFIG_NETFILTER_XT_MATCH_IPRANGE=y @@ -143,14 +175,22 @@ CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_MATCH_ESP=y CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_NF_DEFRAG_IPV6=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y CONFIG_NF_NAT_IPV4=y +CONFIG_NF_NAT_IPV6=y CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_NETMAP=y CONFIG_IP_NF_TARGET_REDIRECT=y @@ -163,17 +203,19 @@ CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_MASQUERADE=y CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y CONFIG_L2TP_IP=y CONFIG_L2TP_ETH=y -CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_PRIO=y @@ -188,28 +230,41 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y +CONFIG_BT=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y -CONFIG_BT=y +CONFIG_SOCKEV_NLMCAST=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=y CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_HIDP=y -CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_NL80211_TESTMODE=y CONFIG_CFG80211_INTERNAL_REGDB=y -CONFIG_RFKILL=y CONFIG_NFC_QNCI=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_CMA=y +CONFIG_CMA_SIZE_MBYTES=8 +CONFIG_MTD=y +CONFIG_MTD_TESTS=m +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_LAZYECCSTATS=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y -CONFIG_APDS9930=y CONFIG_QSEECOM=y CONFIG_SCSI=y CONFIG_SCSI_TGT=y @@ -227,10 +282,10 @@ CONFIG_DM_REQ_CRYPT=y CONFIG_DM_VERITY=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_MII=y +CONFIG_IFB=y CONFIG_TUN=y +CONFIG_KS8851=y CONFIG_MSM_RMNET_BAM=y -CONFIG_PHYLIB=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -243,6 +298,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y CONFIG_WCNSS_CORE=y CONFIG_WCNSS_CORE_PRONTO=y CONFIG_WCNSS_MEM_PRE_ALLOC=y @@ -250,31 +306,34 @@ CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y CONFIG_TOUCHSCREEN_ATMEL_MXT=y CONFIG_TOUCHSCREEN_FT5X06=y -CONFIG_TOUCHSCREEN_MSTAR21XX=y +CONFIG_TOUCHSCREEN_FT5X06_GESTURE=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y -CONFIG_TOUCHSCREEN_BU21150=y -CONFIG_INPUT_MT_WRAPPER=y +CONFIG_TOUCHSCREEN_IT7260_I2C=y CONFIG_INPUT_MISC=y -CONFIG_INPUT_HBTP_INPUT=y -CONFIG_SENSORS_MPU6050=y -CONFIG_SENSORS_LIS3DH=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m +CONFIG_SENSORS=y +CONFIG_APDS9930=y +CONFIG_SENSORS_LTR553=y +CONFIG_SENSORS_MPU6050=y CONFIG_SENSORS_MMC3416X=y -CONFIG_SENSORS_AKM09911=y CONFIG_SENSORS_AKM8963=y CONFIG_SENSORS_BMA2X2=y -# CONFIG_SERIO_I8042 is not set -# CONFIG_VT is not set +CONFIG_SENSORS_AP3426=y +CONFIG_SENSORS_HALL=y +#CONFIG_SERIAL_MSM_HSL is not set +#CONFIG_SERIAL_MSM_HSL_CONSOLE is not set CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y @@ -283,6 +342,7 @@ CONFIG_MSM_SMD_PKT=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y +CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_DMADEVICES=y CONFIG_HAS_DMA=y @@ -293,19 +353,20 @@ CONFIG_SPI_SPIDEV=m CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB=y CONFIG_MSM_QPNP_INT=y -CONFIG_USE_PINCTRL_IRQ=y -CONFIG_PINCTRL_MSM_TLMM=y +CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_SUPPLY=y CONFIG_SMB135X_CHARGER=y CONFIG_SMB1360_CHARGER_FG=y CONFIG_BATTERY_BCL=y CONFIG_QPNP_VM_BMS=y CONFIG_QPNP_LINEAR_CHARGER=y +CONFIG_POWER_RESET=y CONFIG_POWER_RESET_MSM=y -CONFIG_MSM_DLOAD_MODE=y -CONFIG_MSM_PM=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_QPNP_ADC_CURRENT=y +CONFIG_SENSORS_QPNP_CURRENT_MONITOR=y CONFIG_THERMAL=y CONFIG_THERMAL_TSENS8974=y CONFIG_THERMAL_MONITOR=y @@ -314,9 +375,7 @@ CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_FAN53555=y CONFIG_REGULATOR_MEM_ACC=y -CONFIG_REGULATOR_ONSEMI_NCP6335D=y CONFIG_REGULATOR_TPS65132=y CONFIG_REGULATOR_STUB=y CONFIG_REGULATOR_RPM_SMD=y @@ -325,56 +384,50 @@ CONFIG_REGULATOR_SPM=y CONFIG_REGULATOR_CPR=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEOBUF2_MSM_MEM=y -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y CONFIG_MSMB_CAMERA=y CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CPP=y -CONFIG_MSM_CCI=y +CONFIG_GC0310=y CONFIG_MSM_CSI30_HEADER=y CONFIG_MSM_CSIPHY=y CONFIG_MSM_CSID=y CONFIG_MSM_EEPROM=y CONFIG_MSM_ISPIF=y -CONFIG_HI256=y -CONFIG_MT9M114=y -CONFIG_OV5645=y -CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y -CONFIG_MSMB_JPEG=y CONFIG_MSM_VIDC_V4L2=y -CONFIG_RADIO_IRIS=y -CONFIG_RADIO_IRIS_TRANSPORT=m CONFIG_MSM_KGSL=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y CONFIG_FB=y +CONFIG_FB_VIRTUAL=y CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_MDP3=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_SOC=y -CONFIG_SND_SOC_MSM8X16=y +CONFIG_SND_SOC_MSM8909=y CONFIG_UHID=y CONFIG_HID_APPLE=y CONFIG_HID_ELECOM=y -CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MULTITOUCH=y -CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y -CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_EHSET=y CONFIG_USB_EHCI_MSM=y -CONFIG_USB_EHCI_MSM_UICC=y -CONFIG_USB_ICE40_HCD=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_ICE40_HCD=m CONFIG_USB_ACM=y CONFIG_USB_CCID_BRIDGE=y CONFIG_USB_STORAGE=y @@ -386,23 +439,23 @@ CONFIG_USB_STORAGE_SDDR09=y CONFIG_USB_STORAGE_SDDR55=y CONFIG_USB_STORAGE_JUMPSHOT=y CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_SERIAL=y CONFIG_USB_SERIAL_CSVT=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_PHY=y -CONFIG_USB_MSM_SSPHY_QMP=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_CI13XXX_MSM=y -CONFIG_USB_DWC3_MSM=y CONFIG_USB_G_ANDROID=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_CLKGATE=y +CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_TEST=m @@ -411,6 +464,12 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_LEDS_TRIGGERS=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_AW2013=y +CONFIG_LEDS_TRIGGERS=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y @@ -423,39 +482,44 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_ASHMEM=y CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_TIMED_GPIO=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ANDROID_INTF_ALARM_DEV=y CONFIG_ONESHOT_SYNC=y CONFIG_ION=y CONFIG_ION_MSM=y CONFIG_SPS=y +CONFIG_USB_BAM=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_POWER_ON=y CONFIG_QPNP_VIBRATOR=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_TRIGGERS=y CONFIG_QPNP_REVID=y -CONFIG_QPNP_COINCELL=y -CONFIG_MSM_AVTIMER=y -CONFIG_IPA=y -CONFIG_RMNET_IPA=y -CONFIG_MSM_BUS_SCALING=y -CONFIG_BUS_TOPOLOGY_ADHOC=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MSM_IOMMU_V1=y +CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING=y CONFIG_PWM=y CONFIG_PWM_QPNP=y -CONFIG_SENSORS=y -CONFIG_SENSORS_SSC=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_FUSE=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_CTI_SAVE_DISABLE=y +CONFIG_CORESIGHT_TMC=y +CONFIG_CORESIGHT_TPIU=y +CONFIG_CORESIGHT_FUNNEL=y +CONFIG_CORESIGHT_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_MOBICORE_SUPPORT=m +CONFIG_MOBICORE_API=m CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_SMD=y -CONFIG_MSM_RPM_SMD=y -CONFIG_MSM_RPM_LOG=y -CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_SMEM=y CONFIG_MSM_SMEM_LOGGING=y @@ -463,18 +527,13 @@ CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y -CONFIG_MSM_ADSP_LOADER=y CONFIG_MSM_MEMORY_DUMP_V2=y -# CONFIG_MSM_DEBUG_LAR_UNLOCK is not set -CONFIG_MSM_WATCHDOG_V2=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_COMMON_LOG=y CONFIG_MSM_SYSMON_COMM=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y -CONFIG_MSM_OCMEM=y -CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y CONFIG_MSM_SCM=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_EXT2_FS=y @@ -482,6 +541,7 @@ CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y CONFIG_EXT4_FS_SECURITY=y CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y @@ -492,39 +552,43 @@ CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_ON_RECURSIVE_FAULT=y -# CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y -# CONFIG_DEBUG_PREEMPT is not set -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_MEMORY_INIT=y CONFIG_IPC_LOGGING=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_XTS=y -CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_ARC4=y CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y -CONFIG_ARM64_CRYPTO=y -CONFIG_CRYPTO_SHA1_ARM64_CE=y -CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE_CCM=y -CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_SHA256=y CONFIG_QMI_ENCDEC=y +CONFIG_MSM_BUSPM_DEV=m +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_RADIO_IRIS=y +CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_MSM_PERFORMANCE=y -CONFIG_MOBICORE_SUPPORT=m -CONFIG_MOBICORE_API=m +CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=n +CONFIG_DEVFREQ_SPDM=y +CONFIG_SPDM_SCM=y CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +CONFIG_DEBUG_LL=y +CONFIG_EARLY_PRINTK=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig new file mode 100755 index 000000000000..58771456096b --- /dev/null +++ b/arch/arm/configs/msm8909w_defconfig @@ -0,0 +1,633 @@ +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_AUDIT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_MSM=y +CONFIG_ARCH_MSM8909=y +CONFIG_LEDS_MSM_GPIO_FLASH=y +# CONFIG_MSM_STACKED_MEMORY is not set +CONFIG_CPU_HAS_L2_PMU=y +CONFIG_MSM_SMCMOD=y +CONFIG_MSM_TZ_LOG=y +CONFIG_MSM_DIRECT_SCLK_ACCESS=y +CONFIG_MSM_AVTIMER=y +CONFIG_MSM_BUS_SCALING=y +CONFIG_BUS_TOPOLOGY_ADHOC=y +CONFIG_MSM_WATCHDOG_V2=y +CONFIG_MSM_DLOAD_MODE=y +CONFIG_MSM_ADSP_LOADER=y +CONFIG_SENSORS_ADSP=y +CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_XPU_ERR_FATAL=y +CONFIG_STRICT_MEMORY_RWX=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_HIGHMEM=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_PROCESS_RECLAIM=y +CONFIG_CP_ACCESS=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_RUNTIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NF_NAT_IPV6=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_MASQUERADE=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_BT=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_NFC_QNCI=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_CMA=y +CONFIG_CMA_SIZE_MBYTES=8 +CONFIG_CMA_DEBUG=y +CONFIG_MTD=y +CONFIG_MTD_TESTS=m +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_LAZYECCSTATS=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_QSEECOM=y +CONFIG_SCSI=y +CONFIG_SCSI_TGT=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_VERITY=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_IFB=y +CONFIG_TUN=y +CONFIG_KS8851=y +CONFIG_MSM_RMNET_BAM=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +CONFIG_TOUCHSCREEN_FT5X06=y +CONFIG_TOUCHSCREEN_FT5X06_GESTURE=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y +CONFIG_TOUCHSCREEN_IT7260_I2C=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=m +CONFIG_SENSORS=y +CONFIG_APDS9930=y +CONFIG_SENSORS_LTR553=y +CONFIG_SENSORS_MPU6050=y +CONFIG_SENSORS_MMC3416X=y +CONFIG_SENSORS_AKM8963=y +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_AP3426=y +CONFIG_SENSORS_HALL=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_DIAG_CHAR=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM=y +CONFIG_MSM_SMD_PKT=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SLIMBUS=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_DMADEVICES=y +CONFIG_HAS_DMA=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +CONFIG_MSM_QPNP_INT=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_SUPPLY=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1360_CHARGER_FG=y +CONFIG_BATTERY_BCL=y +CONFIG_QPNP_VM_BMS=y +CONFIG_QPNP_LINEAR_CHARGER=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_MSM=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_SENSORS_QPNP_ADC_CURRENT=y +CONFIG_SENSORS_QPNP_CURRENT_MONITOR=y +CONFIG_THERMAL=y +CONFIG_THERMAL_TSENS8974=y +CONFIG_THERMAL_MONITOR=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_SUPPLY_LM_MONITOR=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEOBUF2_MSM_MEM=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_MSMB_CAMERA=y +CONFIG_MSM_CAMERA_SENSOR=y +CONFIG_MSM_CSI30_HEADER=y +CONFIG_MSM_CSIPHY=y +CONFIG_MSM_CSID=y +CONFIG_MSM_EEPROM=y +CONFIG_MSM_ISPIF=y +CONFIG_GC0310=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_KGSL=y +CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y +CONFIG_FB=y +CONFIG_FB_VIRTUAL=y +CONFIG_FB_MSM=y +# CONFIG_FB_MSM_BACKLIGHT is not set +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_MDP3=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_MSM8909=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MSM=y +CONFIG_USB_EHCI_EHSET=y +CONFIG_USB_ICE40_HCD=m +CONFIG_USB_ACM=y +CONFIG_USB_CCID_BRIDGE=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CSVT=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_CI13XXX_MSM=y +CONFIG_USB_G_ANDROID=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_TEST=m +CONFIG_MMC_BLOCK_TEST=m +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_AW2013=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ZSMALLOC=y +CONFIG_ZRAM=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_ONESHOT_SYNC=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_SPS=y +CONFIG_USB_BAM=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_POWER_ON=y +CONFIG_QPNP_VIBRATOR=y +CONFIG_QPNP_REVID=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_IOMMU_V1=y +CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_MOBICORE_SUPPORT=m +CONFIG_MOBICORE_API=m +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_FUSE=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TMC=y +CONFIG_CORESIGHT_TPIU=y +CONFIG_CORESIGHT_FUNNEL=y +CONFIG_CORESIGHT_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_ETM=y +CONFIG_CORESIGHT_MODEM_ETM=y +CONFIG_CORESIGHT_WCN_ETM=y +CONFIG_CORESIGHT_RPM_ETM=y +CONFIG_CORESIGHT_QPDI=y +CONFIG_CORESIGHT_DBGUI=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_MEMORY_DUMP_V2=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_COMMON_LOG=y +CONFIG_MSM_SYSMON_COMM=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_MSM_SCM=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PAGE_OWNER=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_HIGHMEM=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_LIST=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_MSM_RTB=y +CONFIG_MSM_RTB_SEPARATE_CPUS=y +CONFIG_IPC_LOGGING=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_DEBUG_USER=y +CONFIG_FREE_PAGES_RDONLY=y +CONFIG_KERNEL_TEXT_RDONLY=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_KEYS=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_SHA256=y +CONFIG_QMI_ENCDEC=y +CONFIG_MSM_BUSPM_DEV=m +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_RADIO_IRIS=y +CONFIG_RADIO_IRIS_TRANSPORT=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_PERFORMANCE_HOTPLUG_ON=n +CONFIG_DEVFREQ_SPDM=y +CONFIG_SPDM_SCM=y +CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +CONFIG_DEBUG_LL=y +CONFIG_EARLY_PRINTK=y diff --git a/arch/arm/configs/msm8916-perf_defconfig b/arch/arm/configs/msm8916-perf_defconfig index 090fb484eaea..62cb39187718 100644 --- a/arch/arm/configs/msm8916-perf_defconfig +++ b/arch/arm/configs/msm8916-perf_defconfig @@ -53,6 +53,8 @@ CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES="msm8916-cdp msm8916-mtp msm8939-mtp-smb1360" CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_HIGHMEM=y CONFIG_CP_ACCESS=y @@ -132,6 +134,7 @@ CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -363,7 +366,7 @@ CONFIG_OV5645=y CONFIG_MSMB_JPEG=y CONFIG_MSM_VIDC_V4L2=y CONFIG_RADIO_IRIS=y -CONFIG_RADIO_IRIS_TRANSPORT=m +CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_MSM_KGSL=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y CONFIG_FB=y @@ -541,3 +544,4 @@ CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm/configs/msm8916_defconfig b/arch/arm/configs/msm8916_defconfig index 8b8c08e893b1..56c56dab1574 100755 --- a/arch/arm/configs/msm8916_defconfig +++ b/arch/arm/configs/msm8916_defconfig @@ -56,6 +56,8 @@ CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES="msm8916-cdp msm8916-mtp msm8939-mtp-smb1360" CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_HIGHMEM=y CONFIG_CP_ACCESS=y @@ -135,6 +137,7 @@ CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -368,7 +371,7 @@ CONFIG_OV5645=y CONFIG_MSMB_JPEG=y CONFIG_MSM_VIDC_V4L2=y CONFIG_RADIO_IRIS=y -CONFIG_RADIO_IRIS_TRANSPORT=m +CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_MSM_KGSL=y CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y CONFIG_FB=y @@ -586,3 +589,4 @@ CONFIG_SECCOMP=y CONFIG_SECCOMP_FILTER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index 8f9d1cf505dd..dae47dfc8dae 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -173,10 +173,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm) { unsigned long random_factor = 0UL; - /* 8 bits of randomness in 20 address space bits */ if ((current->flags & PF_RANDOMIZE) && !(current->personality & ADDR_NO_RANDOMIZE)) - random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT; + random_factor = (get_random_long() & ((1UL << mmap_rnd_bits) - 1)) << PAGE_SHIFT; if (mmap_is_legacy()) { mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 2a8c9d44a782..d580d171c84b 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -121,6 +121,7 @@ CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_TARGET_TEE=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y @@ -576,3 +577,4 @@ CONFIG_MSM_PERFORMANCE=y CONFIG_MOBICORE_SUPPORT=m CONFIG_MOBICORE_API=m CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_UID_CPUTIME=y diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index 9be924f08f34..7f463465b4e8 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -147,7 +147,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm) unsigned long random_factor = 0UL; if (current->flags & PF_RANDOMIZE) { - random_factor = get_random_int(); + random_factor = get_random_long(); random_factor = random_factor << PAGE_SHIFT; if (TASK_IS_32BIT_ADDR) random_factor &= 0xfffffful; @@ -166,7 +166,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm) static inline unsigned long brk_rnd(void) { - unsigned long rnd = get_random_int(); + unsigned long rnd = get_random_long(); rnd = rnd << PAGE_SHIFT; /* 8MB for 32bit, 256MB for 64bit */ diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 838b479a42c4..88d0962de65a 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -60,6 +60,7 @@ struct hpux_dirent { }; struct getdents_callback { + struct dir_context ctx; struct hpux_dirent __user *current_dir; struct hpux_dirent __user *previous; int count; @@ -110,24 +111,23 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i { struct fd arg; struct hpux_dirent __user * lastdirent; - struct getdents_callback buf; + struct getdents_callback buf = { + .ctx.actor = filldir, + .current_dir = dirent, + .count = count + }; int error; arg = fdget(fd); if (!arg.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(arg.file, filldir, &buf); + error = iterate_dir(arg.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; if (lastdirent) { - if (put_user(arg.file->f_pos, &lastdirent->d_off)) + if (put_user(buf.ctx.pos, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d55357ee9028..47936dc128a1 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1450,9 +1450,9 @@ static inline unsigned long brk_rnd(void) /* 8MB for 32bit, 1GB for 64bit */ if (is_32bit_task()) - rnd = (long)(get_random_int() % (1<<(23-PAGE_SHIFT))); + rnd = (get_random_long() % (1UL<<(23-PAGE_SHIFT))); else - rnd = (long)(get_random_int() % (1<<(30-PAGE_SHIFT))); + rnd = (get_random_long() % (1UL<<(30-PAGE_SHIFT))); return rnd << PAGE_SHIFT; } diff --git a/arch/powerpc/mm/mmap_64.c b/arch/powerpc/mm/mmap_64.c index cb8bdbe4972f..bde8ed0c6ddd 100644 --- a/arch/powerpc/mm/mmap_64.c +++ b/arch/powerpc/mm/mmap_64.c @@ -60,9 +60,9 @@ static unsigned long mmap_rnd(void) if (current->flags & PF_RANDOMIZE) { /* 8MB for 32bit, 1GB for 64bit */ if (is_32bit_task()) - rnd = (long)(get_random_int() % (1<<(23-PAGE_SHIFT))); + rnd = get_random_long() % (1<<(23-PAGE_SHIFT)); else - rnd = (long)(get_random_int() % (1<<(30-PAGE_SHIFT))); + rnd = get_random_long() % (1UL<<(30-PAGE_SHIFT)); } return rnd << PAGE_SHIFT; } diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 0fd7c67f1a96..ea80c0b003fd 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -265,7 +265,7 @@ static unsigned long mmap_rnd(void) unsigned long rnd = 0UL; if (current->flags & PF_RANDOMIZE) { - unsigned long val = get_random_int(); + unsigned long val = get_random_long(); if (test_thread_flag(TIF_32BIT)) rnd = (val % (1UL << (23UL-PAGE_SHIFT))); else diff --git a/block/blk-core.c b/block/blk-core.c index 33ad0c9aabc5..8707a434e098 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1189,6 +1189,8 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio, if (unlikely(!rq)) return ERR_PTR(-ENOMEM); + blk_rq_set_block_pc(rq); + for_each_bio(bio) { struct bio *bounce_bio = bio; int ret; @@ -1205,6 +1207,22 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio, } EXPORT_SYMBOL(blk_make_request); +/** + * blk_rq_set_block_pc - initialize a requeest to type BLOCK_PC + * @rq: request to be initialized + * + */ +void blk_rq_set_block_pc(struct request *rq) +{ + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->__data_len = 0; + rq->__sector = (sector_t) -1; + rq->bio = rq->biotail = NULL; + memset(rq->__cmd, 0, sizeof(rq->__cmd)); + rq->cmd = rq->__cmd; +} +EXPORT_SYMBOL(blk_rq_set_block_pc); + /** * blk_requeue_request - put a request back on queue * @q: request queue where request should be inserted diff --git a/block/bsg.c b/block/bsg.c index 76801e57f556..0ed26bce6655 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -196,7 +196,6 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, * fill in request structure */ rq->cmd_len = hdr->request_len; - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = msecs_to_jiffies(hdr->timeout); if (!rq->timeout) @@ -273,6 +272,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm, rq = blk_get_request(q, rw, GFP_KERNEL); if (!rq) return ERR_PTR(-ENOMEM); + blk_rq_set_block_pc(rq); + ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm); if (ret) goto out; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 9bfbb51aa75e..3a2530221914 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -236,7 +236,6 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, * fill in request structure */ rq->cmd_len = hdr->cmd_len; - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = msecs_to_jiffies(hdr->timeout); if (!rq->timeout) @@ -317,6 +316,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) return -ENOMEM; + blk_rq_set_block_pc(rq); if (blk_fill_sghdr_rq(q, rq, hdr, mode)) { blk_put_request(rq); @@ -515,7 +515,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; - rq->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(rq); blk_execute_rq(q, disk, rq, 0); @@ -547,7 +547,7 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, int err; rq = blk_get_request(q, WRITE, __GFP_WAIT); - rq->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(rq); rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; rq->cmd[4] = data; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index f5d0ea11d9fd..caddb5dba3e0 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -712,6 +712,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, __GFP_WAIT); + blk_rq_set_block_pc(rq); if (cgc->buflen) { if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT)) @@ -722,7 +723,6 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); rq->timeout = 60*HZ; - rq->cmd_type = REQ_TYPE_BLOCK_PC; if (cgc->quiet) rq->cmd_flags |= REQ_QUIET; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 8a3aff724d98..1ca0772c713f 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2165,6 +2165,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ret = -ENOMEM; break; } + blk_rq_set_block_pc(rq); ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL); if (ret) { @@ -2184,7 +2185,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, rq->cmd[9] = 0xf8; rq->cmd_len = 12; - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = 60 * HZ; bio = rq->bio; diff --git a/drivers/char/random.c b/drivers/char/random.c index 29e447d93167..b72bcd2af443 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1502,6 +1502,28 @@ unsigned int get_random_int(void) } EXPORT_SYMBOL(get_random_int); +/* + * Same as get_random_int(), but returns unsigned long. + */ +unsigned long get_random_long(void) +{ + __u32 *hash; + unsigned long ret; + + if (arch_get_random_long(&ret)) + return ret; + + hash = get_cpu_var(get_random_int_hash); + + hash[0] += current->pid + jiffies + get_cycles(); + md5_transform(hash, random_int_secret); + ret = *(unsigned long *)hash; + put_cpu_var(get_random_int_hash); + + return ret; +} +EXPORT_SYMBOL(get_random_long); + /* * randomize_range() returns a start address such that * diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index d49acc41a775..d3d32b433916 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -176,6 +176,16 @@ static inline u32 get_hfi_codec(enum hal_video_codec hal_codec) return hfi_codec; } +static void create_pkt_enable(void *pkt, u32 type, bool enable) +{ + u32 *pkt_header = pkt; + u32 *pkt_type = &pkt_header[0]; + struct hfi_enable *hfi_enable = (struct hfi_enable *)&pkt_header[1]; + + *pkt_type = type; + hfi_enable->enable = enable; +} + int create_pkt_cmd_sys_init(struct hfi_cmd_sys_init_packet *pkt, u32 arch_type) { @@ -483,6 +493,19 @@ static int get_hfi_extradata_index(enum hal_extradata_id index) case HAL_EXTRADATA_METADATA_MBI: ret = HFI_PROPERTY_PARAM_VENC_MBI_DUMPING; break; + case HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI: + ret = + HFI_PROPERTY_PARAM_VDEC_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA; + break; + case HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI: + ret = HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA; + break; + case HAL_EXTRADATA_VUI_DISPLAY_INFO: + ret = HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA; + break; + case HAL_EXTRADATA_VPX_COLORSPACE: + ret = HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA; + break; default: dprintk(VIDC_WARN, "Extradata index not found: %d\n", index); break; @@ -1898,6 +1921,34 @@ int create_pkt_cmd_session_set_property( sizeof(struct hfi_hybrid_hierp); break; } + case HAL_PARAM_VENC_VIDEO_SIGNAL_INFO: + { + struct hal_video_signal_info *hal = pdata; + struct hfi_video_signal_metadata *signal_info = + (struct hfi_video_signal_metadata *) + &pkt->rg_property_data[1]; + + signal_info->enable = true; + signal_info->video_format = MSM_VIDC_NTSC; + signal_info->video_full_range = hal->full_range; + signal_info->color_description = MSM_VIDC_COLOR_DESC_PRESENT; + signal_info->color_primaries = hal->color_space; + signal_info->transfer_characteristics = hal->transfer_chars; + signal_info->matrix_coeffs = hal->matrix_coeffs; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO; + pkt->size += sizeof(u32) + sizeof(*signal_info); + break; + } + case HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32) + sizeof(struct hfi_enable); + break; + } /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ case HAL_CONFIG_BUFFER_REQUIREMENTS: case HAL_CONFIG_PRIORITY: diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 8c2b8731c243..1a9cd222af86 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -50,27 +50,6 @@ static const char *const mpeg_video_output_order[] = { "Decode Order", NULL }; -static const char *const mpeg_video_vidc_extradata[] = { - "Extradata none", - "Extradata MB Quantization", - "Extradata Interlace Video", - "Extradata VC1 Framedisp", - "Extradata VC1 Seqdisp", - "Extradata timestamp", - "Extradata S3D Frame Packing", - "Extradata Frame Rate", - "Extradata Panscan Window", - "Extradata Recovery point SEI", - "Extradata Closed Caption UD", - "Extradata AFD UD", - "Extradata Multislice info", - "Extradata number of concealed MB", - "Extradata metadata filler", - "Extradata input crop", - "Extradata digital zoom", - "Extradata aspect ratio", - "Extradata mpeg2 seqdisp", -}; static const char *const mpeg_vidc_video_alloc_mode_type[] = { "Buffer Allocation Static", "Buffer Allocation Ring Buffer", @@ -246,7 +225,7 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { .name = "Extradata Type", .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE, - .maximum = V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO, + .maximum = V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE, .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE, .menu_skip_mask = ~( (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) | @@ -268,7 +247,12 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { (1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) | (1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA) | (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) | - (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO) + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI) | + (1 << + V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE) ), .qmenu = mpeg_video_vidc_extradata, .step = 0, diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index f36a152656a6..4ec50e3b1d4c 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -152,29 +152,6 @@ static const char *const vp8_profile_level[] = { "2.0", "3.0", }; - -static const char *const mpeg_video_vidc_extradata[] = { - "Extradata none", - "Extradata MB Quantization", - "Extradata Interlace Video", - "Extradata VC1 Framedisp", - "Extradata VC1 Seqdisp", - "Extradata timestamp", - "Extradata S3D Frame Packing", - "Extradata Frame Rate", - "Extradata Panscan Window", - "Extradata Recovery point SEI", - "Extradata Closed Caption UD", - "Extradata AFD UD", - "Extradata Multislice info", - "Extradata number of concealed MB", - "Extradata metadata filler", - "Extradata input crop", - "Extradata digital zoom", - "Extradata aspect ratio", - "Extradata macroblock metadata", -}; - static const char *const perf_level[] = { "Nominal", "Performance", @@ -1083,6 +1060,55 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .step = 1, .qmenu = NULL, }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE, + .name = "Set Color space", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_BT709_5, + .maximum = MSM_VIDC_BT2020, + .default_value = MSM_VIDC_BT601_6_625, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE, + .name = "Set Color space range", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_ENABLE, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS, + .name = "Set Color space transfer characterstics", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_TRANSFER_BT709_5, + .maximum = MSM_VIDC_TRANSFER_BT_2020_12, + .default_value = MSM_VIDC_TRANSFER_601_6_625, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS, + .name = "Set Color space matrix coefficients", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_MATRIX_BT_709_5, + .maximum = MSM_VIDC_MATRIX_BT_2020_CONST, + .default_value = MSM_VIDC_MATRIX_601_6_625, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC, + .name = "Set VPE Color space conversion coefficients", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_DISABLE, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_DISABLE, + .step = 1, + }, + }; #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls) @@ -1163,6 +1189,8 @@ static struct msm_vidc_format venc_formats[] = { }, }; +static int msm_venc_set_csc(struct msm_vidc_inst *inst); + static int msm_venc_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, unsigned int *num_buffers, @@ -1837,6 +1865,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) struct hal_hybrid_hierp hyb_hierp; u32 hier_p_layers = 0, hier_b_layers = 0; struct hal_venc_perf_mode venc_mode; + struct hal_video_signal_info signal_info = {0}; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); @@ -2347,12 +2376,34 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: { struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs; + bool is_cont_intra_supported = false; + air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS); air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF); cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS); - property_id = - HAL_PARAM_VENC_INTRA_REFRESH; + is_cont_intra_supported = + (inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_H264) || + (inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_HEVC); + + if (is_cont_intra_supported) { + if (air_mbs || air_ref || cir_mbs) + enable.enable = true; + else + enable.enable = false; + + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED, &enable); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set constrained intra\n"); + rc = -EINVAL; + break; + } + } + + property_id = HAL_PARAM_VENC_INTRA_REFRESH; intra_refresh.mode = ctrl->val; intra_refresh.air_mbs = air_mbs->val; @@ -2697,6 +2748,71 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE: property_id = 0; break; + case V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE: + { + signal_info.color_space = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE: + { + signal_info.full_range = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS: + { + signal_info.transfer_chars = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS: + { + signal_info.matrix_coeffs = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC: + if (ctrl->val == V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE) { + rc = msm_venc_set_csc(inst); + if (rc) + dprintk(VIDC_ERR, "fail to set csc: %d\n", rc); + } + break; default: dprintk(VIDC_ERR, "Unsupported index: %x\n", ctrl->id); rc = -ENOTSUPP; @@ -3094,7 +3210,7 @@ int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a) return rc; } -int msm_venc_set_csc(struct msm_vidc_inst *inst) +static int msm_venc_set_csc(struct msm_vidc_inst *inst) { int rc = 0; int count = 0; @@ -3137,10 +3253,6 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) } hdev = inst->core->device; - if (msm_vidc_vpe_csc_601_to_709) { - msm_venc_set_csc(inst); - } - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index dc76227a1749..d6860109f2fb 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -51,6 +51,39 @@ #define IS_SYS_CMD_VALID(cmd) (((cmd) >= SYS_MSG_START) && \ ((cmd) <= SYS_MSG_END)) +const char *const mpeg_video_vidc_extradata[] = { + "Extradata none", + "Extradata MB Quantization", + "Extradata Interlace Video", + "Extradata VC1 Framedisp", + "Extradata VC1 Seqdisp", + "Extradata timestamp", + "Extradata S3D Frame Packing", + "Extradata Frame Rate", + "Extradata Panscan Window", + "Extradata Recovery point SEI", + "Extradata Multislice info", + "Extradata number of concealed MB", + "Extradata metadata filler", + "Extradata input crop", + "Extradata digital zoom", + "Extradata aspect ratio", + "Extradata mpeg2 seqdisp", + "Extradata stream userdata", + "Extradata frame QP", + "Extradata frame bits info", + "Extradata LTR", + "Extradata macroblock metadata", + "Extradata VQZip SEI", + "Extradata YUV Stats", + "Extradata ROI QP", + "Extradata output crop", + "Extradata display colour SEI", + "Extradata light level SEI", + "Extradata display VUI", + "Extradata vpx color space", +}; + struct getprop_buf { struct list_head list; void *data; @@ -82,7 +115,6 @@ static inline bool is_non_realtime_session(struct msm_vidc_inst *inst) rc = v4l2_g_ctrl(&inst->ctrl_handler, &ctrl); return (!rc && ctrl.value); } - enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst) { if (inst->session_type == MSM_VIDC_DECODER) { @@ -4284,6 +4316,18 @@ enum hal_extradata_id msm_comm_get_hal_extradata_index( case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI: ret = HAL_EXTRADATA_METADATA_MBI; break; + case V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI: + ret = HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI; + break; + case V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI: + ret = HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI; + break; + case V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY: + ret = HAL_EXTRADATA_VUI_DISPLAY_INFO; + break; + case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE: + ret = HAL_EXTRADATA_VPX_COLORSPACE; + break; default: dprintk(VIDC_WARN, "Extradata not found: %d\n", index); break; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 890153b93311..d9cb73a86bcf 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -18,6 +18,9 @@ struct vb2_buf_entry { struct list_head list; struct vb2_buffer *vb; }; + +extern const char *const mpeg_video_vidc_extradata[]; + struct msm_vidc_core *get_vidc_core(int core_id); const struct msm_vidc_format *msm_comm_get_pixel_fmt_index( const struct msm_vidc_format fmt[], int size, int index, int fmt_type); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index b0bda5de403f..509ea440cf6e 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -23,7 +23,6 @@ int msm_fw_debug_mode = 0x1; int msm_fw_low_power_mode = 0x1; int msm_vidc_hw_rsp_timeout = 1000; u32 msm_fw_coverage = 0x0; -int msm_vidc_vpe_csc_601_to_709 = 0x0; int msm_vidc_dcvs_mode = 0x1; int msm_vidc_sys_idle_indicator = 0x0; u32 msm_vidc_firmware_unload_delay = 15000; @@ -183,11 +182,6 @@ struct dentry *msm_vidc_debugfs_init_drv(void) dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); goto failed_create_dir; } - if (!debugfs_create_bool("enable_vpe_csc_601_709", S_IRUGO | S_IWUSR, - dir, &msm_vidc_vpe_csc_601_to_709)) { - dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); - goto failed_create_dir; - } if (!debugfs_create_bool("sys_idle_indicator", S_IRUGO | S_IWUSR, dir, &msm_vidc_sys_idle_indicator)) { dprintk(VIDC_ERR, diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index 6199c1516f08..073985edc97b 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -86,6 +86,7 @@ #define HFI_EXTRADATA_STREAM_USERDATA 0x0000000E #define HFI_EXTRADATA_FRAME_QP 0x0000000F #define HFI_EXTRADATA_FRAME_BITS_INFO 0x00000010 +#define HFI_EXTRADATA_VPX_COLORSPACE 0x00000014 #define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000 #define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001 #define HFI_EXTRADATA_INDEX 0x7F100002 @@ -217,6 +218,14 @@ struct hfi_extradata_header { (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x019) #define HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD \ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01A) +#define HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01B) +#define HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001D) +#define HFI_PROPERTY_PARAM_VDEC_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001E) +#define HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001F) #define HFI_PROPERTY_CONFIG_VDEC_OX_START \ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000) diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index c92e179ae628..323c4380e59c 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -114,6 +114,10 @@ enum hal_extradata_id { HAL_EXTRADATA_DIGITAL_ZOOM, HAL_EXTRADATA_LTR_INFO, HAL_EXTRADATA_METADATA_MBI, + HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI, + HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI, + HAL_EXTRADATA_VUI_DISPLAY_INFO, + HAL_EXTRADATA_VPX_COLORSPACE, }; enum hal_property { @@ -216,6 +220,8 @@ enum hal_property { HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS, HAL_PARAM_VDEC_NON_SECURE_OUTPUT2, HAL_PARAM_VENC_HIER_P_HYBRID_MODE, + HAL_PARAM_VENC_VIDEO_SIGNAL_INFO, + HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED, }; enum hal_domain { @@ -946,6 +952,13 @@ struct hal_vpe_color_space_conversion { u32 csc_limit[HAL_MAX_LIMIT_COEFFS]; }; +struct hal_video_signal_info { + u32 color_space; + u32 transfer_chars; + u32 matrix_coeffs; + bool full_range; +}; + enum vidc_resource_id { VIDC_RESOURCE_OCMEM = 0x00000001, VIDC_UNUSED_RESORUCE = 0x10000000, diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index e6b58a098673..13ed39410a66 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -338,7 +338,7 @@ struct hfi_buffer_info { (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B) #define HFI_PROPERTY_PARAM_VENC_LTRMODE \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C) -#define HFI_PROPERTY_PARAM_VENC_VIDEO_FULL_RANGE \ +#define HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D) #define HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E) @@ -358,6 +358,8 @@ struct hfi_buffer_info { (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x028) #define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x029) +#define HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02B) #define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02C) #define HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE \ @@ -626,6 +628,16 @@ struct hfi_frame_size { u32 height; }; +struct hfi_video_signal_metadata { + u32 enable; + u32 video_format; + u32 video_full_range; + u32 color_description; + u32 color_primaries; + u32 transfer_characteristics; + u32 matrix_coeffs; +}; + struct hfi_h264_vui_timing_info { u32 enable; u32 fixed_frame_rate; diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c index 07cd5f8b03c6..231c70b7905f 100644 --- a/drivers/platform/msm/mhi/mhi_sys.c +++ b/drivers/platform/msm/mhi/mhi_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -187,22 +187,6 @@ static const struct file_operations mhi_dbgfs_ev_fops = { .write = NULL, }; -static ssize_t mhi_dbgfs_trigger_msi(struct file *fp, const char __user *buf, - size_t count, loff_t *offp) -{ - u32 msi_nr = 0; - void *irq_ctxt = &((mhi_devices.device_list[0]).pcie_device->dev); - if (copy_from_user(&msi_nr, buf, sizeof(msi_nr))) - return -ENOMEM; - mhi_msi_handlr(msi_nr, irq_ctxt); - return 0; -} - -static const struct file_operations mhi_dbgfs_trigger_msi_fops = { - .read = NULL, - .write = mhi_dbgfs_trigger_msi, -}; - static ssize_t mhi_dbgfs_state_read(struct file *fp, char __user *buf, size_t count, loff_t *offp) { @@ -311,7 +295,6 @@ int mhi_init_debugfs(struct mhi_device_ctxt *mhi_dev_ctxt) { struct dentry *mhi_chan_stats; struct dentry *mhi_state_stats; - struct dentry *mhi_msi_trigger; struct dentry *mhi_ev_stats; mhi_dev_ctxt->mhi_parent_folder = debugfs_create_dir("mhi", NULL); @@ -340,21 +323,12 @@ int mhi_init_debugfs(struct mhi_device_ctxt *mhi_dev_ctxt) &mhi_dbgfs_state_fops); if (mhi_state_stats == NULL) goto clean_ev_stats; - mhi_msi_trigger = debugfs_create_file("mhi_msi_trigger", - 0444, - mhi_dev_ctxt->mhi_parent_folder, - mhi_dev_ctxt, - &mhi_dbgfs_trigger_msi_fops); - if (mhi_msi_trigger == NULL) - goto clean_state; mhi_dev_ctxt->chan_info = kmalloc(MHI_LOG_SIZE, GFP_KERNEL); if (mhi_dev_ctxt->chan_info == NULL) goto clean_all; return 0; clean_all: - debugfs_remove(mhi_msi_trigger); -clean_state: debugfs_remove(mhi_state_stats); clean_ev_stats: debugfs_remove(mhi_ev_stats); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 68adb8955d2d..28bf7fb7e175 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -120,6 +120,7 @@ static struct request *get_alua_req(struct scsi_device *sdev, "%s: blk_get_request failed\n", __func__); return NULL; } + blk_rq_set_block_pc(rq); if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { blk_put_request(rq); @@ -128,7 +129,6 @@ static struct request *get_alua_req(struct scsi_device *sdev, return NULL; } - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; rq->retries = ALUA_FAILOVER_RETRIES; diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index f94fcda1285d..d24eb0b8039c 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -280,6 +280,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, return NULL; } + blk_rq_set_block_pc(rq); rq->cmd_len = COMMAND_SIZE(cmd); rq->cmd[0] = cmd; @@ -304,7 +305,6 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, break; } - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; rq->timeout = CLARIION_TIMEOUT; diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 084062bb8ee9..e9d9fea9e272 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -120,7 +120,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) if (!req) return SCSI_DH_RES_TEMP_UNAVAIL; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); @@ -250,7 +250,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h) if (!req) return SCSI_DH_RES_TEMP_UNAVAIL; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(START_STOP); diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index d661fcda1932..310928fc646a 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -279,6 +279,7 @@ static struct request *get_rdac_req(struct scsi_device *sdev, "get_rdac_req: blk_get_request failed.\n"); return NULL; } + blk_rq_set_block_pc(rq); if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { blk_put_request(rq); @@ -287,7 +288,6 @@ static struct request *get_rdac_req(struct scsi_device *sdev, return NULL; } - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; rq->retries = RDAC_RETRIES; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index aa66361ed44b..11bd87eaf01c 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -1570,6 +1570,7 @@ static struct request *_make_request(struct request_queue *q, bool has_write, if (unlikely(!req)) return ERR_PTR(-ENOMEM); + blk_rq_set_block_pc(req); return req; } } @@ -1590,7 +1591,6 @@ static int _init_blk_request(struct osd_request *or, } or->request = req; - req->cmd_type = REQ_TYPE_BLOCK_PC; req->cmd_flags |= REQ_QUIET; req->timeout = or->timeout; @@ -1608,7 +1608,7 @@ static int _init_blk_request(struct osd_request *or, ret = PTR_ERR(req); goto out; } - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); or->in.req = or->request->next_rq = req; } } else if (has_in) diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 21883a2d6324..0727ea7cc387 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -365,7 +365,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, if (!req) return DRIVER_ERROR << 24; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_QUIET; SRpnt->bio = NULL; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 5ba69ea8eb92..65046b21ee46 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1652,6 +1652,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) */ req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); + blk_rq_set_block_pc(req); + req->cmd[0] = ALLOW_MEDIUM_REMOVAL; req->cmd[1] = 0; req->cmd[2] = 0; @@ -1661,7 +1663,6 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) req->cmd_len = COMMAND_SIZE(req->cmd[0]); - req->cmd_type = REQ_TYPE_BLOCK_PC; req->cmd_flags |= REQ_QUIET; req->timeout = 10 * HZ; req->retries = 5; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index dc1c2f4520f2..973bca48f85b 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -238,6 +238,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); if (!req) return ret; + blk_rq_set_block_pc(req); if (bufflen && blk_rq_map_kern(sdev->request_queue, req, buffer, bufflen, __GFP_WAIT)) @@ -249,7 +250,6 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req->sense_len = 0; req->retries = retries; req->timeout = timeout; - req->cmd_type = REQ_TYPE_BLOCK_PC; req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT; /* diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 847e9f89b6cf..2cb295f02e0b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -7,9 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2005 Douglas Gilbert - * - * Modified 19-JAN-1998 Richard Gooch Devfs support + * Copyright (C) 1998 - 2014 Douglas Gilbert * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,11 +16,11 @@ * */ -static int sg_version_num = 30534; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.34" +static int sg_version_num = 30536; /* 2 digits for each component */ +#define SG_VERSION_STR "3.5.36" /* - * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: + * D. P. Gilbert (dgilbert@interlog.com), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First * the kernel/module needs to be built with CONFIG_SCSI_LOGGING * (otherwise the macros compile to empty statements). @@ -64,7 +62,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20061027"; +static char *sg_version_date = "20140603"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -74,6 +72,12 @@ static void sg_proc_cleanup(void); #define SG_MAX_DEVS 32768 +/* SG_MAX_CDB_SIZE should be 260 (spc4r37 section 3.1.30) however the type + * of sg_io_hdr::cmd_len can only represent 255. All SCSI commands greater + * than 16 bytes are "variable length" whose length is a multiple of 4 + */ +#define SG_MAX_CDB_SIZE 252 + /* * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d) * Then when using 32 bit integers x * m may overflow during the calculation. @@ -161,7 +165,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ char low_dma; /* as in parent but possibly overridden to 1 */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ - char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ + unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ char mmap_called; /* 0 -> mmap() never called on this fd */ struct kref f_ref; @@ -566,7 +570,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) Sg_request *srp; struct sg_header old_hdr; sg_io_hdr_t *hp; - unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned char cmnd[SG_MAX_CDB_SIZE]; if (unlikely(segment_eq(get_fs(), KERNEL_DS))) return -EINVAL; @@ -601,12 +605,6 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) buf += SZ_SG_HEADER; __get_user(opcode, buf); if (sfp->next_cmd_len > 0) { - if (sfp->next_cmd_len > MAX_COMMAND_SIZE) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n")); - sfp->next_cmd_len = 0; - sg_remove_request(sfp, srp); - return -EIO; - } cmd_size = sfp->next_cmd_len; sfp->next_cmd_len = 0; /* reset so only this write() effected */ } else { @@ -679,7 +677,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, int k; Sg_request *srp; sg_io_hdr_t *hp; - unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned char cmnd[SG_MAX_CDB_SIZE]; int timeout; unsigned long ul_timeout; @@ -986,6 +984,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) result = get_user(val, ip); if (result) return result; + if (val > SG_MAX_CDB_SIZE) + return -ENOMEM; sfp->next_cmd_len = (val > 0) ? val : 0; return 0; case SG_GET_VERSION_NUM: @@ -1654,18 +1654,29 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) struct request_queue *q = sfp->parentdp->device->request_queue; struct rq_map_data *md, map_data; int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ; + unsigned char *long_cmdp = NULL; SCSI_LOG_TIMEOUT(4, printk(KERN_INFO "sg_start_req: dxfer_len=%d\n", dxfer_len)); + if (hp->cmd_len > BLK_MAX_CDB) { + long_cmdp = kzalloc(hp->cmd_len, GFP_KERNEL); + if (!long_cmdp) + return -ENOMEM; + } + rq = blk_get_request(q, rw, GFP_ATOMIC); - if (!rq) + if (!rq) { + kfree(long_cmdp); return -ENOMEM; + } - memcpy(rq->cmd, cmd, hp->cmd_len); + blk_rq_set_block_pc(rq); + if (hp->cmd_len > BLK_MAX_CDB) + rq->cmd = long_cmdp; + memcpy(rq->cmd, cmd, hp->cmd_len); rq->cmd_len = hp->cmd_len; - rq->cmd_type = REQ_TYPE_BLOCK_PC; srp->rq = rq; rq->end_io_data = srp; @@ -1751,6 +1762,8 @@ static int sg_finish_rem_req(Sg_request * srp) if (srp->bio) ret = blk_rq_unmap_user(srp->bio); + if (srp->rq->cmd != srp->rq->__cmd) + kfree(srp->rq->cmd); blk_put_request(srp->rq); } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index fa9811200c9d..882b31c54922 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -484,7 +484,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, if (!req) return DRIVER_ERROR << 24; - req->cmd_type = REQ_TYPE_BLOCK_PC; + blk_rq_set_block_pc(req); req->cmd_flags |= REQ_QUIET; mdata->null_mapped = 1; diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index d298b803aceb..64ea1ef71e85 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2015,2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,6 +44,7 @@ #define SMEM_IMAGE_VERSION_OEM_OFFSET 96 #define SMEM_IMAGE_VERSION_PARTITION_APPS 10 +static DECLARE_RWSEM(current_image_rwsem); enum { HW_PLATFORM_UNKNOWN = 0, HW_PLATFORM_SURF = 1, @@ -785,7 +786,9 @@ msm_get_image_version(struct device *dev, __func__); return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown"); } + down_read(¤t_image_rwsem); string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_image_rwsem); return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s\n", string_address); } @@ -798,15 +801,20 @@ msm_set_image_version(struct device *dev, { char *store_address; - if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) + down_read(¤t_image_rwsem); + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) { + up_read(¤t_image_rwsem); return count; + } store_address = socinfo_get_image_version_base_address(); if (IS_ERR_OR_NULL(store_address)) { pr_err("%s : Failed to get image version base address", __func__); + up_read(¤t_image_rwsem); return count; } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_image_rwsem); snprintf(store_address, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s", buf); return count; } @@ -825,7 +833,9 @@ msm_get_image_variant(struct device *dev, return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "Unknown"); } + down_read(¤t_image_rwsem); string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_image_rwsem); string_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET; return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s\n", string_address); @@ -839,15 +849,20 @@ msm_set_image_variant(struct device *dev, { char *store_address; - if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) + down_read(¤t_image_rwsem); + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) { + up_read(¤t_image_rwsem); return count; + } store_address = socinfo_get_image_version_base_address(); if (IS_ERR_OR_NULL(store_address)) { pr_err("%s : Failed to get image version base address", __func__); + up_read(¤t_image_rwsem); return count; } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_image_rwsem); store_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET; snprintf(store_address, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s", buf); return count; @@ -866,7 +881,9 @@ msm_get_image_crm_version(struct device *dev, __func__); return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "Unknown"); } + down_read(¤t_image_rwsem); string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_image_rwsem); string_address += SMEM_IMAGE_VERSION_OEM_OFFSET; return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n", string_address); @@ -880,15 +897,20 @@ msm_set_image_crm_version(struct device *dev, { char *store_address; - if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) + down_read(¤t_image_rwsem); + if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) { + up_read(¤t_image_rwsem); return count; + } store_address = socinfo_get_image_version_base_address(); if (IS_ERR_OR_NULL(store_address)) { pr_err("%s : Failed to get image version base address", __func__); + up_read(¤t_image_rwsem); return count; } store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE; + up_read(¤t_image_rwsem); store_address += SMEM_IMAGE_VERSION_OEM_OFFSET; snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf); return count; @@ -899,8 +921,14 @@ msm_get_image_number(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", + int ret; + + down_read(¤t_image_rwsem); + ret = snprintf(buf, PAGE_SIZE, "%d\n", current_image); + up_read(¤t_image_rwsem); + return ret; + } static ssize_t @@ -912,10 +940,12 @@ msm_select_image(struct device *dev, struct device_attribute *attr, ret = kstrtoint(buf, 10, &digit); if (ret) return ret; + down_write(¤t_image_rwsem); if (0 <= digit && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT) current_image = digit; else current_image = 0; + up_write(¤t_image_rwsem); return count; } diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index d025afc97ae1..7808a6ea80fc 100755 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -111,6 +111,7 @@ struct ion_client { */ struct ion_handle { struct kref ref; + unsigned int user_ref_count; struct ion_client *client; struct ion_buffer *buffer; struct rb_node node; @@ -423,6 +424,48 @@ int ion_handle_put(struct ion_handle *handle) return ret; } +/* Must hold the client lock */ +static void user_ion_handle_get(struct ion_handle *handle) +{ + if (handle->user_ref_count++ == 0) + kref_get(&handle->ref); +} + +/* Must hold the client lock */ +static struct ion_handle *user_ion_handle_get_check_overflow(struct ion_handle *handle) +{ + if (handle->user_ref_count + 1 == 0) + return ERR_PTR(-EOVERFLOW); + user_ion_handle_get(handle); + return handle; +} + +/* passes a kref to the user ref count. + * We know we're holding a kref to the object before and + * after this call, so no need to reverify handle. */ +static struct ion_handle *pass_to_user(struct ion_handle *handle) +{ + struct ion_client *client = handle->client; + struct ion_handle *ret; + + mutex_lock(&client->lock); + ret = user_ion_handle_get_check_overflow(handle); + ion_handle_put_nolock(handle); + mutex_unlock(&client->lock); + return ret; +} + +/* Must hold the client lock */ +static int user_ion_handle_put_nolock(struct ion_handle *handle) +{ + int ret; + + if (--handle->user_ref_count == 0) + ret = ion_handle_put_nolock(handle); + + return ret; +} + static struct ion_handle *ion_handle_lookup(struct ion_client *client, struct ion_buffer *buffer) { @@ -638,6 +681,25 @@ static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle ion_handle_put_nolock(handle); } +/* Must hold the client lock */ +static void user_ion_free_nolock(struct ion_client *client, struct ion_handle *handle) +{ + bool valid_handle; + + BUG_ON(client != handle->client); + + valid_handle = ion_handle_validate(client, handle); + if (!valid_handle) { + WARN(1, "%s: invalid handle passed to free.\n", __func__); + return; + } + if (handle->user_ref_count == 0) { + WARN(1, "%s: User does not have access!\n", __func__); + return; + } + user_ion_handle_put_nolock(handle); +} + void ion_free(struct ion_client *client, struct ion_handle *handle) { BUG_ON(client != handle->client); @@ -1460,7 +1522,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) data.allocation.flags, true); if (IS_ERR(handle)) return PTR_ERR(handle); - + pass_to_user(handle); data.allocation.handle = handle->id; cleanup_handle = handle; @@ -1476,7 +1538,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) mutex_unlock(&client->lock); return PTR_ERR(handle); } - ion_free_nolock(client, handle); + user_ion_free_nolock(client, handle); ion_handle_put_nolock(handle); mutex_unlock(&client->lock); break; @@ -1499,10 +1561,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ion_handle *handle; handle = ion_import_dma_buf(client, data.fd.fd); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { ret = PTR_ERR(handle); - else - data.handle.handle = handle->id; + } else { + handle = pass_to_user(handle); + if (IS_ERR(handle)) + ret = PTR_ERR(handle); + else + data.handle.handle = handle->id; + } break; } case ION_IOC_SYNC: @@ -1534,8 +1601,10 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (dir & _IOC_READ) { if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) { if (cleanup_handle) { - ion_free(client, cleanup_handle); - ion_handle_put(cleanup_handle); + mutex_lock(&client->lock); + user_ion_free_nolock(client, cleanup_handle); + ion_handle_put_nolock(cleanup_handle); + mutex_unlock(&client->lock); } return -EFAULT; } diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 79fed114a2e0..3e152a400eaa 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1037,6 +1037,8 @@ pscsi_execute_cmd(struct se_cmd *cmd) ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto fail; } + + blk_rq_set_block_pc(req); } else { BUG_ON(!cmd->data_length); @@ -1053,7 +1055,6 @@ pscsi_execute_cmd(struct se_cmd *cmd) } } - req->cmd_type = REQ_TYPE_BLOCK_PC; req->end_io = pscsi_req_done; req->end_io_data = cmd; req->cmd_len = scsi_command_size(pt->pscsi_cdb); diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c index a170397e325d..755e223b3fb7 100644 --- a/drivers/thermal/msm_thermal-dev.c +++ b/drivers/thermal/msm_thermal-dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -33,6 +33,7 @@ static struct class *thermal_class; static struct msm_thermal_ioctl_dev *msm_thermal_dev; static unsigned int freq_table_len[NR_CPUS], freq_table_set[NR_CPUS]; static unsigned int *freq_table_ptr[NR_CPUS]; +static DEFINE_MUTEX(ioctl_access_mutex); static int msm_thermal_ioctl_open(struct inode *node, struct file *filep) { @@ -199,8 +200,9 @@ static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd, ret = validate_and_copy(&cmd, &arg, &query); if (ret) - goto process_exit; + return ret; + mutex_lock(&ioctl_access_mutex); switch (cmd) { case MSM_THERMAL_SET_CPU_MAX_FREQUENCY: ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num, @@ -226,6 +228,7 @@ static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd, goto process_exit; } process_exit: + mutex_unlock(&ioctl_access_mutex); return ret; } diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index e5eb1b5a04eb..2f261fba980c 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -774,8 +774,6 @@ static int ab8500_usb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ab); - ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier); - /* all: Disable phy when called from set_host and set_peripheral */ INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 8443335c2ea0..f7451fa27788 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -314,8 +314,6 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) goto err_irq; } - ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier); - INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw"); diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index bd601c537c8d..f2a77e236d07 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -157,8 +157,6 @@ static int mxs_phy_probe(struct platform_device *pdev) mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; mxs_phy->phy.type = USB_PHY_TYPE_USB2; - ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier); - mxs_phy->clk = clk; platform_set_drvdata(pdev, &mxs_phy->phy); diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 5f79d8e2caab..f716ea19f123 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -331,6 +331,8 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) return -EINVAL; } + ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); + spin_lock_irqsave(&phy_lock, flags); list_for_each_entry(phy, &phy_list, head) { @@ -369,6 +371,8 @@ int usb_add_phy_dev(struct usb_phy *x) return -EINVAL; } + ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); + spin_lock_irqsave(&phy_lock, flags); list_for_each_entry(phy_bind, &phy_bind_list, list) if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev)))) diff --git a/fs/Kconfig b/fs/Kconfig index dc3ec4cb406e..3b5e7c5be37e 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -188,6 +188,7 @@ if MISC_FILESYSTEMS source "fs/adfs/Kconfig" source "fs/affs/Kconfig" source "fs/ecryptfs/Kconfig" +source "fs/sdcardfs/Kconfig" source "fs/hfs/Kconfig" source "fs/hfsplus/Kconfig" source "fs/befs/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index adb8947b94af..7594e22a39d4 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -3,7 +3,7 @@ # # 14 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. -# +# obj-y := open.o read_write.o file_table.o super.o \ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ @@ -59,7 +59,7 @@ obj-y += devpts/ obj-$(CONFIG_PROFILING) += dcookies.o obj-$(CONFIG_DLM) += dlm/ - + # Do not add any filesystems before this line obj-$(CONFIG_FSCACHE) += fscache/ obj-$(CONFIG_REISERFS_FS) += reiserfs/ @@ -82,6 +82,7 @@ obj-$(CONFIG_ISO9660_FS) += isofs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ obj-$(CONFIG_HFS_FS) += hfs/ obj-$(CONFIG_ECRYPT_FS) += ecryptfs/ +obj-$(CONFIG_SDCARD_FS) += sdcardfs/ obj-$(CONFIG_VXFS_FS) += freevxfs/ obj-$(CONFIG_NFS_FS) += nfs/ obj-$(CONFIG_EXPORTFS) += exportfs/ diff --git a/fs/attr.c b/fs/attr.c index 66fa6251c398..64fc5985c598 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -167,7 +167,7 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) } EXPORT_SYMBOL(setattr_copy); -int notify_change(struct dentry * dentry, struct iattr * attr) +int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; umode_t mode = inode->i_mode; @@ -239,7 +239,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr) if (error) return error; - if (inode->i_op->setattr) + if (mnt && inode->i_op->setattr2) + error = inode->i_op->setattr2(mnt, dentry, attr); + else if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); @@ -252,4 +254,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr) return error; } +EXPORT_SYMBOL(notify_change2); + +int notify_change(struct dentry * dentry, struct iattr * attr) +{ + return notify_change2(NULL, dentry, attr); +} EXPORT_SYMBOL(notify_change); diff --git a/fs/coda/dir.c b/fs/coda/dir.c index b7d3a05c062c..fc66861b3598 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -391,8 +391,7 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) if (!host_file->f_op) return -ENOTDIR; - if (host_file->f_op->readdir) - { + if (host_file->f_op->readdir) { /* potemkin case: we were handed a directory inode. * We can't use vfs_readdir because we have to keep the file * position in sync between the coda_file and the host_file. @@ -410,8 +409,20 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) coda_file->f_pos = host_file->f_pos; mutex_unlock(&host_inode->i_mutex); - } - else /* Venus: we must read Venus dirents from a file */ + } else if (host_file->f_op->iterate) { + struct inode *host_inode = file_inode(host_file); + struct dir_context *ctx = buf; + + mutex_lock(&host_inode->i_mutex); + ret = -ENOENT; + if (!IS_DEADDIR(host_inode)) { + ret = host_file->f_op->iterate(host_file, ctx); + file_accessed(host_file); + } + mutex_unlock(&host_inode->i_mutex); + + coda_file->f_pos = ctx->pos; + } else /* Venus: we must read Venus dirents from a file */ ret = coda_venus_readdir(coda_file, buf, filldir); return ret; diff --git a/fs/compat.c b/fs/compat.c index 77480d6a01e9..0095a6978eef 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -832,6 +832,7 @@ struct compat_old_linux_dirent { }; struct compat_readdir_callback { + struct dir_context ctx; struct compat_old_linux_dirent __user *dirent; int result; }; @@ -873,15 +874,15 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd, { int error; struct fd f = fdget(fd); - struct compat_readdir_callback buf; + struct compat_readdir_callback buf = { + .ctx.actor = compat_fillonedir, + .dirent = dirent + }; if (!f.file) return -EBADF; - buf.result = 0; - buf.dirent = dirent; - - error = vfs_readdir(f.file, compat_fillonedir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (buf.result) error = buf.result; @@ -897,6 +898,7 @@ struct compat_linux_dirent { }; struct compat_getdents_callback { + struct dir_context ctx; struct compat_linux_dirent __user *current_dir; struct compat_linux_dirent __user *previous; int count; @@ -951,7 +953,11 @@ asmlinkage long compat_sys_getdents(unsigned int fd, { struct fd f; struct compat_linux_dirent __user * lastdirent; - struct compat_getdents_callback buf; + struct compat_getdents_callback buf = { + .ctx.actor = compat_filldir, + .current_dir = dirent, + .count = count + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -961,17 +967,12 @@ asmlinkage long compat_sys_getdents(unsigned int fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(f.file, compat_filldir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; if (lastdirent) { - if (put_user(f.file->f_pos, &lastdirent->d_off)) + if (put_user(buf.ctx.pos, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; @@ -983,6 +984,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd, #ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64 struct compat_getdents_callback64 { + struct dir_context ctx; struct linux_dirent64 __user *current_dir; struct linux_dirent64 __user *previous; int count; @@ -1036,7 +1038,11 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, { struct fd f; struct linux_dirent64 __user * lastdirent; - struct compat_getdents_callback64 buf; + struct compat_getdents_callback64 buf = { + .ctx.actor = compat_filldir64, + .current_dir = dirent, + .count = count + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -1046,17 +1052,12 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(f.file, compat_filldir64, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; if (lastdirent) { - typeof(lastdirent->d_off) d_off = f.file->f_pos; + typeof(lastdirent->d_off) d_off = buf.ctx.pos; if (__put_user_unaligned(d_off, &lastdirent->d_off)) error = -EFAULT; else diff --git a/fs/coredump.c b/fs/coredump.c index a94f94d4f1a1..a4d6745b67da 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -673,7 +673,7 @@ void do_coredump(siginfo_t *siginfo) goto close_fail; if (!cprm.file->f_op || !cprm.file->f_op->write) goto close_fail; - if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file)) + if (do_truncate2(cprm.file->f_path.mnt, cprm.file->f_path.dentry, 0, 0, cprm.file)) goto close_fail; } diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index d4644cc938ba..fac9d0125fb6 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -68,6 +68,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, } struct ecryptfs_getdents_callback { + struct dir_context ctx; void *dirent; struct dentry *dentry; filldir_t filldir; @@ -126,7 +127,8 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) buf.filldir = filldir; buf.filldir_called = 0; buf.entries_written = 0; - rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf); + buf.ctx.actor = ecryptfs_filldir; + rc = iterate_dir(lower_file, &buf.ctx); file->f_pos = lower_file->f_pos; if (rc < 0) goto out; diff --git a/fs/exec.c b/fs/exec.c index a095d9856378..960266d5d3bb 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1127,7 +1127,7 @@ EXPORT_SYMBOL(flush_old_exec); void would_dump(struct linux_binprm *bprm, struct file *file) { - if (inode_permission(file_inode(file), MAY_READ) < 0) + if (inode_permission2(file->f_path.mnt, file_inode(file), MAY_READ) < 0) bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; } EXPORT_SYMBOL(would_dump); @@ -1570,6 +1570,11 @@ static int do_execve_common(const char *filename, if (retval < 0) goto out; + if (d_is_su(file->f_dentry) && capable(CAP_SYS_ADMIN)) { + current->flags |= PF_SU; + su_exec(); + } + /* execve succeeded */ current->fs->in_exec = 0; current->in_execve = 0; diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index b4eec4c9a790..dc4784b52d92 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -212,6 +212,7 @@ reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf) } struct getdents_callback { + struct dir_context ctx; char *name; /* name that was found. It already points to a buffer NAME_MAX+1 is size */ unsigned long ino; /* the inum we are looking for */ @@ -254,7 +255,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child) struct inode *dir = path->dentry->d_inode; int error; struct file *file; - struct getdents_callback buffer; + struct getdents_callback buffer = { + .ctx.actor = filldir_one, + .name = name, + .ino = child->d_inode->i_ino + }; error = -ENOTDIR; if (!dir || !S_ISDIR(dir->i_mode)) @@ -271,17 +276,14 @@ static int get_name(const struct path *path, char *name, struct dentry *child) goto out; error = -EINVAL; - if (!file->f_op->readdir) + if (!file->f_op->readdir && !file->f_op->iterate) goto out_close; - buffer.name = name; - buffer.ino = child->d_inode->i_ino; - buffer.found = 0; buffer.sequence = 0; while (1) { int old_seq = buffer.sequence; - error = vfs_readdir(file, filldir_one, &buffer); + error = iterate_dir(file, &buffer.ctx); if (buffer.found) { error = 0; break; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 00d607ed08e0..6902fc9e1306 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3782,7 +3782,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG)) { - if (le32_to_cpu(es->s_first_meta_bg) > db_count) { + if (le32_to_cpu(es->s_first_meta_bg) >= db_count) { ext4_msg(sb, KERN_WARNING, "first meta block group too large: %u " "(group descriptor block count %u)", diff --git a/fs/fs_struct.c b/fs/fs_struct.c index d8ac61d0c932..5a1bb8242a56 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -127,6 +127,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) } return fs; } +EXPORT_SYMBOL_GPL(copy_fs_struct); int unshare_fs_struct(void) { diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index f4e875a29e7a..69eee305d36e 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1874,6 +1875,10 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc, spin_unlock(&fc->lock); err = copy_out_args(cs, &req->out, nbytes); + if (req->in.h.opcode == FUSE_CANONICAL_PATH) { + req->out.h.error = kern_path((char *)req->out.args[0].value, 0, + req->canonical_path); + } fuse_copy_finish(cs); spin_lock(&fc->lock); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index e67b13de2ebc..7668bbcd444a 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -252,6 +252,50 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) return 1; } +/* + * Get the canonical path. Since we must translate to a path, this must be done + * in the context of the userspace daemon, however, the userspace daemon cannot + * look up paths on its own. Instead, we handle the lookup as a special case + * inside of the write request. + */ +static void fuse_dentry_canonical_path(const struct path *path, struct path *canonical_path) { + struct inode *inode = path->dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + int err; + char *path_name; + + req = fuse_get_req(fc, 1); + err = PTR_ERR(req); + if (IS_ERR(req)) + goto default_path; + + path_name = (char*)__get_free_page(GFP_KERNEL); + if (!path_name) { + fuse_put_request(fc, req); + goto default_path; + } + + req->in.h.opcode = FUSE_CANONICAL_PATH; + req->in.h.nodeid = get_node_id(inode); + req->in.numargs = 0; + req->out.numargs = 1; + req->out.args[0].size = PATH_MAX; + req->out.args[0].value = path_name; + req->canonical_path = canonical_path; + req->out.argvar = 1; + fuse_request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + free_page((unsigned long)path_name); + if (!err) + return; +default_path: + canonical_path->dentry = path->dentry; + canonical_path->mnt = path->mnt; + path_get(canonical_path); +} + static int invalid_nodeid(u64 nodeid) { return !nodeid || nodeid == FUSE_ROOT_ID; @@ -259,6 +303,7 @@ static int invalid_nodeid(u64 nodeid) const struct dentry_operations fuse_dentry_operations = { .d_revalidate = fuse_dentry_revalidate, + .d_canonical_path = fuse_dentry_canonical_path, }; int fuse_valid_type(int m) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5ced199b50bb..93f861a6d36d 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -348,6 +348,9 @@ struct fuse_req { /** Inode used in the request or NULL */ struct inode *inode; + /** Path used for completing d_canonical_path */ + struct path *canonical_path; + /** AIO control block */ struct fuse_io_priv *io; diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 9973df4ff565..7102c7a5af4d 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -88,7 +88,10 @@ static int gfs2_get_name(struct dentry *parent, char *name, struct inode *dir = parent->d_inode; struct inode *inode = child->d_inode; struct gfs2_inode *dip, *ip; - struct get_name_filldir gnfd; + struct get_name_filldir gnfd = { + .ctx.actor = get_name_filldir, + .name = name + }; struct gfs2_holder gh; u64 offset = 0; int error; @@ -106,7 +109,6 @@ static int gfs2_get_name(struct dentry *parent, char *name, *name = 0; gnfd.inum.no_addr = ip->i_no_addr; gnfd.inum.no_formal_ino = ip->i_no_formal_ino; - gnfd.name = name; error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh); if (error) diff --git a/fs/inode.c b/fs/inode.c index 17f95b417955..9cc33bab1696 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1599,12 +1599,12 @@ int should_remove_suid(struct dentry *dentry) } EXPORT_SYMBOL(should_remove_suid); -static int __remove_suid(struct dentry *dentry, int kill) +static int __remove_suid(struct vfsmount *mnt, struct dentry *dentry, int kill) { struct iattr newattrs; newattrs.ia_valid = ATTR_FORCE | kill; - return notify_change(dentry, &newattrs); + return notify_change2(mnt, dentry, &newattrs); } int file_remove_suid(struct file *file) @@ -1626,8 +1626,6 @@ int file_remove_suid(struct file *file) return killpriv; if (killpriv) error = security_inode_killpriv(dentry); - if (!error && killsuid) - error = __remove_suid(dentry, killsuid); if (!error) inode_has_no_xattr(inode); diff --git a/fs/internal.h b/fs/internal.h index 2ffa65a36ca0..db80be4c5b8d 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -80,9 +80,11 @@ extern struct file *get_empty_filp(void); * super.c */ extern int do_remount_sb(struct super_block *, int, void *, int); +extern int do_remount_sb2(struct vfsmount *, struct super_block *, int, + void *, int); extern bool grab_super_passive(struct super_block *sb); extern struct dentry *mount_fs(struct file_system_type *, - int, const char *, void *); + int, const char *, struct vfsmount *, void *); extern struct super_block *user_get_super(dev_t); /* diff --git a/fs/namei.c b/fs/namei.c index f7065d973ebe..bdfbb34dd137 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -356,9 +356,11 @@ int generic_permission(struct inode *inode, int mask) * flag in inode->i_opflags, that says "this has not special * permission function, use the fast case". */ -static inline int do_inode_permission(struct inode *inode, int mask) +static inline int do_inode_permission(struct vfsmount *mnt, struct inode *inode, int mask) { if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { + if (likely(mnt && inode->i_op->permission2)) + return inode->i_op->permission2(mnt, inode, mask); if (likely(inode->i_op->permission)) return inode->i_op->permission(inode, mask); @@ -382,7 +384,7 @@ static inline int do_inode_permission(struct inode *inode, int mask) * This does not check for a read-only file system. You probably want * inode_permission(). */ -int __inode_permission(struct inode *inode, int mask) +int __inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask) { int retval; @@ -394,7 +396,7 @@ int __inode_permission(struct inode *inode, int mask) return -EACCES; } - retval = do_inode_permission(inode, mask); + retval = do_inode_permission(mnt, inode, mask); if (retval) return retval; @@ -404,6 +406,13 @@ int __inode_permission(struct inode *inode, int mask) return security_inode_permission(inode, mask); } +EXPORT_SYMBOL(__inode_permission2); + +int __inode_permission(struct inode *inode, int mask) +{ + return __inode_permission2(NULL, inode, mask); +} +EXPORT_SYMBOL(__inode_permission); /** * sb_permission - Check superblock-level permissions @@ -437,15 +446,22 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask) * * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. */ -int inode_permission(struct inode *inode, int mask) +int inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask) { int retval; retval = sb_permission(inode->i_sb, inode, mask); if (retval) return retval; - return __inode_permission(inode, mask); + return __inode_permission2(mnt, inode, mask); } +EXPORT_SYMBOL(inode_permission2); + +int inode_permission(struct inode *inode, int mask) +{ + return inode_permission2(NULL, inode, mask); +} +EXPORT_SYMBOL(inode_permission); /** * path_get - get a reference to a path @@ -1485,13 +1501,13 @@ static int lookup_slow(struct nameidata *nd, struct path *path) static inline int may_lookup(struct nameidata *nd) { if (nd->flags & LOOKUP_RCU) { - int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); + int err = inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC|MAY_NOT_BLOCK); if (err != -ECHILD) return err; if (unlazy_walk(nd, NULL)) return -ECHILD; } - return inode_permission(nd->inode, MAY_EXEC); + return inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC); } static inline int handle_dots(struct nameidata *nd, int type) @@ -1866,10 +1882,11 @@ static int path_init(int dfd, const char *name, unsigned int flags, nd->depth = 0; if (flags & LOOKUP_ROOT) { struct inode *inode = nd->root.dentry->d_inode; + struct vfsmount *mnt = nd->root.mnt; if (*name) { if (!can_lookup(inode)) return -ENOTDIR; - retval = inode_permission(inode, MAY_EXEC); + retval = inode_permission2(mnt, inode, MAY_EXEC); if (retval) return retval; } @@ -2009,6 +2026,16 @@ static int path_lookupat(int dfd, const char *name, } } + if (!err) { + struct super_block *sb = nd->inode->i_sb; + if (sb->s_flags & MS_RDONLY) { + if (d_is_su(nd->path.dentry) && !su_visible()) { + path_put(&nd->path); + err = -ENOENT; + } + } + } + if (base) fput(base); @@ -2111,6 +2138,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) /** * lookup_one_len - filesystem helper to lookup single pathname component * @name: pathname component to lookup + * @mnt: mount we are looking up on * @base: base directory to lookup from * @len: maximum length @len should be interpreted to * @@ -2119,7 +2147,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) * nameidata argument is passed to the filesystem methods and a filesystem * using this helper needs to be prepared for that. */ -struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) +struct dentry *lookup_one_len2(const char *name, struct vfsmount *mnt, struct dentry *base, int len) { struct qstr this; unsigned int c; @@ -2153,12 +2181,19 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) return ERR_PTR(err); } - err = inode_permission(base->d_inode, MAY_EXEC); + err = inode_permission2(mnt, base->d_inode, MAY_EXEC); if (err) return ERR_PTR(err); return __lookup_hash(&this, base, 0); } +EXPORT_SYMBOL(lookup_one_len2); + +struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) +{ + return lookup_one_len2(name, NULL, base, len); +} +EXPORT_SYMBOL(lookup_one_len); int user_path_at_empty(int dfd, const char __user *name, unsigned flags, struct path *path, int *empty) @@ -2248,7 +2283,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) * 10. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). */ -static int may_delete(struct inode *dir,struct dentry *victim,int isdir) +static int may_delete(struct vfsmount *mnt, struct inode *dir,struct dentry *victim,int isdir) { int error; @@ -2258,7 +2293,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) BUG_ON(victim->d_parent->d_inode != dir); audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); + error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) @@ -2288,14 +2323,14 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) * 3. We should have write and exec permissions on dir * 4. We can't do it if dir is immutable (done in permission()) */ -static inline int may_create(struct inode *dir, struct dentry *child) +static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child) { audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return inode_permission(dir, MAY_WRITE | MAY_EXEC); + return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC); } /* @@ -2340,10 +2375,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2) } } -int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool want_excl) +int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, + umode_t mode, bool want_excl) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); if (error) return error; @@ -2364,10 +2399,19 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, fsnotify_create(dir, dentry); return error; } +EXPORT_SYMBOL(vfs_create2); + +int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool want_excl) +{ + return vfs_create2(NULL, dir, dentry, mode, want_excl); +} +EXPORT_SYMBOL(vfs_create); static int may_open(struct path *path, int acc_mode, int flag) { struct dentry *dentry = path->dentry; + struct vfsmount *mnt = path->mnt; struct inode *inode = dentry->d_inode; int error; @@ -2396,7 +2440,7 @@ static int may_open(struct path *path, int acc_mode, int flag) break; } - error = inode_permission(inode, acc_mode); + error = inode_permission2(mnt, inode, acc_mode); if (error) return error; @@ -2431,7 +2475,7 @@ static int handle_truncate(struct file *filp) if (!error) error = security_path_truncate(path); if (!error) { - error = do_truncate(path->dentry, 0, + error = do_truncate2(path->mnt, path->dentry, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, filp); } @@ -2452,7 +2496,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode) if (error) return error; - error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); + error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); if (error) return error; @@ -2640,6 +2684,7 @@ static int lookup_open(struct nameidata *nd, struct path *path, bool got_write, int *opened) { struct dentry *dir = nd->path.dentry; + struct vfsmount *mnt = nd->path.mnt; struct inode *dir_inode = dir->d_inode; struct dentry *dentry; int error; @@ -2687,7 +2732,7 @@ static int lookup_open(struct nameidata *nd, struct path *path, error = security_path_mknod(&nd->path, dentry, mode, 0); if (error) goto out_dput; - error = vfs_create(dir->d_inode, dentry, mode, + error = vfs_create2(mnt, dir->d_inode, dentry, mode, nd->flags & LOOKUP_EXCL); if (error) goto out_dput; @@ -3153,9 +3198,9 @@ struct dentry *user_path_create(int dfd, const char __user *pathname, } EXPORT_SYMBOL(user_path_create); -int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) +int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); if (error) return error; @@ -3186,6 +3231,13 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) return 0; } +EXPORT_SYMBOL(vfs_mknod2); + +int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) +{ + return vfs_mknod2(NULL, dir, dentry, mode, dev); +} +EXPORT_SYMBOL(vfs_mknod); static int may_mknod(umode_t mode) { @@ -3227,10 +3279,10 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, goto out; switch (mode & S_IFMT) { case 0: case S_IFREG: - error = vfs_create(path.dentry->d_inode,dentry,mode,true); + error = vfs_create2(path.mnt, path.dentry->d_inode,dentry,mode,true); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode, + error = vfs_mknod2(path.mnt, path.dentry->d_inode,dentry,mode, new_decode_dev(dev)); break; case S_IFIFO: case S_IFSOCK: @@ -3251,9 +3303,9 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d return sys_mknodat(AT_FDCWD, filename, mode, dev); } -int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +int vfs_mkdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); unsigned max_links = dir->i_sb->s_max_links; if (error) @@ -3275,6 +3327,13 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) fsnotify_mkdir(dir, dentry); return error; } +EXPORT_SYMBOL(vfs_mkdir2); + +int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + return vfs_mkdir2(NULL, dir, dentry, mode); +} +EXPORT_SYMBOL(vfs_mkdir); SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) { @@ -3292,7 +3351,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) mode &= ~current_umask(); error = security_path_mkdir(&path, dentry, mode); if (!error) - error = vfs_mkdir(path.dentry->d_inode, dentry, mode); + error = vfs_mkdir2(path.mnt, path.dentry->d_inode, dentry, mode); done_path_create(&path, dentry); if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; @@ -3330,9 +3389,9 @@ void dentry_unhash(struct dentry *dentry) spin_unlock(&dentry->d_lock); } -int vfs_rmdir(struct inode *dir, struct dentry *dentry) +int vfs_rmdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry) { - int error = may_delete(dir, dentry, 1); + int error = may_delete(mnt, dir, dentry, 1); if (error) return error; @@ -3366,6 +3425,13 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) d_delete(dentry); return error; } +EXPORT_SYMBOL(vfs_rmdir2); + +int vfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + return vfs_rmdir2(NULL, dir, dentry); +} +EXPORT_SYMBOL(vfs_rmdir); static long do_rmdir(int dfd, const char __user *pathname) { @@ -3408,7 +3474,7 @@ static long do_rmdir(int dfd, const char __user *pathname) error = security_path_rmdir(&nd.path, dentry); if (error) goto exit3; - error = vfs_rmdir(nd.path.dentry->d_inode, dentry); + error = vfs_rmdir2(nd.path.mnt, nd.path.dentry->d_inode, dentry); exit3: dput(dentry); exit2: @@ -3429,9 +3495,9 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname) return do_rmdir(AT_FDCWD, pathname); } -int vfs_unlink(struct inode *dir, struct dentry *dentry) +int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry) { - int error = may_delete(dir, dentry, 0); + int error = may_delete(mnt, dir, dentry, 0); if (error) return error; @@ -3460,6 +3526,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) return error; } +EXPORT_SYMBOL(vfs_unlink2); + +int vfs_unlink(struct inode *dir, struct dentry *dentry) +{ + return vfs_unlink2(NULL, dir, dentry); +} +EXPORT_SYMBOL(vfs_unlink); /* * Make sure that the actual truncation of the file will occur outside its @@ -3503,7 +3576,7 @@ static long do_unlinkat(int dfd, const char __user *pathname) error = security_path_unlink(&nd.path, dentry); if (error) goto exit2; - error = vfs_unlink(nd.path.dentry->d_inode, dentry); + error = vfs_unlink2(nd.path.mnt, nd.path.dentry->d_inode, dentry); exit2: dput(dentry); } @@ -3543,9 +3616,9 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname) return do_unlinkat(AT_FDCWD, pathname); } -int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) +int vfs_symlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, const char *oldname) { - int error = may_create(dir, dentry); + int error = may_create(mnt, dir, dentry); if (error) return error; @@ -3562,6 +3635,13 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) fsnotify_create(dir, dentry); return error; } +EXPORT_SYMBOL(vfs_symlink2); + +int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) +{ + return vfs_symlink2(NULL, dir, dentry, oldname); +} +EXPORT_SYMBOL(vfs_symlink); SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, int, newdfd, const char __user *, newname) @@ -3583,7 +3663,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, error = security_path_symlink(&path, dentry, from->name); if (!error) - error = vfs_symlink(path.dentry->d_inode, dentry, from->name); + error = vfs_symlink2(path.mnt, path.dentry->d_inode, dentry, from->name); done_path_create(&path, dentry); if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; @@ -3599,7 +3679,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn return sys_symlinkat(oldname, AT_FDCWD, newname); } -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct inode *inode = old_dentry->d_inode; unsigned max_links = dir->i_sb->s_max_links; @@ -3608,7 +3688,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de if (!inode) return -ENOENT; - error = may_create(dir, new_dentry); + error = may_create(mnt, dir, new_dentry); if (error) return error; @@ -3642,6 +3722,13 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de fsnotify_link(dir, inode, new_dentry); return error; } +EXPORT_SYMBOL(vfs_link2); + +int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +{ + return vfs_link2(NULL, old_dentry, dir, new_dentry); +} +EXPORT_SYMBOL(vfs_link); /* * Hardlinks are often used in delicate situations. We avoid @@ -3695,7 +3782,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, error = security_path_link(old_path.dentry, &new_path, new_dentry); if (error) goto out_dput; - error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); + error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry); out_dput: done_path_create(&new_path, new_dentry); if (retry_estale(error, how)) { @@ -3741,8 +3828,9 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname * ->i_mutex on parents, which works but leads to some truly excessive * locking]. */ -static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) +static int vfs_rename_dir(struct vfsmount *mnt, + struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { int error = 0; struct inode *target = new_dentry->d_inode; @@ -3753,7 +3841,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, * we'll need to flip '..'. */ if (new_dir != old_dir) { - error = inode_permission(old_dentry->d_inode, MAY_WRITE); + error = inode_permission2(mnt, old_dentry->d_inode, MAY_WRITE); if (error) return error; } @@ -3828,7 +3916,8 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, return error; } -int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, +int vfs_rename2(struct vfsmount *mnt, + struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int error; @@ -3838,14 +3927,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (old_dentry->d_inode == new_dentry->d_inode) return 0; - error = may_delete(old_dir, old_dentry, is_dir); + error = may_delete(mnt, old_dir, old_dentry, is_dir); if (error) return error; if (!new_dentry->d_inode) - error = may_create(new_dir, new_dentry); + error = may_create(mnt, new_dir, new_dentry); else - error = may_delete(new_dir, new_dentry, is_dir); + error = may_delete(mnt, new_dir, new_dentry, is_dir); if (error) return error; @@ -3855,7 +3944,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, old_name = fsnotify_oldname_init(old_dentry->d_name.name); if (is_dir) - error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); + error = vfs_rename_dir(mnt, old_dir,old_dentry,new_dir,new_dentry); else error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); if (!error) @@ -3865,6 +3954,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, return error; } +EXPORT_SYMBOL(vfs_rename2); + +int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry); +} +EXPORT_SYMBOL(vfs_rename); SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname) @@ -3947,7 +4044,7 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, &newnd.path, new_dentry); if (error) goto exit5; - error = vfs_rename(old_dir->d_inode, old_dentry, + error = vfs_rename2(oldnd.path.mnt, old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); exit5: dput(new_dentry); @@ -4121,7 +4218,6 @@ EXPORT_SYMBOL(follow_down); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(get_write_access); /* nfsd */ EXPORT_SYMBOL(lock_rename); -EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(page_follow_link_light); EXPORT_SYMBOL(page_put_link); EXPORT_SYMBOL(page_readlink); @@ -4130,18 +4226,9 @@ EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(kern_path); EXPORT_SYMBOL(vfs_path_lookup); -EXPORT_SYMBOL(inode_permission); EXPORT_SYMBOL(unlock_rename); -EXPORT_SYMBOL(vfs_create); EXPORT_SYMBOL(vfs_follow_link); -EXPORT_SYMBOL(vfs_link); -EXPORT_SYMBOL(vfs_mkdir); -EXPORT_SYMBOL(vfs_mknod); EXPORT_SYMBOL(generic_permission); EXPORT_SYMBOL(vfs_readlink); -EXPORT_SYMBOL(vfs_rename); -EXPORT_SYMBOL(vfs_rmdir); -EXPORT_SYMBOL(vfs_symlink); -EXPORT_SYMBOL(vfs_unlink); EXPORT_SYMBOL(dentry_unhash); EXPORT_SYMBOL(generic_readlink); diff --git a/fs/namespace.c b/fs/namespace.c index 4c1d882684b0..c70d6fac9777 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -797,7 +797,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void if (flags & MS_KERNMOUNT) mnt->mnt.mnt_flags = MNT_INTERNAL; - root = mount_fs(type, flags, name, data); + root = mount_fs(type, flags, name, &mnt->mnt, data); if (IS_ERR(root)) { kfree(mnt->mnt.data); free_vfsmnt(mnt); @@ -1870,7 +1870,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags, else if (!capable(CAP_SYS_ADMIN)) err = -EPERM; else { - err = do_remount_sb(sb, flags, data, 0); + err = do_remount_sb2(path->mnt, sb, flags, data, 0); namespace_lock(); br_write_lock(&vfsmount_lock); propagate_remount(mnt); diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 4e9a21db867a..105a3b080d12 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -240,11 +240,16 @@ struct name_list { struct list_head list; }; +struct nfs4_dir_ctx { + struct dir_context ctx; + struct list_head names; +}; + static int nfsd4_build_namelist(void *arg, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - struct list_head *names = arg; + struct nfs4_dir_ctx *ctx = arg; struct name_list *entry; if (namlen != HEXDIR_LEN - 1) @@ -254,7 +259,7 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, return -ENOMEM; memcpy(entry->name, name, HEXDIR_LEN - 1); entry->name[HEXDIR_LEN - 1] = '\0'; - list_add(&entry->list, names); + list_add(&entry->list, &ctx->names); return 0; } @@ -263,7 +268,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) { const struct cred *original_cred; struct dentry *dir = nn->rec_file->f_path.dentry; - LIST_HEAD(names); + struct nfs4_dir_ctx ctx = { + .ctx.actor = nfsd4_build_namelist, + .names = LIST_HEAD_INIT(ctx.names) + }; int status; status = nfs4_save_creds(&original_cred); @@ -276,11 +284,11 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) return status; } - status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names); + status = iterate_dir(nn->rec_file, &ctx.ctx); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); - while (!list_empty(&names)) { + while (!list_empty(&ctx.names)) { struct name_list *entry; - entry = list_entry(names.next, struct name_list, list); + entry = list_entry(ctx.names.next, struct name_list, list); if (!status) { struct dentry *dentry; dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 81325ba8660a..11224fa5ff25 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1950,6 +1950,7 @@ struct buffered_dirent { }; struct readdir_data { + struct dir_context ctx; char *dirent; size_t used; int full; @@ -1981,13 +1982,15 @@ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen, static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, struct readdir_cd *cdp, loff_t *offsetp) { - struct readdir_data buf; struct buffered_dirent *de; int host_err; int size; loff_t offset; + struct readdir_data buf = { + .ctx.actor = nfsd_buffered_filldir, + .dirent = (void *)__get_free_page(GFP_KERNEL) + }; - buf.dirent = (void *)__get_free_page(GFP_KERNEL); if (!buf.dirent) return nfserrno(-ENOMEM); @@ -2001,7 +2004,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, buf.used = 0; buf.full = 0; - host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf); + host_err = iterate_dir(file, &buf.ctx); if (buf.full) host_err = 0; diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 9be6b4163406..92d31fa7cb1a 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -490,7 +490,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, } /* you can only watch an inode if you have read permissions on it */ - ret = inode_permission(path->dentry->d_inode, MAY_READ); + ret = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ); if (ret) path_put(path); out: diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 959815c1e017..941e59d7ffe7 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -349,7 +349,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns if (error) return error; /* you can only watch an inode if you have read permissions on it */ - error = inode_permission(path->dentry->d_inode, MAY_READ); + error = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ); if (error) path_put(path); return error; @@ -738,6 +738,8 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, struct fsnotify_group *group; struct inode *inode; struct path path; + struct path alteredpath; + struct path *canonical_path = &path; struct fd f; int ret; unsigned flags = 0; @@ -765,13 +767,22 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, if (ret) goto fput_and_out; + /* support stacked filesystems */ + if(path.dentry && path.dentry->d_op) { + if (path.dentry->d_op->d_canonical_path) { + path.dentry->d_op->d_canonical_path(&path, &alteredpath); + canonical_path = &alteredpath; + path_put(&path); + } + } + /* inode held in place by reference to path; group by fget on fd */ - inode = path.dentry->d_inode; + inode = canonical_path->dentry->d_inode; group = f.file->private_data; /* create/update an inode mark */ ret = inotify_update_watch(group, inode, mask); - path_put(&path); + path_put(canonical_path); fput_and_out: fdput(f); return ret; diff --git a/fs/open.c b/fs/open.c index 9bf7fa0b475d..4bf18067c8e5 100644 --- a/fs/open.c +++ b/fs/open.c @@ -34,8 +34,8 @@ #include "internal.h" -int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - struct file *filp) +int do_truncate2(struct vfsmount *mnt, struct dentry *dentry, loff_t length, + unsigned int time_attrs, struct file *filp) { int ret; struct iattr newattrs; @@ -57,17 +57,24 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, newattrs.ia_valid |= ret | ATTR_FORCE; mutex_lock(&dentry->d_inode->i_mutex); - ret = notify_change(dentry, &newattrs); + ret = notify_change2(mnt, dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); return ret; } +int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + struct file *filp) +{ + return do_truncate2(NULL, dentry, length, time_attrs, filp); +} long vfs_truncate(struct path *path, loff_t length) { struct inode *inode; + struct vfsmount *mnt; long error; inode = path->dentry->d_inode; + mnt = path->mnt; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ if (S_ISDIR(inode->i_mode)) @@ -79,7 +86,7 @@ long vfs_truncate(struct path *path, loff_t length) if (error) goto out; - error = inode_permission(inode, MAY_WRITE); + error = inode_permission2(mnt, inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; @@ -103,7 +110,7 @@ long vfs_truncate(struct path *path, loff_t length) if (!error) error = security_path_truncate(path); if (!error) - error = do_truncate(path->dentry, length, 0, NULL); + error = do_truncate2(mnt, path->dentry, length, 0, NULL); put_write_and_out: put_write_access(inode); @@ -152,6 +159,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) { struct inode *inode; struct dentry *dentry; + struct vfsmount *mnt; struct fd f; int error; @@ -168,6 +176,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) small = 0; dentry = f.file->f_path.dentry; + mnt = f.file->f_path.mnt; inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE)) @@ -187,7 +196,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) if (!error) error = security_path_truncate(&f.file->f_path); if (!error) - error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); + error = do_truncate2(mnt, dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); sb_end_write(inode->i_sb); out_putf: fdput(f); @@ -302,6 +311,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) struct cred *override_cred; struct path path; struct inode *inode; + struct vfsmount *mnt; int res; unsigned int lookup_flags = LOOKUP_FOLLOW; @@ -332,6 +342,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) goto out; inode = path.dentry->d_inode; + mnt = path.mnt; if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { /* @@ -343,7 +354,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) goto out_path_release; } - res = inode_permission(inode, mode | MAY_ACCESS); + res = inode_permission2(mnt, inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; @@ -387,7 +398,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -407,6 +418,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct fd f = fdget_raw(fd); struct inode *inode; + struct vfsmount *mnt; int error = -EBADF; error = -EBADF; @@ -414,12 +426,13 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) goto out; inode = file_inode(f.file); + mnt = f.file->f_path.mnt; error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) goto out_putf; - error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission2(mnt, inode, MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: @@ -438,7 +451,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -476,7 +489,7 @@ static int chmod_common(struct path *path, umode_t mode) goto out_unlock; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); out_unlock: mutex_unlock(&inode->i_mutex); mnt_drop_write(path->mnt); @@ -550,7 +563,7 @@ static int chown_common(struct path *path, uid_t user, gid_t group) mutex_lock(&inode->i_mutex); error = security_path_chown(path, uid, gid); if (!error) - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); return error; diff --git a/fs/proc/fd.c b/fs/proc/fd.c index d7a4a28ef630..d8eda970236c 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -302,11 +302,19 @@ static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, */ int proc_fd_permission(struct inode *inode, int mask) { - int rv = generic_permission(inode, mask); + struct task_struct *p; + int rv; + + rv = generic_permission(inode, mask); if (rv == 0) - return 0; - if (task_pid(current) == proc_pid(inode)) + return rv; + + rcu_read_lock(); + p = pid_task(proc_pid(inode), PIDTYPE_PID); + if (p && same_thread_group(p, current)) rv = 0; + rcu_read_unlock(); + return rv; } diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 5fe34c355e85..9243966026c3 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -112,7 +112,9 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) if (err) goto out; show_mnt_opts(m, mnt); - if (sb->s_op->show_options) + if (sb->s_op->show_options2) + err = sb->s_op->show_options2(mnt, m, mnt_path.dentry); + else if (sb->s_op->show_options) err = sb->s_op->show_options(m, mnt_path.dentry); seq_puts(m, " 0 0\n"); out: @@ -173,7 +175,9 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) err = show_sb_opts(m, sb); if (err) goto out; - if (sb->s_op->show_options) + if (sb->s_op->show_options2) { + err = sb->s_op->show_options2(mnt, m, mnt->mnt_root); + } else if (sb->s_op->show_options) err = sb->s_op->show_options(m, mnt->mnt_root); seq_putc(m, '\n'); out: diff --git a/fs/readdir.c b/fs/readdir.c index fee38e04fae4..d52d18d98877 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -20,11 +20,11 @@ #include -int vfs_readdir(struct file *file, filldir_t filler, void *buf) +int iterate_dir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); int res = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) + if (!file->f_op || (!file->f_op->readdir && !file->f_op->iterate)) goto out; res = security_file_permission(file, MAY_READ); @@ -37,15 +37,30 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf) res = -ENOENT; if (!IS_DEADDIR(inode)) { - res = file->f_op->readdir(file, buf, filler); + if (file->f_op->iterate) { + ctx->pos = file->f_pos; + ctx->romnt = (inode->i_sb->s_flags & MS_RDONLY); + res = file->f_op->iterate(file, ctx); + file->f_pos = ctx->pos; + } else { + res = file->f_op->readdir(file, ctx, ctx->actor); + ctx->pos = file->f_pos; + } file_accessed(file); } mutex_unlock(&inode->i_mutex); out: return res; } +EXPORT_SYMBOL(iterate_dir); -EXPORT_SYMBOL(vfs_readdir); +static bool hide_name(const char *name, int namlen) +{ + if (namlen == 2 && !memcmp(name, "su", 2)) + if (!su_visible()) + return true; + return false; +} /* * Traditional linux readdir() handling.. @@ -66,6 +81,7 @@ struct old_linux_dirent { }; struct readdir_callback { + struct dir_context ctx; struct old_linux_dirent __user * dirent; int result; }; @@ -73,7 +89,7 @@ struct readdir_callback { static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - struct readdir_callback * buf = (struct readdir_callback *) __buf; + struct readdir_callback *buf = (struct readdir_callback *) __buf; struct old_linux_dirent __user * dirent; unsigned long d_ino; @@ -84,6 +100,8 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset buf->result = -EOVERFLOW; return -EOVERFLOW; } + if (hide_name(name, namlen) && buf->ctx.romnt) + return 0; buf->result++; dirent = buf->dirent; if (!access_ok(VERIFY_WRITE, dirent, @@ -107,15 +125,15 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, { int error; struct fd f = fdget(fd); - struct readdir_callback buf; + struct readdir_callback buf = { + .ctx.actor = fillonedir, + .dirent = dirent + }; if (!f.file) return -EBADF; - buf.result = 0; - buf.dirent = dirent; - - error = vfs_readdir(f.file, fillonedir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (buf.result) error = buf.result; @@ -137,6 +155,7 @@ struct linux_dirent { }; struct getdents_callback { + struct dir_context ctx; struct linux_dirent __user * current_dir; struct linux_dirent __user * previous; int count; @@ -160,6 +179,8 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, buf->error = -EOVERFLOW; return -EOVERFLOW; } + if (hide_name(name, namlen) && buf->ctx.romnt) + return 0; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) @@ -191,7 +212,11 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, { struct fd f; struct linux_dirent __user * lastdirent; - struct getdents_callback buf; + struct getdents_callback buf = { + .ctx.actor = filldir, + .count = count, + .current_dir = dirent + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -201,17 +226,12 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(f.file, filldir, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; if (lastdirent) { - if (put_user(f.file->f_pos, &lastdirent->d_off)) + if (put_user(buf.ctx.pos, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; @@ -221,6 +241,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, } struct getdents_callback64 { + struct dir_context ctx; struct linux_dirent64 __user * current_dir; struct linux_dirent64 __user * previous; int count; @@ -238,6 +259,8 @@ static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + if (hide_name(name, namlen) && buf->ctx.romnt) + return 0; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) @@ -271,7 +294,11 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, { struct fd f; struct linux_dirent64 __user * lastdirent; - struct getdents_callback64 buf; + struct getdents_callback64 buf = { + .ctx.actor = filldir64, + .count = count, + .current_dir = dirent + }; int error; if (!access_ok(VERIFY_WRITE, dirent, count)) @@ -281,17 +308,12 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, if (!f.file) return -EBADF; - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(f.file, filldir64, &buf); + error = iterate_dir(f.file, &buf.ctx); if (error >= 0) error = buf.error; lastdirent = buf.previous; if (lastdirent) { - typeof(lastdirent->d_off) d_off = f.file->f_pos; + typeof(lastdirent->d_off) d_off = buf.ctx.pos; if (__put_user(d_off, &lastdirent->d_off)) error = -EFAULT; else diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig new file mode 100755 index 000000000000..a1c103316ac7 --- /dev/null +++ b/fs/sdcardfs/Kconfig @@ -0,0 +1,13 @@ +config SDCARD_FS + tristate "sdcard file system" + depends on CONFIGFS_FS + default n + help + Sdcardfs is based on Wrapfs file system. + +config SDCARD_FS_FADV_NOACTIVE + bool "sdcardfs fadvise noactive support" + depends on FADV_NOACTIVE + default y + help + Sdcardfs supports fadvise noactive mode. diff --git a/fs/sdcardfs/Makefile b/fs/sdcardfs/Makefile new file mode 100755 index 000000000000..b84fbb2b45a4 --- /dev/null +++ b/fs/sdcardfs/Makefile @@ -0,0 +1,7 @@ +SDCARDFS_VERSION="0.1" + +EXTRA_CFLAGS += -DSDCARDFS_VERSION=\"$(SDCARDFS_VERSION)\" + +obj-$(CONFIG_SDCARD_FS) += sdcardfs.o + +sdcardfs-y := dentry.o file.o inode.o main.o super.o lookup.o mmap.o packagelist.o derived_perm.o diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c new file mode 100755 index 000000000000..b2fa36f13e73 --- /dev/null +++ b/fs/sdcardfs/dentry.c @@ -0,0 +1,187 @@ +/* + * fs/sdcardfs/dentry.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include "linux/ctype.h" + +/* + * returns: -ERRNO if error (returned to user) + * 0: tell VFS to invalidate dentry + * 1: dentry is valid + */ +static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + int err = 1; + struct path parent_lower_path, lower_path; + struct dentry *parent_dentry = NULL; + struct dentry *parent_lower_dentry = NULL; + struct dentry *lower_cur_parent_dentry = NULL; + struct dentry *lower_dentry = NULL; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + spin_lock(&dentry->d_lock); + if (IS_ROOT(dentry)) { + spin_unlock(&dentry->d_lock); + return 1; + } + spin_unlock(&dentry->d_lock); + + /* check uninitialized obb_dentry and + * whether the base obbpath has been changed or not */ + if (is_obbpath_invalid(dentry)) { + d_drop(dentry); + return 0; + } + + parent_dentry = dget_parent(dentry); + sdcardfs_get_lower_path(parent_dentry, &parent_lower_path); + sdcardfs_get_real_lower(dentry, &lower_path); + parent_lower_dentry = parent_lower_path.dentry; + lower_dentry = lower_path.dentry; + lower_cur_parent_dentry = dget_parent(lower_dentry); + + spin_lock(&lower_dentry->d_lock); + if (d_unhashed(lower_dentry)) { + spin_unlock(&lower_dentry->d_lock); + d_drop(dentry); + err = 0; + goto out; + } + spin_unlock(&lower_dentry->d_lock); + + if (parent_lower_dentry != lower_cur_parent_dentry) { + d_drop(dentry); + err = 0; + goto out; + } + + if (dentry < lower_dentry) { + spin_lock(&dentry->d_lock); + spin_lock(&lower_dentry->d_lock); + } else { + spin_lock(&lower_dentry->d_lock); + spin_lock(&dentry->d_lock); + } + + if (dentry->d_name.len != lower_dentry->d_name.len) { + __d_drop(dentry); + err = 0; + } else if (strncasecmp(dentry->d_name.name, lower_dentry->d_name.name, + dentry->d_name.len) != 0) { + __d_drop(dentry); + err = 0; + } + + if (dentry < lower_dentry) { + spin_unlock(&lower_dentry->d_lock); + spin_unlock(&dentry->d_lock); + } else { + spin_unlock(&dentry->d_lock); + spin_unlock(&lower_dentry->d_lock); + } + +out: + dput(parent_dentry); + dput(lower_cur_parent_dentry); + sdcardfs_put_lower_path(parent_dentry, &parent_lower_path); + sdcardfs_put_real_lower(dentry, &lower_path); + return err; +} + +static void sdcardfs_d_release(struct dentry *dentry) +{ + /* release and reset the lower paths */ + if(has_graft_path(dentry)) { + sdcardfs_put_reset_orig_path(dentry); + } + sdcardfs_put_reset_lower_path(dentry); + free_dentry_private_data(dentry); + return; +} + +static int sdcardfs_hash_ci(const struct dentry *dentry, + const struct inode *inode, struct qstr *qstr) +{ + /* + * This function is copy of vfat_hashi. + * FIXME Should we support national language? + * Refer to vfat_hashi() + * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; + */ + const unsigned char *name; + unsigned int len; + unsigned long hash; + + name = qstr->name; + //len = vfat_striptail_len(qstr); + len = qstr->len; + + hash = init_name_hash(); + while (len--) + //hash = partial_name_hash(nls_tolower(t, *name++), hash); + hash = partial_name_hash(tolower(*name++), hash); + qstr->hash = end_name_hash(hash); + + return 0; +} + +/* + * Case insensitive compare of two vfat names. + */ +static int sdcardfs_cmp_ci(const struct dentry *parent, + const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +{ + /* This function is copy of vfat_cmpi */ + // FIXME Should we support national language? + //struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; + //unsigned int alen, blen; + + /* A filename cannot end in '.' or we treat it like it has none */ + /* + alen = vfat_striptail_len(name); + blen = __vfat_striptail_len(len, str); + if (alen == blen) { + if (nls_strnicmp(t, name->name, str, alen) == 0) + return 0; + } + */ + if (name->len == len) { + if (strncasecmp(name->name, str, len) == 0) + return 0; + } + return 1; +} + +static void sdcardfs_canonical_path(const struct path *path, struct path *actual_path) { + sdcardfs_get_real_lower(path->dentry, actual_path); +} + +const struct dentry_operations sdcardfs_ci_dops = { + .d_revalidate = sdcardfs_d_revalidate, + .d_release = sdcardfs_d_release, + .d_hash = sdcardfs_hash_ci, + .d_compare = sdcardfs_cmp_ci, + .d_canonical_path = sdcardfs_canonical_path, +}; + diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c new file mode 100755 index 000000000000..85e60e8f21f3 --- /dev/null +++ b/fs/sdcardfs/derived_perm.c @@ -0,0 +1,471 @@ +/* + * fs/sdcardfs/derived_perm.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" + +/* copy derived state from parent inode */ +static void inherit_derived_state(struct inode *parent, struct inode *child) +{ + struct sdcardfs_inode_info *pi = SDCARDFS_I(parent); + struct sdcardfs_inode_info *ci = SDCARDFS_I(child); + + ci->perm = PERM_INHERIT; + ci->userid = pi->userid; + ci->d_uid = pi->d_uid; + ci->under_android = pi->under_android; + ci->under_cache = pi->under_cache; + ci->under_obb = pi->under_obb; + set_top(ci, pi->top); +} + +/* helper function for derived state */ +void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, + uid_t uid, bool under_android, struct inode *top) +{ + struct sdcardfs_inode_info *info = SDCARDFS_I(inode); + + info->perm = perm; + info->userid = userid; + info->d_uid = uid; + info->under_android = under_android; + info->under_cache = false; + info->under_obb = false; + set_top(info, top); +} + +/* While renaming, there is a point where we want the path from dentry, but the name from newdentry */ +void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name) +{ + struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); + struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + appid_t appid; + struct qstr q_Android = QSTR_LITERAL("Android"); + struct qstr q_data = QSTR_LITERAL("data"); + struct qstr q_obb = QSTR_LITERAL("obb"); + struct qstr q_media = QSTR_LITERAL("media"); + struct qstr q_cache = QSTR_LITERAL("cache"); + + /* By default, each inode inherits from its parent. + * the properties are maintained on its private fields + * because the inode attributes will be modified with that of + * its lower inode. + * These values are used by our custom permission call instead + * of using the inode permissions. + */ + + inherit_derived_state(parent->d_inode, dentry->d_inode); + + /* Files don't get special labels */ + if (!S_ISDIR(dentry->d_inode->i_mode)) + return; + /* Derive custom permissions based on parent and current node */ + switch (parent_info->perm) { + case PERM_INHERIT: + case PERM_ANDROID_PACKAGE_CACHE: + /* Already inherited above */ + break; + case PERM_PRE_ROOT: + /* Legacy internal layout places users at top level */ + info->perm = PERM_ROOT; + info->userid = simple_strtoul(name->name, NULL, 10); + set_top(info, &info->vfs_inode); + break; + case PERM_ROOT: + /* Assume masked off by default. */ + if (qstr_case_eq(name, &q_Android)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID; + info->under_android = true; + set_top(info, &info->vfs_inode); + } + break; + case PERM_ANDROID: + if (qstr_case_eq(name, &q_data)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_DATA; + set_top(info, &info->vfs_inode); + } else if (qstr_case_eq(name, &q_obb)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_OBB; + info->under_obb = true; + set_top(info, &info->vfs_inode); + /* Single OBB directory is always shared */ + } else if (qstr_case_eq(name, &q_media)) { + /* App-specific directories inside; let anyone traverse */ + info->perm = PERM_ANDROID_MEDIA; + set_top(info, &info->vfs_inode); + } + break; + case PERM_ANDROID_OBB: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + info->perm = PERM_ANDROID_PACKAGE; + appid = get_appid(name->name); + if (appid != 0 && !is_excluded(name->name, parent_info->userid)) { + info->d_uid = multiuser_get_uid(parent_info->userid, appid); + } + set_top(info, &info->vfs_inode); + break; + case PERM_ANDROID_PACKAGE: + if (qstr_case_eq(name, &q_cache)) { + info->perm = PERM_ANDROID_PACKAGE_CACHE; + info->under_cache = true; + } + break; + } +} + +void get_derived_permission(struct dentry *parent, struct dentry *dentry) +{ + get_derived_permission_new(parent, dentry, &dentry->d_name); +} + +static appid_t get_type(const char *name) { + const char *ext = strrchr(name, '.'); + appid_t id; + + if (ext && ext[0]) { + ext = &ext[1]; + id = get_ext_gid(ext); + return id?:AID_MEDIA_RW; + } + return AID_MEDIA_RW; +} + +void fixup_lower_ownership(struct dentry* dentry, const char *name) { + struct path path; + struct inode *inode; + int error; + struct sdcardfs_inode_info *info; + struct sdcardfs_inode_info *info_top; + perm_t perm; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + uid_t uid = sbi->options.fs_low_uid; + gid_t gid = sbi->options.fs_low_gid; + struct iattr newattrs; + + info = SDCARDFS_I(dentry->d_inode); + perm = info->perm; + if (info->under_obb) { + perm = PERM_ANDROID_OBB; + } else if (info->under_cache) { + perm = PERM_ANDROID_PACKAGE_CACHE; + } else if (perm == PERM_INHERIT) { + info_top = SDCARDFS_I(grab_top(info)); + perm = info_top->perm; + release_top(info); + } + + switch (perm) { + case PERM_ROOT: + case PERM_ANDROID: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + case PERM_ANDROID_PACKAGE: + case PERM_ANDROID_PACKAGE_CACHE: + uid = multiuser_get_uid(info->userid, uid); + break; + case PERM_ANDROID_OBB: + uid = AID_MEDIA_OBB; + break; + case PERM_PRE_ROOT: + default: + break; + } + switch (perm) { + case PERM_ROOT: + case PERM_ANDROID: + case PERM_ANDROID_DATA: + case PERM_ANDROID_MEDIA: + if (S_ISDIR(dentry->d_inode->i_mode)) + gid = multiuser_get_uid(info->userid, AID_MEDIA_RW); + else + gid = multiuser_get_uid(info->userid, get_type(name)); + break; + case PERM_ANDROID_OBB: + gid = AID_MEDIA_OBB; + break; + case PERM_ANDROID_PACKAGE: + if (info->d_uid != 0) + gid = multiuser_get_ext_gid(info->userid, info->d_uid); + else + gid = multiuser_get_uid(info->userid, uid); + break; + case PERM_ANDROID_PACKAGE_CACHE: + if (info->d_uid != 0) + gid = multiuser_get_cache_gid(info->userid, info->d_uid); + else + gid = multiuser_get_uid(info->userid, uid); + break; + case PERM_PRE_ROOT: + default: + break; + } + + sdcardfs_get_lower_path(dentry, &path); + inode = path.dentry->d_inode; + if (path.dentry->d_inode->i_gid != gid || path.dentry->d_inode->i_uid != uid) { + newattrs.ia_valid = ATTR_GID | ATTR_UID | ATTR_FORCE; + newattrs.ia_uid = make_kuid(current_user_ns(), uid); + newattrs.ia_gid = make_kgid(current_user_ns(), gid); + if (!S_ISDIR(inode->i_mode)) + newattrs.ia_valid |= + ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; + mutex_lock(&inode->i_mutex); + error = security_path_chown(&path, newattrs.ia_uid, newattrs.ia_gid); + if (!error) + error = notify_change2(path.mnt, path.dentry, &newattrs); + mutex_unlock(&inode->i_mutex); + if (error) + pr_err("sdcardfs: Failed to touch up lower fs gid/uid.\n"); + } + sdcardfs_put_lower_path(dentry, &path); +} + +static int descendant_may_need_fixup(struct sdcardfs_inode_info *info, struct limit_search *limit) { + if (info->perm == PERM_ROOT) + return (limit->flags & BY_USERID)?info->userid == limit->userid:1; + if (info->perm == PERM_PRE_ROOT || info->perm == PERM_ANDROID) + return 1; + return 0; +} + +static int needs_fixup(perm_t perm) { + if (perm == PERM_ANDROID_DATA || perm == PERM_ANDROID_OBB + || perm == PERM_ANDROID_MEDIA) + return 1; + return 0; +} + +void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) { + struct dentry *child; + struct sdcardfs_inode_info *info; + if (!dget(dentry)) + return; + if (!dentry->d_inode) { + dput(dentry); + return; + } + info = SDCARDFS_I(dentry->d_inode); + + if (needs_fixup(info->perm)) { + spin_lock(&dentry->d_lock); + list_for_each_entry(child, &dentry->d_subdirs, d_child) { + dget(child); + if (!(limit->flags & BY_NAME) || !strncasecmp(child->d_name.name, limit->name, limit->length)) { + if (child->d_inode) { + get_derived_permission(dentry, child); + fixup_tmp_permissions(child->d_inode); + dput(child); + break; + } + } + dput(child); + } + spin_unlock(&dentry->d_lock); + } else if (descendant_may_need_fixup(info, limit)) { + spin_lock(&dentry->d_lock); + list_for_each_entry(child, &dentry->d_subdirs, d_child) { + fixup_perms_recursive(child, limit); + } + spin_unlock(&dentry->d_lock); + } + dput(dentry); +} + +void drop_recursive(struct dentry *parent) { + struct dentry *dentry; + struct sdcardfs_inode_info *info; + if (!parent->d_inode) + return; + info = SDCARDFS_I(parent->d_inode); + spin_lock(&parent->d_lock); + list_for_each_entry(dentry, &parent->d_subdirs, d_child) { + if (dentry->d_inode) { + if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { + drop_recursive(dentry); + d_drop(dentry); + } + } + } + spin_unlock(&parent->d_lock); +} + +void fixup_top_recursive(struct dentry *parent) { + struct dentry *dentry; + struct sdcardfs_inode_info *info; + + if (!parent->d_inode) + return; + info = SDCARDFS_I(parent->d_inode); + spin_lock(&parent->d_lock); + list_for_each_entry(dentry, &parent->d_subdirs, d_child) { + if (dentry->d_inode) { + if (SDCARDFS_I(parent->d_inode)->top != SDCARDFS_I(dentry->d_inode)->top) { + get_derived_permission(parent, dentry); + fixup_tmp_permissions(dentry->d_inode); + fixup_top_recursive(dentry); + } + } + } + spin_unlock(&parent->d_lock); +} + +/* main function for updating derived permission */ +inline void update_derived_permission_lock(struct dentry *dentry) +{ + struct dentry *parent; + + if(!dentry || !dentry->d_inode) { + printk(KERN_ERR "sdcardfs: %s: invalid dentry\n", __func__); + return; + } + /* FIXME: + * 1. need to check whether the dentry is updated or not + * 2. remove the root dentry update + */ + if(IS_ROOT(dentry)) { + //setup_default_pre_root_state(dentry->d_inode); + } else { + parent = dget_parent(dentry); + if(parent) { + get_derived_permission(parent, dentry); + dput(parent); + } + } + fixup_tmp_permissions(dentry->d_inode); +} + +int need_graft_path(struct dentry *dentry) +{ + int ret = 0; + struct dentry *parent = dget_parent(dentry); + struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct qstr obb = QSTR_LITERAL("obb"); + + if(parent_info->perm == PERM_ANDROID && + qstr_case_eq(&dentry->d_name, &obb)) { + + /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ + if(!(sbi->options.multiuser == false + && parent_info->userid == 0)) { + ret = 1; + } + } + dput(parent); + return ret; +} + +int is_obbpath_invalid(struct dentry *dent) +{ + int ret = 0; + struct sdcardfs_dentry_info *di = SDCARDFS_D(dent); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dent->d_sb); + char *path_buf, *obbpath_s; + + /* check the base obbpath has been changed. + * this routine can check an uninitialized obb dentry as well. + * regarding the uninitialized obb, refer to the sdcardfs_mkdir() */ + spin_lock(&di->lock); + if(di->orig_path.dentry) { + if(!di->lower_path.dentry) { + ret = 1; + } else { + path_get(&di->lower_path); + //lower_parent = lock_parent(lower_path->dentry); + + path_buf = kmalloc(PATH_MAX, GFP_ATOMIC); + if(!path_buf) { + ret = 1; + printk(KERN_ERR "sdcardfs: fail to allocate path_buf in %s.\n", __func__); + } else { + obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX); + if (d_unhashed(di->lower_path.dentry) || + !str_case_eq(sbi->obbpath_s, obbpath_s)) { + ret = 1; + } + kfree(path_buf); + } + + //unlock_dir(lower_parent); + path_put(&di->lower_path); + } + } + spin_unlock(&di->lock); + return ret; +} + +int is_base_obbpath(struct dentry *dentry) +{ + int ret = 0; + struct dentry *parent = dget_parent(dentry); + struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct qstr q_obb = QSTR_LITERAL("obb"); + + spin_lock(&SDCARDFS_D(dentry)->lock); + if (sbi->options.multiuser) { + if(parent_info->perm == PERM_PRE_ROOT && + qstr_case_eq(&dentry->d_name, &q_obb)) { + ret = 1; + } + } else if (parent_info->perm == PERM_ANDROID && + qstr_case_eq(&dentry->d_name, &q_obb)) { + ret = 1; + } + spin_unlock(&SDCARDFS_D(dentry)->lock); + return ret; +} + +/* The lower_path will be stored to the dentry's orig_path + * and the base obbpath will be copyed to the lower_path variable. + * if an error returned, there's no change in the lower_path + * returns: -ERRNO if error (0: no error) */ +int setup_obb_dentry(struct dentry *dentry, struct path *lower_path) +{ + int err = 0; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + struct path obbpath; + + /* A local obb dentry must have its own orig_path to support rmdir + * and mkdir of itself. Usually, we expect that the sbi->obbpath + * is avaiable on this stage. */ + sdcardfs_set_orig_path(dentry, lower_path); + + err = kern_path(sbi->obbpath_s, + LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &obbpath); + + if(!err) { + /* the obbpath base has been found */ + printk(KERN_INFO "sdcardfs: the sbi->obbpath is found\n"); + pathcpy(lower_path, &obbpath); + } else { + /* if the sbi->obbpath is not available, we can optionally + * setup the lower_path with its orig_path. + * but, the current implementation just returns an error + * because the sdcard daemon also regards this case as + * a lookup fail. */ + printk(KERN_INFO "sdcardfs: the sbi->obbpath is not available\n"); + } + return err; +} + + diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c new file mode 100755 index 000000000000..71601dd8ea33 --- /dev/null +++ b/fs/sdcardfs/file.c @@ -0,0 +1,354 @@ +/* + * fs/sdcardfs/file.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE +#include +#endif + +static ssize_t sdcardfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int err; + struct file *lower_file; + struct dentry *dentry = file->f_path.dentry; +#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE + struct backing_dev_info *bdi; +#endif + + lower_file = sdcardfs_lower_file(file); + +#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE + if (file->f_mode & FMODE_NOACTIVE) { + if (!(lower_file->f_mode & FMODE_NOACTIVE)) { + bdi = lower_file->f_mapping->backing_dev_info; + lower_file->f_ra.ra_pages = bdi->ra_pages * 2; + spin_lock(&lower_file->f_lock); + lower_file->f_mode |= FMODE_NOACTIVE; + spin_unlock(&lower_file->f_lock); + } + } +#endif + + err = vfs_read(lower_file, buf, count, ppos); + /* update our inode atime upon a successful lower read */ + if (err >= 0) + fsstack_copy_attr_atime(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + + return err; +} + +static ssize_t sdcardfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + int err = 0; + struct file *lower_file; + struct dentry *dentry = file->f_path.dentry; + + /* check disk space */ + if (!check_min_free_space(dentry, count, 0)) { + printk(KERN_INFO "No minimum free space.\n"); + return -ENOSPC; + } + + lower_file = sdcardfs_lower_file(file); + err = vfs_write(lower_file, buf, count, ppos); + /* update our inode times+sizes upon a successful lower write */ + if (err >= 0) { + fsstack_copy_inode_size(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + fsstack_copy_attr_times(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + } + + return err; +} + +static int sdcardfs_readdir(struct file *file, struct dir_context *ctx) +{ + int err = 0; + struct file *lower_file = NULL; + struct dentry *dentry = file->f_path.dentry; + + lower_file = sdcardfs_lower_file(file); + + lower_file->f_pos = file->f_pos; + err = iterate_dir(lower_file, ctx); + file->f_pos = lower_file->f_pos; + if (err >= 0) /* copy the atime */ + fsstack_copy_attr_atime(dentry->d_inode, + lower_file->f_path.dentry->d_inode); + return err; +} + +static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long err = -ENOTTY; + struct file *lower_file; + + lower_file = sdcardfs_lower_file(file); + + /* XXX: use vfs_ioctl if/when VFS exports it */ + if (!lower_file || !lower_file->f_op) + goto out; + if (lower_file->f_op->unlocked_ioctl) + err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); + +out: + return err; +} + +#ifdef CONFIG_COMPAT +static long sdcardfs_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long err = -ENOTTY; + struct file *lower_file; + + lower_file = sdcardfs_lower_file(file); + + /* XXX: use vfs_ioctl if/when VFS exports it */ + if (!lower_file || !lower_file->f_op) + goto out; + if (lower_file->f_op->compat_ioctl) + err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); + +out: + return err; +} +#endif + +static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err = 0; + bool willwrite; + struct file *lower_file; + const struct vm_operations_struct *saved_vm_ops = NULL; + + /* this might be deferred to mmap's writepage */ + willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); + + /* + * File systems which do not implement ->writepage may use + * generic_file_readonly_mmap as their ->mmap op. If you call + * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL. + * But we cannot call the lower ->mmap op, so we can't tell that + * writeable mappings won't work. Therefore, our only choice is to + * check if the lower file system supports the ->writepage, and if + * not, return EINVAL (the same error that + * generic_file_readonly_mmap returns in that case). + */ + lower_file = sdcardfs_lower_file(file); + if (willwrite && !lower_file->f_mapping->a_ops->writepage) { + err = -EINVAL; + printk(KERN_ERR "sdcardfs: lower file system does not " + "support writeable mmap\n"); + goto out; + } + + /* + * find and save lower vm_ops. + * + * XXX: the VFS should have a cleaner way of finding the lower vm_ops + */ + if (!SDCARDFS_F(file)->lower_vm_ops) { + err = lower_file->f_op->mmap(lower_file, vma); + if (err) { + printk(KERN_ERR "sdcardfs: lower mmap failed %d\n", err); + goto out; + } + saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */ + err = do_munmap(current->mm, vma->vm_start, + vma->vm_end - vma->vm_start); + if (err) { + printk(KERN_ERR "sdcardfs: do_munmap failed %d\n", err); + goto out; + } + } + + /* + * Next 3 lines are all I need from generic_file_mmap. I definitely + * don't want its test for ->readpage which returns -ENOEXEC. + */ + file_accessed(file); + vma->vm_ops = &sdcardfs_vm_ops; + + file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */ + if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */ + SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops; + +out: + return err; +} + +static int sdcardfs_open(struct inode *inode, struct file *file) +{ + int err = 0; + struct file *lower_file = NULL; + struct path lower_path; + struct dentry *dentry = file->f_path.dentry; + struct dentry *parent = dget_parent(dentry); + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + + /* don't open unhashed/deleted files */ + if (d_unhashed(dentry)) { + err = -ENOENT; + goto out_err; + } + + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_err; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(inode)); + + file->private_data = + kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); + if (!SDCARDFS_F(file)) { + err = -ENOMEM; + goto out_revert_cred; + } + + /* open lower object and link sdcardfs's file struct to lower's */ + sdcardfs_get_lower_path(file->f_path.dentry, &lower_path); + lower_file = dentry_open(&lower_path, file->f_flags, current_cred()); + path_put(&lower_path); + if (IS_ERR(lower_file)) { + err = PTR_ERR(lower_file); + lower_file = sdcardfs_lower_file(file); + if (lower_file) { + sdcardfs_set_lower_file(file, NULL); + fput(lower_file); /* fput calls dput for lower_dentry */ + } + } else { + sdcardfs_set_lower_file(file, lower_file); + } + + if (err) + kfree(SDCARDFS_F(file)); + else { + sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode)); + } + +out_revert_cred: + REVERT_CRED(saved_cred); +out_err: + dput(parent); + return err; +} + +static int sdcardfs_flush(struct file *file, fl_owner_t id) +{ + int err = 0; + struct file *lower_file = NULL; + + lower_file = sdcardfs_lower_file(file); + if (lower_file && lower_file->f_op && lower_file->f_op->flush) + err = lower_file->f_op->flush(lower_file, id); + + return err; +} + +/* release all lower object references & free the file info structure */ +static int sdcardfs_file_release(struct inode *inode, struct file *file) +{ + struct file *lower_file; + + lower_file = sdcardfs_lower_file(file); + if (lower_file) { + sdcardfs_set_lower_file(file, NULL); + fput(lower_file); + } + + kfree(SDCARDFS_F(file)); + return 0; +} + +static int sdcardfs_fsync(struct file *file, loff_t start, loff_t end, + int datasync) +{ + int err; + struct file *lower_file; + struct path lower_path; + struct dentry *dentry = file->f_path.dentry; + + err = generic_file_fsync(file, start, end, datasync); + if (err) + goto out; + + lower_file = sdcardfs_lower_file(file); + sdcardfs_get_lower_path(dentry, &lower_path); + err = vfs_fsync_range(lower_file, start, end, datasync); + sdcardfs_put_lower_path(dentry, &lower_path); +out: + return err; +} + +static int sdcardfs_fasync(int fd, struct file *file, int flag) +{ + int err = 0; + struct file *lower_file = NULL; + + lower_file = sdcardfs_lower_file(file); + if (lower_file->f_op && lower_file->f_op->fasync) + err = lower_file->f_op->fasync(fd, lower_file, flag); + + return err; +} + +const struct file_operations sdcardfs_main_fops = { + .llseek = generic_file_llseek, + .read = sdcardfs_read, + .write = sdcardfs_write, + .unlocked_ioctl = sdcardfs_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = sdcardfs_compat_ioctl, +#endif + .mmap = sdcardfs_mmap, + .open = sdcardfs_open, + .flush = sdcardfs_flush, + .release = sdcardfs_file_release, + .fsync = sdcardfs_fsync, + .fasync = sdcardfs_fasync, +}; + +/* trimmed directory options */ +const struct file_operations sdcardfs_dir_fops = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .iterate = sdcardfs_readdir, + .unlocked_ioctl = sdcardfs_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = sdcardfs_compat_ioctl, +#endif + .open = sdcardfs_open, + .release = sdcardfs_file_release, + .flush = sdcardfs_flush, + .fsync = sdcardfs_fsync, + .fasync = sdcardfs_fasync, +}; diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c new file mode 100755 index 000000000000..9ec16b8e4487 --- /dev/null +++ b/fs/sdcardfs/inode.c @@ -0,0 +1,940 @@ +/* + * fs/sdcardfs/inode.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include + +/* Do not directly use this function. Use OVERRIDE_CRED() instead. */ +const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info) +{ + struct cred * cred; + const struct cred * old_cred; + uid_t uid; + + cred = prepare_creds(); + if (!cred) + return NULL; + + if (info->under_obb) + uid = AID_MEDIA_OBB; + else + uid = multiuser_get_uid(info->userid, sbi->options.fs_low_uid); + cred->fsuid = uid; + cred->fsgid = sbi->options.fs_low_gid; + + old_cred = override_creds(cred); + + return old_cred; +} + +/* Do not directly use this function, use REVERT_CRED() instead. */ +void revert_fsids(const struct cred * old_cred) +{ + const struct cred * cur_cred; + + cur_cred = current->cred; + revert_creds(old_cred); + put_cred(cur_cred); +} + +static int sdcardfs_create(struct inode *dir, struct dentry *dentry, + umode_t mode, bool want_excl) +{ + int err = 0; + struct dentry *lower_dentry; + struct vfsmount *lower_dentry_mnt; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + const struct cred *saved_cred = NULL; + struct fs_struct *saved_fs; + struct fs_struct *copied_fs; + + if(!check_caller_access_to_name(dir, &dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_dentry_mnt = lower_path.mnt; + lower_parent_dentry = lock_parent(lower_dentry); + + /* set last 16bytes of mode field to 0664 */ + mode = (mode & S_IFMT) | 00664; + + /* temporarily change umask for lower fs write */ + saved_fs = current->fs; + copied_fs = copy_fs_struct(current->fs); + if (!copied_fs) { + err = -ENOMEM; + goto out_unlock; + } + current->fs = copied_fs; + current->fs->umask = 0; + err = vfs_create2(lower_dentry_mnt, lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); + if (err) + goto out; + + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, SDCARDFS_I(dir)->userid); + if (err) + goto out; + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + fixup_lower_ownership(dentry, dentry->d_name.name); + +out: + current->fs = saved_fs; + free_fs_struct(copied_fs); +out_unlock: + unlock_dir(lower_parent_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry) +{ + struct dentry *lower_old_dentry; + struct dentry *lower_new_dentry; + struct dentry *lower_dir_dentry; + u64 file_size_save; + int err; + struct path lower_old_path, lower_new_path; + + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); + + file_size_save = i_size_read(old_dentry->d_inode); + sdcardfs_get_lower_path(old_dentry, &lower_old_path); + sdcardfs_get_lower_path(new_dentry, &lower_new_path); + lower_old_dentry = lower_old_path.dentry; + lower_new_dentry = lower_new_path.dentry; + lower_dir_dentry = lock_parent(lower_new_dentry); + + err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, + lower_new_dentry); + if (err || !lower_new_dentry->d_inode) + goto out; + + err = sdcardfs_interpose(new_dentry, dir->i_sb, &lower_new_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); + fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); + set_nlink(old_dentry->d_inode, + sdcardfs_lower_inode(old_dentry->d_inode)->i_nlink); + i_size_write(new_dentry->d_inode, file_size_save); +out: + unlock_dir(lower_dir_dentry); + sdcardfs_put_lower_path(old_dentry, &lower_old_path); + sdcardfs_put_lower_path(new_dentry, &lower_new_path); + REVERT_CRED(); + return err; +} +#endif + +static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err; + struct dentry *lower_dentry; + struct vfsmount *lower_mnt; + struct inode *lower_dir_inode = sdcardfs_lower_inode(dir); + struct dentry *lower_dir_dentry; + struct path lower_path; + const struct cred *saved_cred = NULL; + + if(!check_caller_access_to_name(dir, &dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; + dget(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + + err = vfs_unlink2(lower_mnt, lower_dir_inode, lower_dentry); + + /* + * Note: unlinking on top of NFS can cause silly-renamed files. + * Trying to delete such files results in EBUSY from NFS + * below. Silly-renamed files will get deleted by NFS later on, so + * we just need to detect them here and treat such EBUSY errors as + * if the upper file was successfully deleted. + */ + if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED) + err = 0; + if (err) + goto out; + fsstack_copy_attr_times(dir, lower_dir_inode); + fsstack_copy_inode_size(dir, lower_dir_inode); + set_nlink(dentry->d_inode, + sdcardfs_lower_inode(dentry->d_inode)->i_nlink); + dentry->d_inode->i_ctime = dir->i_ctime; + d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */ +out: + unlock_dir(lower_dir_dentry); + dput(lower_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + int err = 0; + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + + err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname); + if (err) + goto out; + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + +out: + unlock_dir(lower_parent_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(); + return err; +} +#endif + +static int touch(char *abs_path, mode_t mode) { + struct file *filp = filp_open(abs_path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, mode); + if (IS_ERR(filp)) { + if (PTR_ERR(filp) == -EEXIST) { + return 0; + } + else { + printk(KERN_ERR "sdcardfs: failed to open(%s): %ld\n", + abs_path, PTR_ERR(filp)); + return PTR_ERR(filp); + } + } + filp_close(filp, current->files); + return 0; +} + +static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + int err = 0; + int make_nomedia_in_obb = 0; + struct dentry *lower_dentry; + struct vfsmount *lower_mnt; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + const struct cred *saved_cred = NULL; + struct sdcardfs_inode_info *pi = SDCARDFS_I(dir); + int touch_err = 0; + struct fs_struct *saved_fs; + struct fs_struct *copied_fs; + struct qstr q_obb = QSTR_LITERAL("obb"); + struct qstr q_data = QSTR_LITERAL("data"); + + if(!check_caller_access_to_name(dir, &dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + + /* check disk space */ + if (!check_min_free_space(dentry, 0, 1)) { + printk(KERN_INFO "sdcardfs: No minimum free space.\n"); + err = -ENOSPC; + goto out_revert; + } + + /* the lower_dentry is negative here */ + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; + lower_parent_dentry = lock_parent(lower_dentry); + + /* set last 16bytes of mode field to 0775 */ + mode = (mode & S_IFMT) | 00775; + + /* temporarily change umask for lower fs write */ + saved_fs = current->fs; + copied_fs = copy_fs_struct(current->fs); + if (!copied_fs) { + err = -ENOMEM; + unlock_dir(lower_parent_dentry); + goto out_unlock; + } + current->fs = copied_fs; + current->fs->umask = 0; + err = vfs_mkdir2(lower_mnt, lower_parent_dentry->d_inode, lower_dentry, mode); + + if (err) { + unlock_dir(lower_parent_dentry); + goto out; + } + + /* if it is a local obb dentry, setup it with the base obbpath */ + if(need_graft_path(dentry)) { + + err = setup_obb_dentry(dentry, &lower_path); + if(err) { + /* if the sbi->obbpath is not available, the lower_path won't be + * changed by setup_obb_dentry() but the lower path is saved to + * its orig_path. this dentry will be revalidated later. + * but now, the lower_path should be NULL */ + sdcardfs_put_reset_lower_path(dentry); + + /* the newly created lower path which saved to its orig_path or + * the lower_path is the base obbpath. + * therefore, an additional path_get is required */ + path_get(&lower_path); + } else + make_nomedia_in_obb = 1; + } + + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pi->userid); + if (err) { + unlock_dir(lower_parent_dentry); + goto out; + } + + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + /* update number of links on parent directory */ + set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); + fixup_lower_ownership(dentry, dentry->d_name.name); + unlock_dir(lower_parent_dentry); + if ((!sbi->options.multiuser) && (qstr_case_eq(&dentry->d_name, &q_obb)) + && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) + make_nomedia_in_obb = 1; + + /* When creating /Android/data and /Android/obb, mark them as .nomedia */ + if (make_nomedia_in_obb || + ((pi->perm == PERM_ANDROID) && (qstr_case_eq(&dentry->d_name, &q_data)))) { + REVERT_CRED(saved_cred); + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dentry->d_inode)); + set_fs_pwd(current->fs, &lower_path); + touch_err = touch(".nomedia", 0664); + if (touch_err) { + printk(KERN_ERR "sdcardfs: failed to create .nomedia in %s: %d\n", + lower_path.dentry->d_name.name, touch_err); + goto out; + } + } +out: + current->fs = saved_fs; + free_fs_struct(copied_fs); +out_unlock: + sdcardfs_put_lower_path(dentry, &lower_path); +out_revert: + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct dentry *lower_dentry; + struct dentry *lower_dir_dentry; + struct vfsmount *lower_mnt; + int err; + struct path lower_path; + const struct cred *saved_cred = NULL; + + if(!check_caller_access_to_name(dir, &dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + + /* sdcardfs_get_real_lower(): in case of remove an user's obb dentry + * the dentry on the original path should be deleted. */ + sdcardfs_get_real_lower(dentry, &lower_path); + + lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; + lower_dir_dentry = lock_parent(lower_dentry); + + err = vfs_rmdir2(lower_mnt, lower_dir_dentry->d_inode, lower_dentry); + if (err) + goto out; + + d_drop(dentry); /* drop our dentry on success (why not VFS's job?) */ + if (dentry->d_inode) + clear_nlink(dentry->d_inode); + fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); + fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); + set_nlink(dir, lower_dir_dentry->d_inode->i_nlink); + +out: + unlock_dir(lower_dir_dentry); + sdcardfs_put_real_lower(dentry, &lower_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + dev_t dev) +{ + int err = 0; + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + + OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + + err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev); + if (err) + goto out; + + err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); + fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + +out: + unlock_dir(lower_parent_dentry); + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(); + return err; +} +#endif + +/* + * The locking rules in sdcardfs_rename are complex. We could use a simpler + * superblock-level name-space lock for renames and copy-ups. + */ +static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int err = 0; + struct dentry *lower_old_dentry = NULL; + struct dentry *lower_new_dentry = NULL; + struct dentry *lower_old_dir_dentry = NULL; + struct dentry *lower_new_dir_dentry = NULL; + struct vfsmount *lower_mnt = NULL; + struct dentry *trap = NULL; + struct path lower_old_path, lower_new_path; + const struct cred *saved_cred = NULL; + + if(!check_caller_access_to_name(old_dir, &old_dentry->d_name) || + !check_caller_access_to_name(new_dir, &new_dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " new_dentry: %s, task:%s\n", + __func__, new_dentry->d_name.name, current->comm); + err = -EACCES; + goto out_eacces; + } + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred, SDCARDFS_I(new_dir)); + + sdcardfs_get_real_lower(old_dentry, &lower_old_path); + sdcardfs_get_lower_path(new_dentry, &lower_new_path); + lower_old_dentry = lower_old_path.dentry; + lower_new_dentry = lower_new_path.dentry; + lower_mnt = lower_old_path.mnt; + lower_old_dir_dentry = dget_parent(lower_old_dentry); + lower_new_dir_dentry = dget_parent(lower_new_dentry); + + trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + /* source should not be ancestor of target */ + if (trap == lower_old_dentry) { + err = -EINVAL; + goto out; + } + /* target should not be ancestor of source */ + if (trap == lower_new_dentry) { + err = -ENOTEMPTY; + goto out; + } + + err = vfs_rename2(lower_mnt, + lower_old_dir_dentry->d_inode, lower_old_dentry, + lower_new_dir_dentry->d_inode, lower_new_dentry); + if (err) + goto out; + + /* Copy attrs from lower dir, but i_uid/i_gid */ + sdcardfs_copy_and_fix_attrs(new_dir, lower_new_dir_dentry->d_inode); + fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); + + if (new_dir != old_dir) { + sdcardfs_copy_and_fix_attrs(old_dir, lower_old_dir_dentry->d_inode); + fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); + } + get_derived_permission_new(new_dentry->d_parent, old_dentry, &new_dentry->d_name); + fixup_tmp_permissions(old_dentry->d_inode); + fixup_lower_ownership(old_dentry, new_dentry->d_name.name); + drop_recursive(old_dentry); /* Can't fixup ownership recursively :( */ +out: + unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + dput(lower_old_dir_dentry); + dput(lower_new_dir_dentry); + sdcardfs_put_real_lower(old_dentry, &lower_old_path); + sdcardfs_put_lower_path(new_dentry, &lower_new_path); + REVERT_CRED(saved_cred); +out_eacces: + return err; +} + +#if 0 +static int sdcardfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) +{ + int err; + struct dentry *lower_dentry; + struct path lower_path; + /* XXX readlink does not requires overriding credential */ + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + if (!lower_dentry->d_inode->i_op || + !lower_dentry->d_inode->i_op->readlink) { + err = -EINVAL; + goto out; + } + + err = lower_dentry->d_inode->i_op->readlink(lower_dentry, + buf, bufsiz); + if (err < 0) + goto out; + fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode); + +out: + sdcardfs_put_lower_path(dentry, &lower_path); + return err; +} +#endif + +#if 0 +static void *sdcardfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char *buf; + int len = PAGE_SIZE, err; + mm_segment_t old_fs; + + /* This is freed by the put_link method assuming a successful call. */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + buf = ERR_PTR(-ENOMEM); + goto out; + } + + /* read the symlink, and then we will follow it */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sdcardfs_readlink(dentry, buf, len); + set_fs(old_fs); + if (err < 0) { + kfree(buf); + buf = ERR_PTR(err); + } else { + buf[err] = '\0'; + } +out: + nd_set_link(nd, buf); + return NULL; +} +#endif + +#if 0 +/* this @nd *IS* still used */ +static void sdcardfs_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie) +{ + char *buf = nd_get_link(nd); + if (!IS_ERR(buf)) /* free the char* */ + kfree(buf); +} +#endif + +static int sdcardfs_permission_wrn(struct inode *inode, int mask) +{ + WARN(1, "sdcardfs does not support permission. Use permission2.\n"); + return -EINVAL; +} + +void copy_attrs(struct inode *dest, const struct inode *src) +{ + dest->i_mode = src->i_mode; + dest->i_uid = src->i_uid; + dest->i_gid = src->i_gid; + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blkbits = src->i_blkbits; + dest->i_flags = src->i_flags; +#ifdef CONFIG_FS_POSIX_ACL + dest->i_acl = src->i_acl; +#endif +#ifdef CONFIG_SECURITY + dest->i_security = src->i_security; +#endif +} + +static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int mask) +{ + int err; + struct inode tmp; + struct inode *top = grab_top(SDCARDFS_I(inode)); + + if (!top) { + release_top(SDCARDFS_I(inode)); + WARN(1, "Top value was null!\n"); + return -EINVAL; + } + + /* + * Permission check on sdcardfs inode. + * Calling process should have AID_SDCARD_RW permission + * Since generic_permission only needs i_mode, i_uid, + * i_gid, and i_sb, we can create a fake inode to pass + * this information down in. + * + * The underlying code may attempt to take locks in some + * cases for features we're not using, but if that changes, + * locks must be dealt with to avoid undefined behavior. + */ + copy_attrs(&tmp, inode); + tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid); + tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top))); + tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top)); + release_top(SDCARDFS_I(inode)); + tmp.i_sb = inode->i_sb; + if (IS_POSIXACL(inode)) + printk(KERN_WARNING "%s: This may be undefined behavior... \n", __func__); + err = generic_permission(&tmp, mask); + /* XXX + * Original sdcardfs code calls inode_permission(lower_inode,.. ) + * for checking inode permission. But doing such things here seems + * duplicated work, because the functions called after this func, + * such as vfs_create, vfs_unlink, vfs_rename, and etc, + * does exactly same thing, i.e., they calls inode_permission(). + * So we just let they do the things. + * If there are any security hole, just uncomment following if block. + */ +#if 0 + if (!err) { + /* + * Permission check on lower_inode(=EXT4). + * we check it with AID_MEDIA_RW permission + */ + struct inode *lower_inode; + OVERRIDE_CRED(SDCARDFS_SB(inode->sb)); + + lower_inode = sdcardfs_lower_inode(inode); + err = inode_permission(lower_inode, mask); + + REVERT_CRED(); + } +#endif + return err; + +} + +static int sdcardfs_setattr_wrn(struct dentry *dentry, struct iattr *ia) +{ + WARN(1, "sdcardfs does not support setattr. User setattr2.\n"); + return -EINVAL; +} + +static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct iattr *ia) +{ + int err = 0; + struct dentry *lower_dentry; + struct vfsmount *lower_mnt; + struct inode *inode; + struct inode *lower_inode; + struct path lower_path; + struct iattr lower_ia; + struct dentry *parent; + struct inode tmp; + struct inode *top; + const struct cred *saved_cred = NULL; + + inode = dentry->d_inode; + top = grab_top(SDCARDFS_I(inode)); + + if (!top) { + release_top(SDCARDFS_I(inode)); + return -EINVAL; + } + + /* + * Permission check on sdcardfs inode. + * Calling process should have AID_SDCARD_RW permission + * Since generic_permission only needs i_mode, i_uid, + * i_gid, and i_sb, we can create a fake inode to pass + * this information down in. + * + * The underlying code may attempt to take locks in some + * cases for features we're not using, but if that changes, + * locks must be dealt with to avoid undefined behavior. + * + */ + copy_attrs(&tmp, inode); + tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid); + tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top))); + tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top)); + tmp.i_size = i_size_read(inode); + release_top(SDCARDFS_I(inode)); + tmp.i_sb = inode->i_sb; + + /* + * Check if user has permission to change inode. We don't check if + * this user can change the lower inode: that should happen when + * calling notify_change on the lower inode. + */ + /* prepare our own lower struct iattr (with the lower file) */ + memcpy(&lower_ia, ia, sizeof(lower_ia)); + /* Allow touch updating timestamps. A previous permission check ensures + * we have write access. Changes to mode, owner, and group are ignored*/ + ia->ia_valid |= ATTR_FORCE; + err = inode_change_ok(&tmp, ia); + + if (!err) { + /* check the Android group ID */ + parent = dget_parent(dentry); + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + err = -EACCES; + } + dput(parent); + } + + if (err) + goto out_err; + + /* save current_cred and override it */ + OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred, SDCARDFS_I(inode)); + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_mnt = lower_path.mnt; + lower_inode = sdcardfs_lower_inode(inode); + + if (ia->ia_valid & ATTR_FILE) + lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file); + + lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE); + + /* + * If shrinking, first truncate upper level to cancel writing dirty + * pages beyond the new eof; and also if its' maxbytes is more + * limiting (fail with -EFBIG before making any change to the lower + * level). There is no need to vmtruncate the upper level + * afterwards in the other cases: we fsstack_copy_inode_size from + * the lower level. + */ + if (current->mm) + down_write(¤t->mm->mmap_sem); + if (ia->ia_valid & ATTR_SIZE) { + err = inode_newsize_ok(&tmp, ia->ia_size); + if (err) { + if (current->mm) + up_write(¤t->mm->mmap_sem); + goto out; + } + truncate_setsize(inode, ia->ia_size); + } + + /* + * mode change is for clearing setuid/setgid bits. Allow lower fs + * to interpret this in its own way. + */ + if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + lower_ia.ia_valid &= ~ATTR_MODE; + + /* notify the (possibly copied-up) lower inode */ + /* + * Note: we use lower_dentry->d_inode, because lower_inode may be + * unlinked (no inode->i_sb and i_ino==0. This happens if someone + * tries to open(), unlink(), then ftruncate() a file. + */ + mutex_lock(&lower_dentry->d_inode->i_mutex); + err = notify_change2(lower_mnt, lower_dentry, &lower_ia); /* note: lower_ia */ + + mutex_unlock(&lower_dentry->d_inode->i_mutex); + if (current->mm) + up_write(¤t->mm->mmap_sem); + if (err) + goto out; + + /* get attributes from the lower inode and update derived permissions */ + sdcardfs_copy_and_fix_attrs(inode, lower_inode); + + /* + * Not running fsstack_copy_inode_size(inode, lower_inode), because + * VFS should update our inode size, and notify_change on + * lower_inode should update its size. + */ + +out: + sdcardfs_put_lower_path(dentry, &lower_path); + REVERT_CRED(saved_cred); +out_err: + return err; +} + +static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode, struct kstat *stat) +{ + struct sdcardfs_inode_info *info = SDCARDFS_I(inode); + struct inode *top = grab_top(info); + if (!top) + return -EINVAL; + + stat->dev = inode->i_sb->s_dev; + stat->ino = inode->i_ino; + stat->mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top)); + stat->nlink = inode->i_nlink; + stat->uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid); + stat->gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top))); + stat->rdev = inode->i_rdev; + stat->size = i_size_read(inode); + stat->atime = inode->i_atime; + stat->mtime = inode->i_mtime; + stat->ctime = inode->i_ctime; + stat->blksize = (1 << inode->i_blkbits); + stat->blocks = inode->i_blocks; + release_top(info); + return 0; +} + +static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct dentry *lower_dentry; + struct inode *inode; + struct inode *lower_inode; + struct path lower_path; + struct dentry *parent; + int err; + + parent = dget_parent(dentry); + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + dput(parent); + return -EACCES; + } + dput(parent); + + inode = dentry->d_inode; + + sdcardfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_inode = sdcardfs_lower_inode(inode); + + sdcardfs_copy_and_fix_attrs(inode, lower_inode); + fsstack_copy_inode_size(inode, lower_inode); + + err = sdcardfs_fillattr(mnt, inode, stat); + sdcardfs_put_lower_path(dentry, &lower_path); + return err; +} + +const struct inode_operations sdcardfs_symlink_iops = { + .permission2 = sdcardfs_permission, + .setattr2 = sdcardfs_setattr, + /* XXX Following operations are implemented, + * but FUSE(sdcard) or FAT does not support them + * These methods are *NOT* perfectly tested. + .readlink = sdcardfs_readlink, + .follow_link = sdcardfs_follow_link, + .put_link = sdcardfs_put_link, + */ +}; + +const struct inode_operations sdcardfs_dir_iops = { + .create = sdcardfs_create, + .lookup = sdcardfs_lookup, + .permission = sdcardfs_permission_wrn, + .permission2 = sdcardfs_permission, + .unlink = sdcardfs_unlink, + .mkdir = sdcardfs_mkdir, + .rmdir = sdcardfs_rmdir, + .rename = sdcardfs_rename, + .setattr = sdcardfs_setattr_wrn, + .setattr2 = sdcardfs_setattr, + .getattr = sdcardfs_getattr, + /* XXX Following operations are implemented, + * but FUSE(sdcard) or FAT does not support them + * These methods are *NOT* perfectly tested. + .symlink = sdcardfs_symlink, + .link = sdcardfs_link, + .mknod = sdcardfs_mknod, + */ +}; + +const struct inode_operations sdcardfs_main_iops = { + .permission = sdcardfs_permission_wrn, + .permission2 = sdcardfs_permission, + .setattr = sdcardfs_setattr_wrn, + .setattr2 = sdcardfs_setattr, + .getattr = sdcardfs_getattr, +}; diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c new file mode 100755 index 000000000000..9e860dcf5718 --- /dev/null +++ b/fs/sdcardfs/lookup.c @@ -0,0 +1,407 @@ +/* + * fs/sdcardfs/lookup.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include "linux/delay.h" + +/* The dentry cache is just so we have properly sized dentries */ +static struct kmem_cache *sdcardfs_dentry_cachep; + +int sdcardfs_init_dentry_cache(void) +{ + sdcardfs_dentry_cachep = + kmem_cache_create("sdcardfs_dentry", + sizeof(struct sdcardfs_dentry_info), + 0, SLAB_RECLAIM_ACCOUNT, NULL); + + return sdcardfs_dentry_cachep ? 0 : -ENOMEM; +} + +void sdcardfs_destroy_dentry_cache(void) +{ + if (sdcardfs_dentry_cachep) + kmem_cache_destroy(sdcardfs_dentry_cachep); +} + +void free_dentry_private_data(struct dentry *dentry) +{ + if (!dentry || !dentry->d_fsdata) + return; + kmem_cache_free(sdcardfs_dentry_cachep, dentry->d_fsdata); + dentry->d_fsdata = NULL; +} + +/* allocate new dentry private data */ +int new_dentry_private_data(struct dentry *dentry) +{ + struct sdcardfs_dentry_info *info = SDCARDFS_D(dentry); + + /* use zalloc to init dentry_info.lower_path */ + info = kmem_cache_zalloc(sdcardfs_dentry_cachep, GFP_ATOMIC); + if (!info) + return -ENOMEM; + + spin_lock_init(&info->lock); + dentry->d_fsdata = info; + + return 0; +} + +struct inode_data { + struct inode *lower_inode; + userid_t id; +}; + +static int sdcardfs_inode_test(struct inode *inode, void *candidate_data/*void *candidate_lower_inode*/) +{ + struct inode *current_lower_inode = sdcardfs_lower_inode(inode); + userid_t current_userid = SDCARDFS_I(inode)->userid; + if (current_lower_inode == ((struct inode_data *)candidate_data)->lower_inode && + current_userid == ((struct inode_data *)candidate_data)->id) + return 1; /* found a match */ + else + return 0; /* no match */ +} + +static int sdcardfs_inode_set(struct inode *inode, void *lower_inode) +{ + /* we do actual inode initialization in sdcardfs_iget */ + return 0; +} + +struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, userid_t id) +{ + struct sdcardfs_inode_info *info; + struct inode_data data; + struct inode *inode; /* the new inode to return */ + int err; + + data.id = id; + data.lower_inode = lower_inode; + inode = iget5_locked(sb, /* our superblock */ + /* + * hashval: we use inode number, but we can + * also use "(unsigned long)lower_inode" + * instead. + */ + lower_inode->i_ino, /* hashval */ + sdcardfs_inode_test, /* inode comparison function */ + sdcardfs_inode_set, /* inode init function */ + &data); /* data passed to test+set fxns */ + if (!inode) { + err = -EACCES; + iput(lower_inode); + return ERR_PTR(err); + } + /* if found a cached inode, then just return it */ + if (!(inode->i_state & I_NEW)) + return inode; + + /* initialize new inode */ + info = SDCARDFS_I(inode); + + inode->i_ino = lower_inode->i_ino; + if (!igrab(lower_inode)) { + err = -ESTALE; + return ERR_PTR(err); + } + sdcardfs_set_lower_inode(inode, lower_inode); + + inode->i_version++; + + /* use different set of inode ops for symlinks & directories */ + if (S_ISDIR(lower_inode->i_mode)) + inode->i_op = &sdcardfs_dir_iops; + else if (S_ISLNK(lower_inode->i_mode)) + inode->i_op = &sdcardfs_symlink_iops; + else + inode->i_op = &sdcardfs_main_iops; + + /* use different set of file ops for directories */ + if (S_ISDIR(lower_inode->i_mode)) + inode->i_fop = &sdcardfs_dir_fops; + else + inode->i_fop = &sdcardfs_main_fops; + + inode->i_mapping->a_ops = &sdcardfs_aops; + + inode->i_atime.tv_sec = 0; + inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_sec = 0; + inode->i_mtime.tv_nsec = 0; + inode->i_ctime.tv_sec = 0; + inode->i_ctime.tv_nsec = 0; + + /* properly initialize special inodes */ + if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || + S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) + init_special_inode(inode, lower_inode->i_mode, + lower_inode->i_rdev); + + /* all well, copy inode attributes */ + sdcardfs_copy_and_fix_attrs(inode, lower_inode); + fsstack_copy_inode_size(inode, lower_inode); + + unlock_new_inode(inode); + return inode; +} + +/* + * Connect a sdcardfs inode dentry/inode with several lower ones. This is + * the classic stackable file system "vnode interposition" action. + * + * @dentry: sdcardfs's dentry which interposes on lower one + * @sb: sdcardfs's super_block + * @lower_path: the lower path (caller does path_get/put) + */ +int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, + struct path *lower_path, userid_t id) +{ + int err = 0; + struct inode *inode; + struct inode *lower_inode; + struct super_block *lower_sb; + + lower_inode = lower_path->dentry->d_inode; + lower_sb = sdcardfs_lower_super(sb); + + /* check that the lower file system didn't cross a mount point */ + if (lower_inode->i_sb != lower_sb) { + err = -EXDEV; + goto out; + } + + /* + * We allocate our new inode below by calling sdcardfs_iget, + * which will initialize some of the new inode's fields + */ + + /* inherit lower inode number for sdcardfs's inode */ + inode = sdcardfs_iget(sb, lower_inode, id); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + update_derived_permission_lock(dentry); +out: + return err; +} + +/* + * Main driver function for sdcardfs's lookup. + * + * Returns: NULL (ok), ERR_PTR if an error occurred. + * Fills in lower_parent_path with on success. + */ +static struct dentry *__sdcardfs_lookup(struct dentry *dentry, + unsigned int flags, struct path *lower_parent_path, userid_t id) +{ + int err = 0; + struct vfsmount *lower_dir_mnt; + struct dentry *lower_dir_dentry = NULL; + struct dentry *lower_dentry; + const struct qstr *name; + struct path lower_path; + struct qstr dname; + struct sdcardfs_sb_info *sbi; + + sbi = SDCARDFS_SB(dentry->d_sb); + /* must initialize dentry operations */ + d_set_d_op(dentry, &sdcardfs_ci_dops); + + if (IS_ROOT(dentry)) + goto out; + + name = &dentry->d_name; + + /* now start the actual lookup procedure */ + lower_dir_dentry = lower_parent_path->dentry; + lower_dir_mnt = lower_parent_path->mnt; + + /* Use vfs_path_lookup to check if the dentry exists or not */ + err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name->name, 0, + &lower_path); + /* check for other cases */ + if (err == -ENOENT) { + struct dentry *child; + struct dentry *match = NULL; + mutex_lock(&lower_dir_dentry->d_inode->i_mutex); + spin_lock(&lower_dir_dentry->d_lock); + list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_child) { + if (child && child->d_inode) { + if (qstr_case_eq(&child->d_name, name)) { + match = dget(child); + break; + } + } + } + spin_unlock(&lower_dir_dentry->d_lock); + mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); + if (match) { + err = vfs_path_lookup(lower_dir_dentry, + lower_dir_mnt, + match->d_name.name, 0, + &lower_path); + dput(match); + } + } + + /* no error: handle positive dentries */ + if (!err) { + /* check if the dentry is an obb dentry + * if true, the lower_inode must be replaced with + * the inode of the graft path */ + + if(need_graft_path(dentry)) { + + /* setup_obb_dentry() + * The lower_path will be stored to the dentry's orig_path + * and the base obbpath will be copyed to the lower_path variable. + * if an error returned, there's no change in the lower_path + * returns: -ERRNO if error (0: no error) */ + err = setup_obb_dentry(dentry, &lower_path); + + if(err) { + /* if the sbi->obbpath is not available, we can optionally + * setup the lower_path with its orig_path. + * but, the current implementation just returns an error + * because the sdcard daemon also regards this case as + * a lookup fail. */ + printk(KERN_INFO "sdcardfs: base obbpath is not available\n"); + sdcardfs_put_reset_orig_path(dentry); + goto out; + } + } + + sdcardfs_set_lower_path(dentry, &lower_path); + err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path, id); + if (err) /* path_put underlying path on error */ + sdcardfs_put_reset_lower_path(dentry); + goto out; + } + + /* + * We don't consider ENOENT an error, and we want to return a + * negative dentry. + */ + if (err && err != -ENOENT) + goto out; + + /* instatiate a new negative dentry */ + dname.name = name->name; + dname.len = name->len; + dname.hash = full_name_hash(dname.name, dname.len); + lower_dentry = d_lookup(lower_dir_dentry, &dname); + if (lower_dentry) + goto setup_lower; + + lower_dentry = d_alloc(lower_dir_dentry, &dname); + if (!lower_dentry) { + err = -ENOMEM; + goto out; + } + d_add(lower_dentry, NULL); /* instantiate and hash */ + +setup_lower: + lower_path.dentry = lower_dentry; + lower_path.mnt = mntget(lower_dir_mnt); + sdcardfs_set_lower_path(dentry, &lower_path); + + /* + * If the intent is to create a file, then don't return an error, so + * the VFS will continue the process of making this negative dentry + * into a positive one. + */ + if (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) + err = 0; + +out: + return ERR_PTR(err); +} + +/* + * On success: + * fills dentry object appropriate values and returns NULL. + * On fail (== error) + * returns error ptr + * + * @dir : Parent inode. It is locked (dir->i_mutex) + * @dentry : Target dentry to lookup. we should set each of fields. + * (dentry->d_name is initialized already) + * @nd : nameidata of parent inode + */ +struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + struct dentry *ret = NULL, *parent; + struct path lower_parent_path; + int err = 0; + const struct cred *saved_cred = NULL; + + parent = dget_parent(dentry); + + if(!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + ret = ERR_PTR(-EACCES); + printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" + " dentry: %s, task:%s\n", + __func__, dentry->d_name.name, current->comm); + goto out_err; + } + + /* save current_cred and override it */ + OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + + sdcardfs_get_lower_path(parent, &lower_parent_path); + + /* allocate dentry private data. We free it in ->d_release */ + err = new_dentry_private_data(dentry); + if (err) { + ret = ERR_PTR(err); + goto out; + } + + ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path, SDCARDFS_I(dir)->userid); + if (IS_ERR(ret)) + { + goto out; + } + if (ret) + dentry = ret; + if (dentry->d_inode) { + fsstack_copy_attr_times(dentry->d_inode, + sdcardfs_lower_inode(dentry->d_inode)); + /* get derived permission */ + get_derived_permission(parent, dentry); + fixup_tmp_permissions(dentry->d_inode); + fixup_lower_ownership(dentry, dentry->d_name.name); + } + /* update parent directory's atime */ + fsstack_copy_attr_atime(parent->d_inode, + sdcardfs_lower_inode(parent->d_inode)); + +out: + sdcardfs_put_lower_path(parent, &lower_parent_path); + REVERT_CRED(saved_cred); +out_err: + dput(parent); + return ret; +} diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c new file mode 100755 index 000000000000..8d16e4d16d96 --- /dev/null +++ b/fs/sdcardfs/main.c @@ -0,0 +1,477 @@ +/* + * fs/sdcardfs/main.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include +#include +#include + +enum { + Opt_fsuid, + Opt_fsgid, + Opt_gid, + Opt_debug, + Opt_mask, + Opt_multiuser, // May need? + Opt_userid, + Opt_reserved_mb, + Opt_err, +}; + +static const match_table_t sdcardfs_tokens = { + {Opt_fsuid, "fsuid=%u"}, + {Opt_fsgid, "fsgid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_debug, "debug"}, + {Opt_mask, "mask=%u"}, + {Opt_userid, "userid=%d"}, + {Opt_multiuser, "multiuser"}, + {Opt_reserved_mb, "reserved_mb=%u"}, + {Opt_err, NULL} +}; + +static int parse_options(struct super_block *sb, char *options, int silent, + int *debug, struct sdcardfs_vfsmount_options *vfsopts, + struct sdcardfs_mount_options *opts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + + /* by default, we use AID_MEDIA_RW as uid, gid */ + opts->fs_low_uid = AID_MEDIA_RW; + opts->fs_low_gid = AID_MEDIA_RW; + vfsopts->mask = 0; + opts->multiuser = false; + opts->fs_user_id = 0; + vfsopts->gid = 0; + /* by default, 0MB is reserved */ + opts->reserved_mb = 0; + + *debug = 0; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, sdcardfs_tokens, args); + + switch (token) { + case Opt_debug: + *debug = 1; + break; + case Opt_fsuid: + if (match_int(&args[0], &option)) + return 0; + opts->fs_low_uid = option; + break; + case Opt_fsgid: + if (match_int(&args[0], &option)) + return 0; + opts->fs_low_gid = option; + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; + vfsopts->gid = option; + break; + case Opt_userid: + if (match_int(&args[0], &option)) + return 0; + opts->fs_user_id = option; + break; + case Opt_mask: + if (match_int(&args[0], &option)) + return 0; + vfsopts->mask = option; + break; + case Opt_multiuser: + opts->multiuser = true; + break; + case Opt_reserved_mb: + if (match_int(&args[0], &option)) + return 0; + opts->reserved_mb = option; + break; + /* unknown option */ + default: + if (!silent) { + printk( KERN_ERR "Unrecognized mount option \"%s\" " + "or missing value", p); + } + return -EINVAL; + } + } + + if (*debug) { + printk( KERN_INFO "sdcardfs : options - debug:%d\n", *debug); + printk( KERN_INFO "sdcardfs : options - uid:%d\n", + opts->fs_low_uid); + printk( KERN_INFO "sdcardfs : options - gid:%d\n", + opts->fs_low_gid); + } + + return 0; +} + +int parse_options_remount(struct super_block *sb, char *options, int silent, + struct sdcardfs_vfsmount_options *vfsopts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + int debug; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, sdcardfs_tokens, args); + + switch (token) { + case Opt_debug: + debug = 1; + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; + vfsopts->gid = option; + + break; + case Opt_mask: + if (match_int(&args[0], &option)) + return 0; + vfsopts->mask = option; + break; + case Opt_multiuser: + case Opt_userid: + case Opt_fsuid: + case Opt_fsgid: + case Opt_reserved_mb: + printk( KERN_WARNING "Option \"%s\" can't be changed during remount\n", p); + break; + /* unknown option */ + default: + if (!silent) { + printk( KERN_ERR "Unrecognized mount option \"%s\" " + "or missing value", p); + } + return -EINVAL; + } + } + + if (debug) { + printk( KERN_INFO "sdcardfs : options - debug:%d\n", debug); + printk( KERN_INFO "sdcardfs : options - gid:%d\n", vfsopts->gid); + printk( KERN_INFO "sdcardfs : options - mask:%d\n", vfsopts->mask); + } + + return 0; +} + +#if 0 +/* + * our custom d_alloc_root work-alike + * + * we can't use d_alloc_root if we want to use our own interpose function + * unchanged, so we simply call our own "fake" d_alloc_root + */ +static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) +{ + struct dentry *ret = NULL; + + if (sb) { + static const struct qstr name = { + .name = "/", + .len = 1 + }; + + ret = d_alloc(NULL, &name); + if (ret) { + d_set_d_op(ret, &sdcardfs_ci_dops); + ret->d_sb = sb; + ret->d_parent = ret; + } + } + return ret; +} +#endif + +DEFINE_MUTEX(sdcardfs_super_list_lock); +LIST_HEAD(sdcardfs_super_list); +EXPORT_SYMBOL_GPL(sdcardfs_super_list_lock); +EXPORT_SYMBOL_GPL(sdcardfs_super_list); + +/* + * There is no need to lock the sdcardfs_super_info's rwsem as there is no + * way anyone can have a reference to the superblock at this point in time. + */ +static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, + const char *dev_name, void *raw_data, int silent) +{ + int err = 0; + int debug; + struct super_block *lower_sb; + struct path lower_path; + struct sdcardfs_sb_info *sb_info; + struct sdcardfs_vfsmount_options *mnt_opt = mnt->data; + struct inode *inode; + + printk(KERN_INFO "sdcardfs version 2.0\n"); + + if (!dev_name) { + printk(KERN_ERR + "sdcardfs: read_super: missing dev_name argument\n"); + err = -EINVAL; + goto out; + } + + printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); + printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); + printk(KERN_INFO "sdcardfs: mnt -> %p\n", mnt); + + /* parse lower path */ + err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, + &lower_path); + if (err) { + printk(KERN_ERR "sdcardfs: error accessing lower directory '%s'\n", dev_name); + goto out; + } + + /* allocate superblock private data */ + sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); + if (!SDCARDFS_SB(sb)) { + printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); + err = -ENOMEM; + goto out_free; + } + + sb_info = sb->s_fs_info; + /* parse options */ + err = parse_options(sb, raw_data, silent, &debug, mnt_opt, &sb_info->options); + if (err) { + printk(KERN_ERR "sdcardfs: invalid options\n"); + goto out_freesbi; + } + + /* set the lower superblock field of upper superblock */ + lower_sb = lower_path.dentry->d_sb; + atomic_inc(&lower_sb->s_active); + sdcardfs_set_lower_super(sb, lower_sb); + + /* inherit maxbytes from lower file system */ + sb->s_maxbytes = lower_sb->s_maxbytes; + + /* + * Our c/m/atime granularity is 1 ns because we may stack on file + * systems whose granularity is as good. + */ + sb->s_time_gran = 1; + + sb->s_magic = SDCARDFS_SUPER_MAGIC; + sb->s_op = &sdcardfs_sops; + + /* get a new inode and allocate our root dentry */ + inode = sdcardfs_iget(sb, lower_path.dentry->d_inode, 0); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out_sput; + } + sb->s_root = d_make_root(inode); + if (!sb->s_root) { + err = -ENOMEM; + goto out_iput; + } + d_set_d_op(sb->s_root, &sdcardfs_ci_dops); + + /* link the upper and lower dentries */ + sb->s_root->d_fsdata = NULL; + err = new_dentry_private_data(sb->s_root); + if (err) + goto out_freeroot; + + /* set the lower dentries for s_root */ + sdcardfs_set_lower_path(sb->s_root, &lower_path); + + /* + * No need to call interpose because we already have a positive + * dentry, which was instantiated by d_make_root. Just need to + * d_rehash it. + */ + d_rehash(sb->s_root); + + /* setup permission policy */ + sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); + mutex_lock(&sdcardfs_super_list_lock); + if(sb_info->options.multiuser) { + setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); + /*err = prepare_dir(sb_info->obbpath_s, + sb_info->options.fs_low_uid, + sb_info->options.fs_low_gid, 00755);*/ + } else { + setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); + snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); + } + fixup_tmp_permissions(sb->s_root->d_inode); + sb_info->sb = sb; + list_add(&sb_info->list, &sdcardfs_super_list); + mutex_unlock(&sdcardfs_super_list_lock); + + if (!silent) + printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", + dev_name, lower_sb->s_type->name); + goto out; /* all is well */ + + /* no longer needed: free_dentry_private_data(sb->s_root); */ +out_freeroot: + dput(sb->s_root); +out_iput: + iput(inode); +out_sput: + /* drop refs we took earlier */ + atomic_dec(&lower_sb->s_active); +out_freesbi: + kfree(SDCARDFS_SB(sb)); + sb->s_fs_info = NULL; +out_free: + path_put(&lower_path); + +out: + return err; +} + +/* A feature which supports mount_nodev() with options */ +static struct dentry *mount_nodev_with_options(struct vfsmount *mnt, + struct file_system_type *fs_type, int flags, const char *dev_name, void *data, + int (*fill_super)(struct vfsmount *, struct super_block *, const char *, void *, int)) + +{ + int error; + struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL); + + if (IS_ERR(s)) + return ERR_CAST(s); + + s->s_flags = flags; + + error = fill_super(mnt, s, dev_name, data, flags & MS_SILENT ? 1 : 0); + if (error) { + deactivate_locked_super(s); + return ERR_PTR(error); + } + s->s_flags |= MS_ACTIVE; + return dget(s->s_root); +} + +static struct dentry *sdcardfs_mount(struct vfsmount *mnt, + struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) +{ + /* + * dev_name is a lower_path_name, + * raw_data is a option string. + */ + return mount_nodev_with_options(mnt, fs_type, flags, dev_name, + raw_data, sdcardfs_read_super); +} + +static struct dentry *sdcardfs_mount_wrn(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) +{ + WARN(1, "sdcardfs does not support mount. Use mount2.\n"); + return ERR_PTR(-EINVAL); +} + +void *sdcardfs_alloc_mnt_data(void) { + return kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); +} + +void sdcardfs_kill_sb(struct super_block *sb) { + struct sdcardfs_sb_info *sbi; + if (sb->s_magic == SDCARDFS_SUPER_MAGIC) { + sbi = SDCARDFS_SB(sb); + mutex_lock(&sdcardfs_super_list_lock); + list_del(&sbi->list); + mutex_unlock(&sdcardfs_super_list_lock); + } + generic_shutdown_super(sb); +} + +static struct file_system_type sdcardfs_fs_type = { + .owner = THIS_MODULE, + .name = SDCARDFS_NAME, + .mount = sdcardfs_mount_wrn, + .mount2 = sdcardfs_mount, + .alloc_mnt_data = sdcardfs_alloc_mnt_data, + .kill_sb = sdcardfs_kill_sb, + .fs_flags = 0, +}; + +static int __init init_sdcardfs_fs(void) +{ + int err; + + pr_info("Registering sdcardfs " SDCARDFS_VERSION "\n"); + + err = sdcardfs_init_inode_cache(); + if (err) + goto out; + err = sdcardfs_init_dentry_cache(); + if (err) + goto out; + err = packagelist_init(); + if (err) + goto out; + err = register_filesystem(&sdcardfs_fs_type); +out: + if (err) { + sdcardfs_destroy_inode_cache(); + sdcardfs_destroy_dentry_cache(); + packagelist_exit(); + } + return err; +} + +static void __exit exit_sdcardfs_fs(void) +{ + sdcardfs_destroy_inode_cache(); + sdcardfs_destroy_dentry_cache(); + packagelist_exit(); + unregister_filesystem(&sdcardfs_fs_type); + pr_info("Completed sdcardfs module unload\n"); +} + +MODULE_AUTHOR("Erez Zadok, Filesystems and Storage Lab, Stony Brook University" + " (http://www.fsl.cs.sunysb.edu/)"); +MODULE_DESCRIPTION("Wrapfs " SDCARDFS_VERSION + " (http://wrapfs.filesystems.org/)"); +MODULE_LICENSE("GPL"); + +module_init(init_sdcardfs_fs); +module_exit(exit_sdcardfs_fs); diff --git a/fs/sdcardfs/mmap.c b/fs/sdcardfs/mmap.c new file mode 100755 index 000000000000..9ec452391072 --- /dev/null +++ b/fs/sdcardfs/mmap.c @@ -0,0 +1,103 @@ +/* + * fs/sdcardfs/mmap.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" + +static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + int err; + struct file *file, *lower_file; + const struct vm_operations_struct *lower_vm_ops; + struct vm_area_struct lower_vma; + + memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); + file = lower_vma.vm_file; + lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; + BUG_ON(!lower_vm_ops); + + lower_file = sdcardfs_lower_file(file); + /* + * XXX: vm_ops->fault may be called in parallel. Because we have to + * resort to temporarily changing the vma->vm_file to point to the + * lower file, a concurrent invocation of sdcardfs_fault could see a + * different value. In this workaround, we keep a different copy of + * the vma structure in our stack, so we never expose a different + * value of the vma->vm_file called to us, even temporarily. A + * better fix would be to change the calling semantics of ->fault to + * take an explicit file pointer. + */ + lower_vma.vm_file = lower_file; + err = lower_vm_ops->fault(&lower_vma, vmf); + return err; +} + +static int sdcardfs_page_mkwrite(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + int err = 0; + struct file *file, *lower_file; + const struct vm_operations_struct *lower_vm_ops; + struct vm_area_struct lower_vma; + + memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); + file = lower_vma.vm_file; + lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; + BUG_ON(!lower_vm_ops); + if (!lower_vm_ops->page_mkwrite) + goto out; + + lower_file = sdcardfs_lower_file(file); + /* + * XXX: vm_ops->page_mkwrite may be called in parallel. + * Because we have to resort to temporarily changing the + * vma->vm_file to point to the lower file, a concurrent + * invocation of sdcardfs_page_mkwrite could see a different + * value. In this workaround, we keep a different copy of the + * vma structure in our stack, so we never expose a different + * value of the vma->vm_file called to us, even temporarily. + * A better fix would be to change the calling semantics of + * ->page_mkwrite to take an explicit file pointer. + */ + lower_vma.vm_file = lower_file; + err = lower_vm_ops->page_mkwrite(&lower_vma, vmf); +out: + return err; +} + +static ssize_t sdcardfs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) +{ + /* + * This function should never be called directly. We need it + * to exist, to get past a check in open_check_o_direct(), + * which is called from do_last(). + */ + return -EINVAL; +} + +const struct address_space_operations sdcardfs_aops = { + .direct_IO = sdcardfs_direct_IO, +}; + +const struct vm_operations_struct sdcardfs_vm_ops = { + .fault = sdcardfs_fault, + .page_mkwrite = sdcardfs_page_mkwrite, +}; diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h new file mode 100755 index 000000000000..52bc20080904 --- /dev/null +++ b/fs/sdcardfs/multiuser.h @@ -0,0 +1,49 @@ +/* + * fs/sdcardfs/multiuser.h + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */ +#define AID_APP_START 10000 /* first app user */ +#define AID_APP_END 19999 /* last app user */ +#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */ +#define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */ +#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */ + +typedef uid_t userid_t; +typedef uid_t appid_t; + +static inline uid_t multiuser_get_uid(userid_t user_id, appid_t app_id) { + return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET); +} + +static inline gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id) { + if (app_id >= AID_APP_START && app_id <= AID_APP_END) { + return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_CACHE_GID_START); + } else { + return -1; + } +} + +static inline gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id) { + if (app_id >= AID_APP_START && app_id <= AID_APP_END) { + return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_GID_START); + } else { + return -1; + } +} diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c new file mode 100755 index 000000000000..21eb2d317e44 --- /dev/null +++ b/fs/sdcardfs/packagelist.c @@ -0,0 +1,884 @@ +/* + * fs/sdcardfs/packagelist.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct hashtable_entry { + struct hlist_node hlist; + struct hlist_node dlist; /* for deletion cleanup */ + struct qstr key; + atomic_t value; +}; + +static DEFINE_HASHTABLE(package_to_appid, 8); +static DEFINE_HASHTABLE(package_to_userid, 8); +static DEFINE_HASHTABLE(ext_to_groupid, 8); + + +static struct kmem_cache *hashtable_entry_cachep; + +static void inline qstr_init(struct qstr *q, const char *name) { + q->name = name; + q->len = strlen(q->name); + q->hash = full_name_hash(q->name, q->len); +} + +static inline int qstr_copy(const struct qstr *src, struct qstr *dest) { + dest->name = kstrdup(src->name, GFP_KERNEL); + dest->hash_len = src->hash_len; + return !!dest->name; +} + + +static appid_t __get_appid(const struct qstr *key) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + appid_t ret_id; + + rcu_read_lock(); + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + ret_id = atomic_read(&hash_cur->value); + rcu_read_unlock(); + return ret_id; + } + } + rcu_read_unlock(); + return 0; +} + +appid_t get_appid(const char *key) +{ + struct qstr q; + qstr_init(&q, key); + return __get_appid(&q); +} + +static appid_t __get_ext_gid(const struct qstr *key) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + appid_t ret_id; + + rcu_read_lock(); + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + ret_id = atomic_read(&hash_cur->value); + rcu_read_unlock(); + return ret_id; + } + } + rcu_read_unlock(); + return 0; +} + +appid_t get_ext_gid(const char *key) +{ + struct qstr q; + qstr_init(&q, key); + return __get_ext_gid(&q); +} + +static appid_t __is_excluded(const struct qstr *app_name, userid_t user) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = app_name->hash; + + rcu_read_lock(); + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (atomic_read(&hash_cur->value) == user && + qstr_case_eq(app_name, &hash_cur->key)) { + rcu_read_unlock(); + return 1; + } + } + rcu_read_unlock(); + return 0; +} + +appid_t is_excluded(const char *key, userid_t user) +{ + struct qstr q; + qstr_init(&q, key); + return __is_excluded(&q, user); +} + +/* Kernel has already enforced everything we returned through + * derive_permissions_locked(), so this is used to lock down access + * even further, such as enforcing that apps hold sdcard_rw. */ +int check_caller_access_to_name(struct inode *parent_node, const struct qstr *name) { + struct qstr q_autorun = QSTR_LITERAL("autorun.inf"); + struct qstr q__android_secure = QSTR_LITERAL(".android_secure"); + struct qstr q_android_secure = QSTR_LITERAL("android_secure"); + + /* Always block security-sensitive files at root */ + if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) { + if (qstr_case_eq(name, &q_autorun) + || qstr_case_eq(name, &q__android_secure) + || qstr_case_eq(name, &q_android_secure)) { + return 0; + } + } + + /* Root always has access; access for any other UIDs should always + * be controlled through packages.list. */ + if (current_fsuid() == 0) { + return 1; + } + + /* No extra permissions to enforce */ + return 1; +} + +/* This function is used when file opening. The open flags must be + * checked before calling check_caller_access_to_name() */ +int open_flags_to_access_mode(int open_flags) { + if((open_flags & O_ACCMODE) == O_RDONLY) { + return 0; /* R_OK */ + } else if ((open_flags & O_ACCMODE) == O_WRONLY) { + return 1; /* W_OK */ + } else { + /* Probably O_RDRW, but treat as default to be safe */ + return 1; /* R_OK | W_OK */ + } +} + +static struct hashtable_entry *alloc_hashtable_entry(const struct qstr *key, + appid_t value) +{ + struct hashtable_entry *ret = kmem_cache_alloc(hashtable_entry_cachep, + GFP_KERNEL); + if (!ret) + return NULL; + INIT_HLIST_NODE(&ret->dlist); + INIT_HLIST_NODE(&ret->hlist); + + if (!qstr_copy(key, &ret->key)) { + kmem_cache_free(hashtable_entry_cachep, ret); + return NULL; + } + + atomic_set(&ret->value, value); + return ret; +} + +static int insert_packagelist_appid_entry_locked(const struct qstr *key, appid_t value) +{ + struct hashtable_entry *hash_cur; + struct hashtable_entry *new_entry; + unsigned int hash = key->hash; + + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + atomic_set(&hash_cur->value, value); + return 0; + } + } + new_entry = alloc_hashtable_entry(key, value); + if (!new_entry) + return -ENOMEM; + hash_add_rcu(package_to_appid, &new_entry->hlist, hash); + return 0; +} + +static int insert_ext_gid_entry_locked(const struct qstr *key, appid_t value) +{ + struct hashtable_entry *hash_cur; + struct hashtable_entry *new_entry; + unsigned int hash = key->hash; + + /* An extension can only belong to one gid */ + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) + return -EINVAL; + } + new_entry = alloc_hashtable_entry(key, value); + if (!new_entry) + return -ENOMEM; + hash_add_rcu(ext_to_groupid, &new_entry->hlist, hash); + return 0; +} + +static int insert_userid_exclude_entry_locked(const struct qstr *key, userid_t value) +{ + struct hashtable_entry *hash_cur; + struct hashtable_entry *new_entry; + unsigned int hash = key->hash; + + /* Only insert if not already present */ + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (atomic_read(&hash_cur->value) == value && + qstr_case_eq(key, &hash_cur->key)) + return 0; + } + new_entry = alloc_hashtable_entry(key, value); + if (!new_entry) + return -ENOMEM; + hash_add_rcu(package_to_userid, &new_entry->hlist, hash); + return 0; +} + +static void fixup_all_perms_name(const struct qstr *key) +{ + struct sdcardfs_sb_info *sbinfo; + struct limit_search limit = { + .flags = BY_NAME, + .name = key->name, + .length = key->len, + }; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo_has_sdcard_magic(sbinfo)) + fixup_perms_recursive(sbinfo->sb->s_root, &limit); + } +} + +static void fixup_all_perms_name_userid(const struct qstr *key, userid_t userid) +{ + struct sdcardfs_sb_info *sbinfo; + struct limit_search limit = { + .flags = BY_NAME | BY_USERID, + .name = key->name, + .length = key->len, + .userid = userid, + }; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo_has_sdcard_magic(sbinfo)) + fixup_perms_recursive(sbinfo->sb->s_root, &limit); + } +} + +static void fixup_all_perms_userid(userid_t userid) +{ + struct sdcardfs_sb_info *sbinfo; + struct limit_search limit = { + .flags = BY_USERID, + .userid = userid, + }; + list_for_each_entry(sbinfo, &sdcardfs_super_list, list) { + if (sbinfo_has_sdcard_magic(sbinfo)) + fixup_perms_recursive(sbinfo->sb->s_root, &limit); + } +} + +static int insert_packagelist_entry(const struct qstr *key, appid_t value) +{ + int err; + + mutex_lock(&sdcardfs_super_list_lock); + err = insert_packagelist_appid_entry_locked(key, value); + if (!err) + fixup_all_perms_name(key); + mutex_unlock(&sdcardfs_super_list_lock); + + return err; +} + +static int insert_ext_gid_entry(const struct qstr *key, appid_t value) +{ + int err; + + mutex_lock(&sdcardfs_super_list_lock); + err = insert_ext_gid_entry_locked(key, value); + mutex_unlock(&sdcardfs_super_list_lock); + + return err; +} + +static int insert_userid_exclude_entry(const struct qstr *key, userid_t value) +{ + int err; + + mutex_lock(&sdcardfs_super_list_lock); + err = insert_userid_exclude_entry_locked(key, value); + if (!err) + fixup_all_perms_name_userid(key, value); + mutex_unlock(&sdcardfs_super_list_lock); + + return err; +} + +static void free_hashtable_entry(struct hashtable_entry *entry) +{ + kfree(entry->key.name); + kmem_cache_free(hashtable_entry_cachep, entry); +} + +static void remove_packagelist_entry_locked(const struct qstr *key) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + struct hlist_node *h_t; + HLIST_HEAD(free_list); + + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); + } + } + hash_for_each_possible_rcu(package_to_appid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key)) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); + break; + } + } + synchronize_rcu(); + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) + free_hashtable_entry(hash_cur); +} + +static void remove_packagelist_entry(const struct qstr *key) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_packagelist_entry_locked(key); + fixup_all_perms_name(key); + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + +static void remove_ext_gid_entry_locked(const struct qstr *key, gid_t group) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + + hash_for_each_possible_rcu(ext_to_groupid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key) && atomic_read(&hash_cur->value) == group) { + hash_del_rcu(&hash_cur->hlist); + synchronize_rcu(); + free_hashtable_entry(hash_cur); + break; + } + } +} + +static void remove_ext_gid_entry(const struct qstr *key, gid_t group) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_ext_gid_entry_locked(key, group); + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + +static void remove_userid_all_entry_locked(userid_t userid) +{ + struct hashtable_entry *hash_cur; + struct hlist_node *h_t; + HLIST_HEAD(free_list); + int i; + + hash_for_each_rcu(package_to_userid, i, hash_cur, hlist) { + if (atomic_read(&hash_cur->value) == userid) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); + } + } + synchronize_rcu(); + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) { + free_hashtable_entry(hash_cur); + } +} + +static void remove_userid_all_entry(userid_t userid) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_userid_all_entry_locked(userid); + fixup_all_perms_userid(userid); + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + +static void remove_userid_exclude_entry_locked(const struct qstr *key, userid_t userid) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = key->hash; + + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (qstr_case_eq(key, &hash_cur->key) && + atomic_read(&hash_cur->value) == userid) { + hash_del_rcu(&hash_cur->hlist); + synchronize_rcu(); + free_hashtable_entry(hash_cur); + break; + } + } +} + +static void remove_userid_exclude_entry(const struct qstr *key, userid_t userid) +{ + mutex_lock(&sdcardfs_super_list_lock); + remove_userid_exclude_entry_locked(key, userid); + fixup_all_perms_name_userid(key, userid); + mutex_unlock(&sdcardfs_super_list_lock); + return; +} + +static void packagelist_destroy(void) +{ + struct hashtable_entry *hash_cur; + struct hlist_node *h_t; + HLIST_HEAD(free_list); + int i; + mutex_lock(&sdcardfs_super_list_lock); + hash_for_each_rcu(package_to_appid, i, hash_cur, hlist) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); + } + hash_for_each_rcu(package_to_userid, i, hash_cur, hlist) { + hash_del_rcu(&hash_cur->hlist); + hlist_add_head(&hash_cur->dlist, &free_list); + } + synchronize_rcu(); + hlist_for_each_entry_safe(hash_cur, h_t, &free_list, dlist) + free_hashtable_entry(hash_cur); + mutex_unlock(&sdcardfs_super_list_lock); + printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n"); +} + +struct package_details { + struct config_item item; + struct qstr name; +}; + +static inline struct package_details *to_package_details(struct config_item *item) +{ + return item ? container_of(item, struct package_details, item) : NULL; +} + +CONFIGFS_ATTR_STRUCT(package_details); +#define PACKAGE_DETAILS_ATTR(_name, _mode, _show, _store) \ +struct package_details_attribute package_details_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store) +#define PACKAGE_DETAILS_ATTRIBUTE(name) &package_details_attr_##name.attr + +static ssize_t package_details_appid_show(struct package_details *package_details, + char *page) +{ + return scnprintf(page, PAGE_SIZE, "%u\n", __get_appid(&package_details->name)); +} + +static ssize_t package_details_appid_store(struct package_details *package_details, + const char *page, size_t count) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + + ret = insert_packagelist_entry(&package_details->name, tmp); + + if (ret) + return ret; + + return count; +} + +static ssize_t package_details_excluded_userids_show(struct package_details *package_details, + char *page) +{ + struct hashtable_entry *hash_cur; + unsigned int hash = package_details->name.hash; + int count = 0; + + rcu_read_lock(); + hash_for_each_possible_rcu(package_to_userid, hash_cur, hlist, hash) { + if (qstr_case_eq(&package_details->name, &hash_cur->key)) + count += scnprintf(page + count, PAGE_SIZE - count, + "%d ", atomic_read(&hash_cur->value)); + } + rcu_read_unlock(); + if (count) + count--; + count += scnprintf(page + count, PAGE_SIZE - count, "\n"); + return count; +} + +static ssize_t package_details_excluded_userids_store(struct package_details *package_details, + const char *page, size_t count) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + + ret = insert_userid_exclude_entry(&package_details->name, tmp); + + if (ret) + return ret; + + return count; +} + +static ssize_t package_details_clear_userid_store(struct package_details *package_details, + const char *page, size_t count) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + remove_userid_exclude_entry(&package_details->name, tmp); + return count; +} + +static void package_details_release(struct config_item *item) +{ + struct package_details *package_details = to_package_details(item); + printk(KERN_INFO "sdcardfs: removing %s\n", package_details->name.name); + remove_packagelist_entry(&package_details->name); + kfree(package_details->name.name); + kfree(package_details); +} + +PACKAGE_DETAILS_ATTR(appid, S_IRUGO | S_IWUGO, package_details_appid_show, package_details_appid_store); +PACKAGE_DETAILS_ATTR(excluded_userids, S_IRUGO | S_IWUGO, + package_details_excluded_userids_show, package_details_excluded_userids_store); +PACKAGE_DETAILS_ATTR(clear_userid, S_IWUGO, NULL, package_details_clear_userid_store); + +static struct configfs_attribute *package_details_attrs[] = { + PACKAGE_DETAILS_ATTRIBUTE(appid), + PACKAGE_DETAILS_ATTRIBUTE(excluded_userids), + PACKAGE_DETAILS_ATTRIBUTE(clear_userid), + NULL, +}; + +CONFIGFS_ATTR_OPS(package_details); + +static struct configfs_item_operations package_details_item_ops = { + .release = package_details_release, + .show_attribute = package_details_attr_show, + .store_attribute = package_details_attr_store, +}; + +static struct config_item_type package_appid_type = { + .ct_item_ops = &package_details_item_ops, + .ct_attrs = package_details_attrs, + .ct_owner = THIS_MODULE, +}; + +struct extensions_value { + struct config_group group; + unsigned int num; +}; + +struct extension_details { + struct config_item item; + struct qstr name; + unsigned int num; +}; + +static inline struct extensions_value *to_extensions_value(struct config_item *item) +{ + return item ? container_of(to_config_group(item), struct extensions_value, group) : NULL; +} + +static inline struct extension_details *to_extension_details(struct config_item *item) +{ + return item ? container_of(item, struct extension_details, item) : NULL; +} + +static void extension_details_release(struct config_item *item) +{ + struct extension_details *extension_details = to_extension_details(item); + + printk(KERN_INFO "sdcardfs: No longer mapping %s files to gid %d\n", + extension_details->name.name, extension_details->num); + remove_ext_gid_entry(&extension_details->name, extension_details->num); + kfree(extension_details->name.name); + kfree(extension_details); +} + +static struct configfs_item_operations extension_details_item_ops = { + .release = extension_details_release, +}; + +static struct config_item_type extension_details_type = { + .ct_item_ops = &extension_details_item_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_item *extension_details_make_item(struct config_group *group, const char *name) +{ + struct extensions_value *extensions_value = to_extensions_value(&group->cg_item); + struct extension_details *extension_details = kzalloc(sizeof(struct extension_details), GFP_KERNEL); + const char *tmp; + int ret; + if (!extension_details) + return ERR_PTR(-ENOMEM); + + tmp = kstrdup(name, GFP_KERNEL); + if (!tmp) { + kfree(extension_details); + return ERR_PTR(-ENOMEM); + } + qstr_init(&extension_details->name, tmp); + ret = insert_ext_gid_entry(&extension_details->name, extensions_value->num); + + if (ret) { + kfree(extension_details->name.name); + kfree(extension_details); + return ERR_PTR(ret); + } + config_item_init_type_name(&extension_details->item, name, &extension_details_type); + + return &extension_details->item; +} + +static struct configfs_group_operations extensions_value_group_ops = { + .make_item = extension_details_make_item, +}; + +static struct config_item_type extensions_name_type = { + .ct_group_ops = &extensions_value_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *extensions_make_group(struct config_group *group, const char *name) +{ + struct extensions_value *extensions_value; + unsigned int tmp; + int ret; + + extensions_value = kzalloc(sizeof(struct extensions_value), GFP_KERNEL); + if (!extensions_value) + return ERR_PTR(-ENOMEM); + ret = kstrtouint(name, 10, &tmp); + if (ret) { + kfree(extensions_value); + return ERR_PTR(ret); + } + + extensions_value->num = tmp; + config_group_init_type_name(&extensions_value->group, name, + &extensions_name_type); + return &extensions_value->group; +} + +static void extensions_drop_group(struct config_group *group, struct config_item *item) +{ + struct extensions_value *value = to_extensions_value(item); + printk(KERN_INFO "sdcardfs: No longer mapping any files to gid %d\n", value->num); + kfree(value); +} + +static struct configfs_group_operations extensions_group_ops = { + .make_group = extensions_make_group, + .drop_item = extensions_drop_group, +}; + +static struct config_item_type extensions_type = { + .ct_group_ops = &extensions_group_ops, + .ct_owner = THIS_MODULE, +}; + +struct config_group extension_group = { + .cg_item = { + .ci_namebuf = "extensions", + .ci_type = &extensions_type, + }, +}; + +struct packages { + struct configfs_subsystem subsystem; +}; + +static inline struct packages *to_packages(struct config_item *item) +{ + return item ? container_of(to_configfs_subsystem(to_config_group(item)), struct packages, subsystem) : NULL; +} + +CONFIGFS_ATTR_STRUCT(packages); +#define PACKAGES_ATTR(_name, _mode, _show, _store) \ +struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store) +#define PACKAGES_ATTR_RO(_name, _show) \ +struct packages_attribute packages_attr_##_name = __CONFIGFS_ATTR_RO(_name, _show); + +static struct config_item *packages_make_item(struct config_group *group, const char *name) +{ + struct package_details *package_details; + const char *tmp; + + package_details = kzalloc(sizeof(struct package_details), GFP_KERNEL); + if (!package_details) + return ERR_PTR(-ENOMEM); + tmp = kstrdup(name, GFP_KERNEL); + if (!tmp) { + kfree(package_details); + return ERR_PTR(-ENOMEM); + } + qstr_init(&package_details->name, tmp); + config_item_init_type_name(&package_details->item, name, + &package_appid_type); + + return &package_details->item; +} + +static ssize_t packages_list_show(struct packages *packages, + char *page) +{ + struct hashtable_entry *hash_cur_app; + struct hashtable_entry *hash_cur_user; + int i; + int count = 0, written = 0; + const char errormsg[] = "\n"; + unsigned int hash; + + rcu_read_lock(); + hash_for_each_rcu(package_to_appid, i, hash_cur_app, hlist) { + written = scnprintf(page + count, PAGE_SIZE - sizeof(errormsg) - count, "%s %d\n", + hash_cur_app->key.name, atomic_read(&hash_cur_app->value)); + hash = hash_cur_app->key.hash; + hash_for_each_possible_rcu(package_to_userid, hash_cur_user, hlist, hash) { + if (qstr_case_eq(&hash_cur_app->key, &hash_cur_user->key)) { + written += scnprintf(page + count + written - 1, + PAGE_SIZE - sizeof(errormsg) - count - written + 1, + " %d\n", atomic_read(&hash_cur_user->value)) - 1; + } + } + if (count + written == PAGE_SIZE - sizeof(errormsg) - 1) { + count += scnprintf(page + count, PAGE_SIZE - count, errormsg); + break; + } + count += written; + } + rcu_read_unlock(); + + return count; +} + +static ssize_t packages_remove_userid_store(struct packages *packages, + const char *page, size_t count) +{ + unsigned int tmp; + int ret; + + ret = kstrtouint(page, 10, &tmp); + if (ret) + return ret; + remove_userid_all_entry(tmp); + return count; +} + +struct packages_attribute packages_attr_packages_gid_list = __CONFIGFS_ATTR_RO(packages_gid.list, packages_list_show); +PACKAGES_ATTR(remove_userid, S_IWUGO, NULL, packages_remove_userid_store); + +static struct configfs_attribute *packages_attrs[] = { + &packages_attr_packages_gid_list.attr, + &packages_attr_remove_userid.attr, + NULL, +}; + +CONFIGFS_ATTR_OPS(packages) +static struct configfs_item_operations packages_item_ops = { + .show_attribute = packages_attr_show, + .store_attribute = packages_attr_store, +}; + +/* + * Note that, since no extra work is required on ->drop_item(), + * no ->drop_item() is provided. + */ +static struct configfs_group_operations packages_group_ops = { + .make_item = packages_make_item, +}; + +static struct config_item_type packages_type = { + .ct_item_ops = &packages_item_ops, + .ct_group_ops = &packages_group_ops, + .ct_attrs = packages_attrs, + .ct_owner = THIS_MODULE, +}; + +struct config_group *sd_default_groups[] = { + &extension_group, + NULL, +}; + +static struct packages sdcardfs_packages = { + .subsystem = { + .su_group = { + .cg_item = { + .ci_namebuf = "sdcardfs", + .ci_type = &packages_type, + }, + .default_groups = sd_default_groups, + }, + }, +}; + +static int configfs_sdcardfs_init(void) +{ + int ret, i; + struct configfs_subsystem *subsys = &sdcardfs_packages.subsystem; + for (i = 0; sd_default_groups[i]; i++) { + config_group_init(sd_default_groups[i]); + } + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + ret = configfs_register_subsystem(subsys); + if (ret) { + printk(KERN_ERR "Error %d while registering subsystem %s\n", + ret, + subsys->su_group.cg_item.ci_namebuf); + } + return ret; +} + +static void configfs_sdcardfs_exit(void) +{ + configfs_unregister_subsystem(&sdcardfs_packages.subsystem); +} + +int packagelist_init(void) +{ + hashtable_entry_cachep = + kmem_cache_create("packagelist_hashtable_entry", + sizeof(struct hashtable_entry), 0, 0, NULL); + if (!hashtable_entry_cachep) { + printk(KERN_ERR "sdcardfs: failed creating pkgl_hashtable entry slab cache\n"); + return -ENOMEM; + } + + configfs_sdcardfs_init(); + return 0; +} + +void packagelist_exit(void) +{ + configfs_sdcardfs_exit(); + packagelist_destroy(); + if (hashtable_entry_cachep) + kmem_cache_destroy(hashtable_entry_cachep); +} diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h new file mode 100755 index 000000000000..fe121e81a24d --- /dev/null +++ b/fs/sdcardfs/sdcardfs.h @@ -0,0 +1,623 @@ +/* + * fs/sdcardfs/sdcardfs.h + * + * The sdcardfs v2.0 + * This file system replaces the sdcard daemon on Android + * On version 2.0, some of the daemon functions have been ported + * to support the multi-user concepts of Android 4.4 + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#ifndef _SDCARDFS_H_ +#define _SDCARDFS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "multiuser.h" + +/* the file system name */ +#define SDCARDFS_NAME "sdcardfs" + +/* sdcardfs root inode number */ +#define SDCARDFS_ROOT_INO 1 + +/* useful for tracking code reachability */ +#define UDBG printk(KERN_DEFAULT "DBG:%s:%s:%d\n", __FILE__, __func__, __LINE__) + +#define SDCARDFS_DIRENT_SIZE 256 + +/* temporary static uid settings for development */ +#define AID_ROOT 0 /* uid for accessing /mnt/sdcard & extSdcard */ +#define AID_MEDIA_RW 1023 /* internal media storage write access */ + +#define AID_SDCARD_RW 1015 /* external storage write access */ +#define AID_SDCARD_R 1028 /* external storage read access */ +#define AID_SDCARD_PICS 1033 /* external storage photos access */ +#define AID_SDCARD_AV 1034 /* external storage audio/video access */ +#define AID_SDCARD_ALL 1035 /* access all users external storage */ +#define AID_MEDIA_OBB 1059 /* obb files */ + +#define AID_SDCARD_IMAGE 1057 + +#define AID_PACKAGE_INFO 1027 + + +/* + * Permissions are handled by our permission function. + * We don't want anyone who happens to look at our inode value to prematurely + * block access, so store more permissive values. These are probably never + * used. + */ +#define fixup_tmp_permissions(x) \ + do { \ + (x)->i_uid = SDCARDFS_I(x)->d_uid; \ + (x)->i_gid = AID_SDCARD_RW; \ + (x)->i_mode = ((x)->i_mode & S_IFMT) | 0775;\ + } while (0) + +/* OVERRIDE_CRED() and REVERT_CRED() + * OVERRID_CRED() + * backup original task->cred + * and modifies task->cred->fsuid/fsgid to specified value. + * REVERT_CRED() + * restore original task->cred->fsuid/fsgid. + * These two macro should be used in pair, and OVERRIDE_CRED() should be + * placed at the beginning of a function, right after variable declaration. + */ +#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \ + saved_cred = override_fsids(sdcardfs_sbi, info); \ + if (!saved_cred) { return -ENOMEM; } + +#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \ + saved_cred = override_fsids(sdcardfs_sbi, info); \ + if (!saved_cred) { return ERR_PTR(-ENOMEM); } + +#define REVERT_CRED(saved_cred) revert_fsids(saved_cred) + +#define DEBUG_CRED() \ + printk("KAKJAGI: %s:%d fsuid %d fsgid %d\n", \ + __FUNCTION__, __LINE__, \ + (int)current->cred->fsuid, \ + (int)current->cred->fsgid); + +/* Android 5.0 support */ + +/* Permission mode for a specific node. Controls how file permissions + * are derived for children nodes. */ +typedef enum { + /* Nothing special; this node should just inherit from its parent. */ + PERM_INHERIT, + /* This node is one level above a normal root; used for legacy layouts + * which use the first level to represent user_id. */ + PERM_PRE_ROOT, + /* This node is "/" */ + PERM_ROOT, + /* This node is "/Android" */ + PERM_ANDROID, + /* This node is "/Android/data" */ + PERM_ANDROID_DATA, + /* This node is "/Android/obb" */ + PERM_ANDROID_OBB, + /* This node is "/Android/media" */ + PERM_ANDROID_MEDIA, + /* This node is "/Android/[data|media|obb]/[package]" */ + PERM_ANDROID_PACKAGE, + /* This node is "/Android/[data|media|obb]/[package]/cache" */ + PERM_ANDROID_PACKAGE_CACHE, +} perm_t; + +struct sdcardfs_sb_info; +struct sdcardfs_mount_options; +struct sdcardfs_inode_info; + +/* Do not directly use this function. Use OVERRIDE_CRED() instead. */ +const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info); +/* Do not directly use this function, use REVERT_CRED() instead. */ +void revert_fsids(const struct cred * old_cred); + +/* operations vectors defined in specific files */ +extern const struct file_operations sdcardfs_main_fops; +extern const struct file_operations sdcardfs_dir_fops; +extern const struct inode_operations sdcardfs_main_iops; +extern const struct inode_operations sdcardfs_dir_iops; +extern const struct inode_operations sdcardfs_symlink_iops; +extern const struct super_operations sdcardfs_sops; +extern const struct dentry_operations sdcardfs_ci_dops; +extern const struct address_space_operations sdcardfs_aops, sdcardfs_dummy_aops; +extern const struct vm_operations_struct sdcardfs_vm_ops; + +extern int sdcardfs_init_inode_cache(void); +extern void sdcardfs_destroy_inode_cache(void); +extern int sdcardfs_init_dentry_cache(void); +extern void sdcardfs_destroy_dentry_cache(void); +extern int new_dentry_private_data(struct dentry *dentry); +extern void free_dentry_private_data(struct dentry *dentry); +extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags); +extern struct inode *sdcardfs_iget(struct super_block *sb, + struct inode *lower_inode, userid_t id); +extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb, + struct path *lower_path, userid_t id); + +/* file private data */ +struct sdcardfs_file_info { + struct file *lower_file; + const struct vm_operations_struct *lower_vm_ops; +}; + +/* sdcardfs inode data in memory */ +struct sdcardfs_inode_info { + struct inode *lower_inode; + /* state derived based on current position in hierachy */ + perm_t perm; + userid_t userid; + uid_t d_uid; + bool under_android; + bool under_cache; + bool under_obb; + /* top folder for ownership */ + struct inode *top; + + struct inode vfs_inode; +}; + + +/* sdcardfs dentry data in memory */ +struct sdcardfs_dentry_info { + spinlock_t lock; /* protects lower_path */ + struct path lower_path; + struct path orig_path; +}; + +struct sdcardfs_mount_options { + uid_t fs_low_uid; + gid_t fs_low_gid; + userid_t fs_user_id; + bool multiuser; + unsigned int reserved_mb; +}; + +struct sdcardfs_vfsmount_options { + gid_t gid; + mode_t mask; +}; + +extern int parse_options_remount(struct super_block *sb, char *options, int silent, + struct sdcardfs_vfsmount_options *vfsopts); + +/* sdcardfs super-block data in memory */ +struct sdcardfs_sb_info { + struct super_block *sb; + struct super_block *lower_sb; + /* derived perm policy : some of options have been added + * to sdcardfs_mount_options (Android 4.4 support) */ + struct sdcardfs_mount_options options; + spinlock_t lock; /* protects obbpath */ + char *obbpath_s; + struct path obbpath; + void *pkgl_id; + struct list_head list; +}; + +/* + * inode to private data + * + * Since we use containers and the struct inode is _inside_ the + * sdcardfs_inode_info structure, SDCARDFS_I will always (given a non-NULL + * inode pointer), return a valid non-NULL pointer. + */ +static inline struct sdcardfs_inode_info *SDCARDFS_I(const struct inode *inode) +{ + return container_of(inode, struct sdcardfs_inode_info, vfs_inode); +} + +/* dentry to private data */ +#define SDCARDFS_D(dent) ((struct sdcardfs_dentry_info *)(dent)->d_fsdata) + +/* superblock to private data */ +#define SDCARDFS_SB(super) ((struct sdcardfs_sb_info *)(super)->s_fs_info) + +/* file to private Data */ +#define SDCARDFS_F(file) ((struct sdcardfs_file_info *)((file)->private_data)) + +/* file to lower file */ +static inline struct file *sdcardfs_lower_file(const struct file *f) +{ + return SDCARDFS_F(f)->lower_file; +} + +static inline void sdcardfs_set_lower_file(struct file *f, struct file *val) +{ + SDCARDFS_F(f)->lower_file = val; +} + +/* inode to lower inode. */ +static inline struct inode *sdcardfs_lower_inode(const struct inode *i) +{ + return SDCARDFS_I(i)->lower_inode; +} + +static inline void sdcardfs_set_lower_inode(struct inode *i, struct inode *val) +{ + SDCARDFS_I(i)->lower_inode = val; +} + +/* superblock to lower superblock */ +static inline struct super_block *sdcardfs_lower_super( + const struct super_block *sb) +{ + return SDCARDFS_SB(sb)->lower_sb; +} + +static inline void sdcardfs_set_lower_super(struct super_block *sb, + struct super_block *val) +{ + SDCARDFS_SB(sb)->lower_sb = val; +} + +/* path based (dentry/mnt) macros */ +static inline void pathcpy(struct path *dst, const struct path *src) +{ + dst->dentry = src->dentry; + dst->mnt = src->mnt; +} + +/* sdcardfs_get_pname functions calls path_get() + * therefore, the caller must call "proper" path_put functions + */ +#define SDCARDFS_DENT_FUNC(pname) \ +static inline void sdcardfs_get_##pname(const struct dentry *dent, \ + struct path *pname) \ +{ \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + pathcpy(pname, &SDCARDFS_D(dent)->pname); \ + path_get(pname); \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} \ +static inline void sdcardfs_put_##pname(const struct dentry *dent, \ + struct path *pname) \ +{ \ + path_put(pname); \ + return; \ +} \ +static inline void sdcardfs_set_##pname(const struct dentry *dent, \ + struct path *pname) \ +{ \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + pathcpy(&SDCARDFS_D(dent)->pname, pname); \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} \ +static inline void sdcardfs_reset_##pname(const struct dentry *dent) \ +{ \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + SDCARDFS_D(dent)->pname.dentry = NULL; \ + SDCARDFS_D(dent)->pname.mnt = NULL; \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} \ +static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \ +{ \ + struct path pname; \ + spin_lock(&SDCARDFS_D(dent)->lock); \ + if(SDCARDFS_D(dent)->pname.dentry) { \ + pathcpy(&pname, &SDCARDFS_D(dent)->pname); \ + SDCARDFS_D(dent)->pname.dentry = NULL; \ + SDCARDFS_D(dent)->pname.mnt = NULL; \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + path_put(&pname); \ + } else \ + spin_unlock(&SDCARDFS_D(dent)->lock); \ + return; \ +} + +SDCARDFS_DENT_FUNC(lower_path) +SDCARDFS_DENT_FUNC(orig_path) + +static inline bool sbinfo_has_sdcard_magic(struct sdcardfs_sb_info *sbinfo) +{ + return sbinfo && sbinfo->sb && sbinfo->sb->s_magic == SDCARDFS_SUPER_MAGIC; +} + +/* grab a refererence if we aren't linking to ourself */ +static inline void set_top(struct sdcardfs_inode_info *info, struct inode *top) +{ + struct inode *old_top = NULL; + BUG_ON(IS_ERR_OR_NULL(top)); + if (info->top && info->top != &info->vfs_inode) { + old_top = info->top; + } + if (top != &info->vfs_inode) + igrab(top); + info->top = top; + iput(old_top); +} + +static inline struct inode *grab_top(struct sdcardfs_inode_info *info) +{ + struct inode *top = info->top; + if (top) { + return igrab(top); + } else { + return NULL; + } +} + +static inline void release_top(struct sdcardfs_inode_info *info) +{ + iput(info->top); +} + +static inline int get_gid(struct vfsmount *mnt, struct sdcardfs_inode_info *info) { + struct sdcardfs_vfsmount_options *opts = mnt->data; + + if (opts->gid == AID_SDCARD_RW) { + /* As an optimization, certain trusted system components only run + * as owner but operate across all users. Since we're now handing + * out the sdcard_rw GID only to trusted apps, we're okay relaxing + * the user boundary enforcement for the default view. The UIDs + * assigned to app directories are still multiuser aware. */ + return AID_SDCARD_RW; + } else { + return multiuser_get_uid(info->userid, opts->gid); + } +} +static inline int get_mode(struct vfsmount *mnt, struct sdcardfs_inode_info *info) { + int owner_mode; + int filtered_mode; + struct sdcardfs_vfsmount_options *opts = mnt->data; + int visible_mode = 0775 & ~opts->mask; + + + if (info->perm == PERM_PRE_ROOT) { + /* Top of multi-user view should always be visible to ensure + * secondary users can traverse inside. */ + visible_mode = 0711; + } else if (info->under_android) { + /* Block "other" access to Android directories, since only apps + * belonging to a specific user should be in there; we still + * leave +x open for the default view. */ + if (opts->gid == AID_SDCARD_RW) { + visible_mode = visible_mode & ~0006; + } else { + visible_mode = visible_mode & ~0007; + } + } + owner_mode = info->lower_inode->i_mode & 0700; + filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6)); + return filtered_mode; +} + +static inline int has_graft_path(const struct dentry *dent) +{ + int ret = 0; + + spin_lock(&SDCARDFS_D(dent)->lock); + if (SDCARDFS_D(dent)->orig_path.dentry != NULL) + ret = 1; + spin_unlock(&SDCARDFS_D(dent)->lock); + + return ret; +} + +static inline void sdcardfs_get_real_lower(const struct dentry *dent, + struct path *real_lower) +{ + /* in case of a local obb dentry + * the orig_path should be returned + */ + if(has_graft_path(dent)) + sdcardfs_get_orig_path(dent, real_lower); + else + sdcardfs_get_lower_path(dent, real_lower); +} + +static inline void sdcardfs_put_real_lower(const struct dentry *dent, + struct path *real_lower) +{ + if(has_graft_path(dent)) + sdcardfs_put_orig_path(dent, real_lower); + else + sdcardfs_put_lower_path(dent, real_lower); +} + +extern struct mutex sdcardfs_super_list_lock; +extern struct list_head sdcardfs_super_list; + +/* for packagelist.c */ +extern appid_t get_appid(const char *app_name); +extern appid_t get_ext_gid(const char *app_name); +extern appid_t is_excluded(const char *app_name, userid_t userid); +extern int check_caller_access_to_name(struct inode *parent_node, const struct qstr* name); +extern int open_flags_to_access_mode(int open_flags); +extern int packagelist_init(void); +extern void packagelist_exit(void); + +/* for derived_perm.c */ +#define BY_NAME (1 << 0) +#define BY_USERID (1 << 1) +struct limit_search { + unsigned int flags; + const char *name; + size_t length; + userid_t userid; +}; + +extern void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, + uid_t uid, bool under_android, struct inode *top); +extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); +extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name); +extern void drop_recursive(struct dentry *parent); +extern void fixup_top_recursive(struct dentry *parent); +extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit); + +extern void update_derived_permission_lock(struct dentry *dentry); +void fixup_lower_ownership(struct dentry* dentry, const char *name); +extern int need_graft_path(struct dentry *dentry); +extern int is_base_obbpath(struct dentry *dentry); +extern int is_obbpath_invalid(struct dentry *dentry); +extern int setup_obb_dentry(struct dentry *dentry, struct path *lower_path); + +/* locking helpers */ +static inline struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir = dget_parent(dentry); + mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); + return dir; +} + +static inline void unlock_dir(struct dentry *dir) +{ + mutex_unlock(&dir->d_inode->i_mutex); + dput(dir); +} + +static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t mode) +{ + int err; + struct dentry *dent; + struct iattr attrs; + struct path parent; + + dent = kern_path_locked(path_s, &parent); + if (IS_ERR(dent)) { + err = PTR_ERR(dent); + if (err == -EEXIST) + err = 0; + goto out_unlock; + } + + err = vfs_mkdir2(parent.mnt, parent.dentry->d_inode, dent, mode); + if (err) { + if (err == -EEXIST) + err = 0; + goto out_dput; + } + + attrs.ia_uid = uid; + attrs.ia_gid = gid; + attrs.ia_valid = ATTR_UID | ATTR_GID; + mutex_lock(&dent->d_inode->i_mutex); + notify_change2(parent.mnt, dent, &attrs); + mutex_unlock(&dent->d_inode->i_mutex); + +out_dput: + dput(dent); + +out_unlock: + /* parent dentry locked by lookup_create */ + mutex_unlock(&parent.dentry->d_inode->i_mutex); + path_put(&parent); + return err; +} + +/* + * Return 1, if a disk has enough free space, otherwise 0. + * We assume that any files can not be overwritten. + */ +static inline int check_min_free_space(struct dentry *dentry, size_t size, int dir) +{ + int err; + struct path lower_path; + struct kstatfs statfs; + u64 avail; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + + if (sbi->options.reserved_mb) { + /* Get fs stat of lower filesystem. */ + sdcardfs_get_lower_path(dentry, &lower_path); + err = vfs_statfs(&lower_path, &statfs); + sdcardfs_put_lower_path(dentry, &lower_path); + + if (unlikely(err)) + return 0; + + /* Invalid statfs informations. */ + if (unlikely(statfs.f_bsize == 0)) + return 0; + + /* if you are checking directory, set size to f_bsize. */ + if (unlikely(dir)) + size = statfs.f_bsize; + + /* available size */ + avail = statfs.f_bavail * statfs.f_bsize; + + /* not enough space */ + if ((u64)size > avail) + return 0; + + /* enough space */ + if ((avail - size) > (sbi->options.reserved_mb * 1024 * 1024)) + return 1; + + return 0; + } else + return 1; +} + +/* + * Copies attrs and maintains sdcardfs managed attrs + * Since our permission check handles all special permissions, set those to be open + */ +static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct inode *src) +{ + + dest->i_mode = (src->i_mode & S_IFMT) | S_IRWXU | S_IRWXG | + S_IROTH | S_IXOTH; /* 0775 */ + dest->i_uid = SDCARDFS_I(dest)->d_uid; + dest->i_gid = AID_SDCARD_RW; + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blkbits = src->i_blkbits; + dest->i_flags = src->i_flags; + set_nlink(dest, src->i_nlink); +} + +static inline bool str_case_eq(const char *s1, const char *s2) +{ + return !strcasecmp(s1, s2); +} + +static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2) +{ + return q1->len == q2->len && str_case_eq(q1->name, q2->name); +} + +#define QSTR_LITERAL(string) QSTR_INIT(string, sizeof(string)-1) + +#endif /* not _SDCARDFS_H_ */ diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c new file mode 100755 index 000000000000..edda32b68dc0 --- /dev/null +++ b/fs/sdcardfs/super.c @@ -0,0 +1,275 @@ +/* + * fs/sdcardfs/super.c + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd + * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, + * Sunghwan Yun, Sungjong Seo + * + * This program has been developed as a stackable file system based on + * the WrapFS which written by + * + * Copyright (c) 1998-2011 Erez Zadok + * Copyright (c) 2009 Shrikar Archak + * Copyright (c) 2003-2011 Stony Brook University + * Copyright (c) 2003-2011 The Research Foundation of SUNY + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#include "sdcardfs.h" + +/* + * The inode cache is used with alloc_inode for both our inode info and the + * vfs inode. + */ +static struct kmem_cache *sdcardfs_inode_cachep; + +/* final actions when unmounting a file system */ +static void sdcardfs_put_super(struct super_block *sb) +{ + struct sdcardfs_sb_info *spd; + struct super_block *s; + + spd = SDCARDFS_SB(sb); + if (!spd) + return; + + if(spd->obbpath_s) { + kfree(spd->obbpath_s); + path_put(&spd->obbpath); + } + + /* decrement lower super references */ + s = sdcardfs_lower_super(sb); + sdcardfs_set_lower_super(sb, NULL); + atomic_dec(&s->s_active); + + kfree(spd); + sb->s_fs_info = NULL; +} + +static int sdcardfs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + int err; + struct path lower_path; + u32 min_blocks; + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); + + sdcardfs_get_lower_path(dentry, &lower_path); + err = vfs_statfs(&lower_path, buf); + sdcardfs_put_lower_path(dentry, &lower_path); + + if (sbi->options.reserved_mb) { + /* Invalid statfs informations. */ + if (buf->f_bsize == 0) { + printk(KERN_ERR "Returned block size is zero.\n"); + return -EINVAL; + } + + min_blocks = ((sbi->options.reserved_mb * 1024 * 1024)/buf->f_bsize); + buf->f_blocks -= min_blocks; + + if (buf->f_bavail > min_blocks) + buf->f_bavail -= min_blocks; + else + buf->f_bavail = 0; + + /* Make reserved blocks invisiable to media storage */ + buf->f_bfree = buf->f_bavail; + } + + /* set return buf to our f/s to avoid confusing user-level utils */ + buf->f_type = SDCARDFS_SUPER_MAGIC; + + return err; +} + +/* + * @flags: numeric mount options + * @options: mount options string + */ +static int sdcardfs_remount_fs(struct super_block *sb, int *flags, char *options) +{ + int err = 0; + + /* + * The VFS will take care of "ro" and "rw" flags among others. We + * can safely accept a few flags (RDONLY, MANDLOCK), and honor + * SILENT, but anything else left over is an error. + */ + if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT)) != 0) { + printk(KERN_ERR + "sdcardfs: remount flags 0x%x unsupported\n", *flags); + err = -EINVAL; + } + + return err; +} + +/* + * @mnt: mount point we are remounting + * @sb: superblock we are remounting + * @flags: numeric mount options + * @options: mount options string + */ +static int sdcardfs_remount_fs2(struct vfsmount *mnt, struct super_block *sb, + int *flags, char *options) +{ + int err = 0; + + /* + * The VFS will take care of "ro" and "rw" flags among others. We + * can safely accept a few flags (RDONLY, MANDLOCK), and honor + * SILENT, but anything else left over is an error. + */ + if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT | MS_REMOUNT)) != 0) { + printk(KERN_ERR + "sdcardfs: remount flags 0x%x unsupported\n", *flags); + err = -EINVAL; + } + printk(KERN_INFO "Remount options were %s for vfsmnt %p.\n", options, mnt); + err = parse_options_remount(sb, options, *flags & ~MS_SILENT, mnt->data); + + + return err; +} + +static void* sdcardfs_clone_mnt_data(void *data) { + struct sdcardfs_vfsmount_options* opt = kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL); + struct sdcardfs_vfsmount_options* old = data; + if(!opt) return NULL; + opt->gid = old->gid; + opt->mask = old->mask; + return opt; +} + +static void sdcardfs_copy_mnt_data(void *data, void *newdata) { + struct sdcardfs_vfsmount_options* old = data; + struct sdcardfs_vfsmount_options* new = newdata; + old->gid = new->gid; + old->mask = new->mask; +} + +/* + * Called by iput() when the inode reference count reached zero + * and the inode is not hashed anywhere. Used to clear anything + * that needs to be, before the inode is completely destroyed and put + * on the inode free list. + */ +static void sdcardfs_evict_inode(struct inode *inode) +{ + struct inode *lower_inode; + + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); + /* + * Decrement a reference to a lower_inode, which was incremented + * by our read_inode when it was created initially. + */ + lower_inode = sdcardfs_lower_inode(inode); + sdcardfs_set_lower_inode(inode, NULL); + set_top(SDCARDFS_I(inode), inode); + iput(lower_inode); +} + +static struct inode *sdcardfs_alloc_inode(struct super_block *sb) +{ + struct sdcardfs_inode_info *i; + + i = kmem_cache_alloc(sdcardfs_inode_cachep, GFP_KERNEL); + if (!i) + return NULL; + + /* memset everything up to the inode to 0 */ + memset(i, 0, offsetof(struct sdcardfs_inode_info, vfs_inode)); + + i->vfs_inode.i_version = 1; + return &i->vfs_inode; +} + +static void sdcardfs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode)); +} + +/* sdcardfs inode cache constructor */ +static void init_once(void *obj) +{ + struct sdcardfs_inode_info *i = obj; + + inode_init_once(&i->vfs_inode); +} + +int sdcardfs_init_inode_cache(void) +{ + int err = 0; + + sdcardfs_inode_cachep = + kmem_cache_create("sdcardfs_inode_cache", + sizeof(struct sdcardfs_inode_info), 0, + SLAB_RECLAIM_ACCOUNT, init_once); + if (!sdcardfs_inode_cachep) + err = -ENOMEM; + return err; +} + +/* sdcardfs inode cache destructor */ +void sdcardfs_destroy_inode_cache(void) +{ + if (sdcardfs_inode_cachep) + kmem_cache_destroy(sdcardfs_inode_cachep); +} + +/* + * Used only in nfs, to kill any pending RPC tasks, so that subsequent + * code can actually succeed and won't leave tasks that need handling. + */ +static void sdcardfs_umount_begin(struct super_block *sb) +{ + struct super_block *lower_sb; + + lower_sb = sdcardfs_lower_super(sb); + if (lower_sb && lower_sb->s_op && lower_sb->s_op->umount_begin) + lower_sb->s_op->umount_begin(lower_sb); +} + +static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, struct dentry *root) +{ + struct sdcardfs_sb_info *sbi = SDCARDFS_SB(root->d_sb); + struct sdcardfs_mount_options *opts = &sbi->options; + struct sdcardfs_vfsmount_options *vfsopts = mnt->data; + + if (opts->fs_low_uid != 0) + seq_printf(m, ",fsuid=%u", opts->fs_low_uid); + if (opts->fs_low_gid != 0) + seq_printf(m, ",fsgid=%u", opts->fs_low_gid); + if (vfsopts->gid != 0) + seq_printf(m, ",gid=%u", vfsopts->gid); + if (opts->multiuser) + seq_printf(m, ",multiuser"); + if (vfsopts->mask) + seq_printf(m, ",mask=%u", vfsopts->mask); + if (opts->fs_user_id) + seq_printf(m, ",userid=%u", opts->fs_user_id); + if (opts->reserved_mb != 0) + seq_printf(m, ",reserved=%uMB", opts->reserved_mb); + + return 0; +}; + +const struct super_operations sdcardfs_sops = { + .put_super = sdcardfs_put_super, + .statfs = sdcardfs_statfs, + .remount_fs = sdcardfs_remount_fs, + .remount_fs2 = sdcardfs_remount_fs2, + .clone_mnt_data = sdcardfs_clone_mnt_data, + .copy_mnt_data = sdcardfs_copy_mnt_data, + .evict_inode = sdcardfs_evict_inode, + .umount_begin = sdcardfs_umount_begin, + .show_options2 = sdcardfs_show_options, + .alloc_inode = sdcardfs_alloc_inode, + .destroy_inode = sdcardfs_destroy_inode, + .drop_inode = generic_delete_inode, +}; diff --git a/fs/super.c b/fs/super.c index f94beee9c9bc..bc02e7246460 100644 --- a/fs/super.c +++ b/fs/super.c @@ -675,7 +675,8 @@ struct super_block *user_get_super(dev_t dev) } /** - * do_remount_sb - asks filesystem to change mount options. + * do_remount_sb2 - asks filesystem to change mount options. + * @mnt: mount we are looking at * @sb: superblock in question * @flags: numeric part of options * @data: the rest of options @@ -683,7 +684,7 @@ struct super_block *user_get_super(dev_t dev) * * Alters the mount options of a mounted file system. */ -int do_remount_sb(struct super_block *sb, int flags, void *data, int force) +int do_remount_sb2(struct vfsmount *mnt, struct super_block *sb, int flags, void *data, int force) { int retval; int remount_ro; @@ -717,7 +718,16 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) sync_filesystem(sb); - if (sb->s_op->remount_fs) { + if (mnt && sb->s_op->remount_fs2) { + retval = sb->s_op->remount_fs2(mnt, sb, &flags, data); + if (retval) { + if (!force) + goto cancel_readonly; + /* If forced remount, go ahead despite any errors */ + WARN(1, "forced remount of a %s fs returned %i\n", + sb->s_type->name, retval); + } + } else if (sb->s_op->remount_fs) { retval = sb->s_op->remount_fs(sb, &flags, data); if (retval) { if (!force) @@ -749,6 +759,11 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) return retval; } +int do_remount_sb(struct super_block *sb, int flags, void *data, int force) +{ + return do_remount_sb2(NULL, sb, flags, data, force); +} + static void do_emergency_remount(struct work_struct *work) { struct super_block *sb, *p = NULL; @@ -1068,7 +1083,7 @@ struct dentry *mount_single(struct file_system_type *fs_type, EXPORT_SYMBOL(mount_single); struct dentry * -mount_fs(struct file_system_type *type, int flags, const char *name, void *data) +mount_fs(struct file_system_type *type, int flags, const char *name, struct vfsmount *mnt, void *data) { struct dentry *root; struct super_block *sb; @@ -1085,7 +1100,10 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data) goto out_free_secdata; } - root = type->mount(type, flags, name, data); + if (type->mount2) + root = type->mount2(mnt, type, flags, name, data); + else + root = type->mount(type, flags, name, data); if (IS_ERR(root)) { error = PTR_ERR(root); goto out_free_secdata; diff --git a/fs/utimes.c b/fs/utimes.c index f4fb7eca10e8..7216a079d569 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -96,13 +96,13 @@ static int utimes_common(struct path *path, struct timespec *times) goto mnt_drop_write_and_out; if (!inode_owner_or_capable(inode)) { - error = inode_permission(inode, MAY_WRITE); + error = inode_permission2(path->mnt, inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; } } mutex_lock(&inode->i_mutex); - error = notify_change(path->dentry, &newattrs); + error = notify_change2(path->mnt, path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); mnt_drop_write_and_out: diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c68b8f9928c8..64f0cf47f25c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -742,6 +742,7 @@ extern void __blk_put_request(struct request_queue *, struct request *); extern struct request *blk_get_request(struct request_queue *, int, gfp_t); extern struct request *blk_make_request(struct request_queue *, struct bio *, gfp_t); +extern void blk_rq_set_block_pc(struct request *); extern void blk_requeue_request(struct request_queue *, struct request *); extern int blk_reinsert_request(struct request_queue *q, struct request *rq); extern bool blk_reinsert_req_sup(struct request_queue *q); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c1999d1fe6f8..a660e2b1a287 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -158,6 +158,7 @@ struct dentry_operations { char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); + void (*d_canonical_path)(const struct path *, struct path *); } ____cacheline_aligned; /* @@ -410,6 +411,13 @@ static inline bool d_mountpoint(struct dentry *dentry) return dentry->d_flags & DCACHE_MOUNTED; } +static inline bool d_is_su(const struct dentry *dentry) +{ + return dentry && + dentry->d_name.len == 2 && + !memcmp(dentry->d_name.name, "su", 2); +} + extern int sysctl_vfs_cache_pressure; #endif /* __LINUX_DCACHE_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 918917843389..15817daf8fa8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1441,13 +1441,20 @@ extern bool inode_owner_or_capable(const struct inode *inode); * VFS helper functions.. */ extern int vfs_create(struct inode *, struct dentry *, umode_t, bool); +extern int vfs_create2(struct vfsmount *, struct inode *, struct dentry *, umode_t, bool); extern int vfs_mkdir(struct inode *, struct dentry *, umode_t); +extern int vfs_mkdir2(struct vfsmount *, struct inode *, struct dentry *, umode_t); extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); +extern int vfs_mknod2(struct vfsmount *, struct inode *, struct dentry *, umode_t, dev_t); extern int vfs_symlink(struct inode *, struct dentry *, const char *); extern int vfs_link(struct dentry *, struct inode *, struct dentry *); +extern int vfs_link2(struct vfsmount *, struct dentry *, struct inode *, struct dentry *); extern int vfs_rmdir(struct inode *, struct dentry *); +extern int vfs_rmdir2(struct vfsmount *, struct inode *, struct dentry *); extern int vfs_unlink(struct inode *, struct dentry *); +extern int vfs_unlink2(struct vfsmount *, struct inode *, struct dentry *); extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +extern int vfs_rename2(struct vfsmount *, struct inode *, struct dentry *, struct inode *, struct dentry *); /* * VFS dentry helper functions. @@ -1496,6 +1503,18 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); * to have different dirent layouts depending on the binary type. */ typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); +struct dir_context { + const filldir_t actor; + loff_t pos; + bool romnt; +}; + +static inline bool dir_emit(struct dir_context *ctx, + const char *name, int namelen, + u64 ino, unsigned type) +{ + return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0; +} struct block_device_operations; /* These macros are for out of kernel modules to test that @@ -1512,6 +1531,7 @@ struct file_operations { ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); + int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); @@ -1539,6 +1559,7 @@ struct inode_operations { struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); void * (*follow_link) (struct dentry *, struct nameidata *); int (*permission) (struct inode *, int); + int (*permission2) (struct vfsmount *, struct inode *, int); struct posix_acl * (*get_acl)(struct inode *, int); int (*readlink) (struct dentry *, char __user *,int); @@ -1554,6 +1575,7 @@ struct inode_operations { int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); int (*setattr) (struct dentry *, struct iattr *); + int (*setattr2) (struct vfsmount *, struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); @@ -1593,11 +1615,13 @@ struct super_operations { int (*unfreeze_fs) (struct super_block *); int (*statfs) (struct dentry *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); + int (*remount_fs2) (struct vfsmount *, struct super_block *, int *, char *); void *(*clone_mnt_data) (void *); void (*copy_mnt_data) (void *, void *); void (*umount_begin) (struct super_block *); int (*show_options)(struct seq_file *, struct dentry *); + int (*show_options2)(struct vfsmount *,struct seq_file *, struct dentry *); int (*show_devname)(struct seq_file *, struct dentry *); int (*show_path)(struct seq_file *, struct dentry *); int (*show_stats)(struct seq_file *, struct dentry *); @@ -1804,6 +1828,8 @@ struct file_system_type { #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); + struct dentry *(*mount2) (struct vfsmount *, struct file_system_type *, int, + const char *, void *); void *(*alloc_mnt_data) (void); void (*kill_sb) (struct super_block *); struct module *owner; @@ -1993,6 +2019,8 @@ struct filename { extern long vfs_truncate(struct path *, loff_t); extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, struct file *filp); +extern int do_truncate2(struct vfsmount *, struct dentry *, loff_t start, + unsigned int time_attrs, struct file *filp); extern int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len); extern long do_sys_open(int dfd, const char __user *filename, int flags, @@ -2200,7 +2228,9 @@ extern void emergency_remount(void); extern sector_t bmap(struct inode *, sector_t); #endif extern int notify_change(struct dentry *, struct iattr *); +extern int notify_change2(struct vfsmount *, struct dentry *, struct iattr *); extern int inode_permission(struct inode *, int); +extern int inode_permission2(struct vfsmount *, struct inode *, int); extern int generic_permission(struct inode *, int); static inline bool execute_ok(struct inode *inode) @@ -2492,6 +2522,7 @@ loff_t inode_get_bytes(struct inode *inode); void inode_set_bytes(struct inode *inode, loff_t bytes); extern int vfs_readdir(struct file *, filldir_t, void *); +extern int iterate_dir(struct file *, struct dir_context *); extern int vfs_stat(const char __user *, struct kstat *); extern int vfs_lstat(const char __user *, struct kstat *); diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 46da02410a09..25de5e73845c 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -3,6 +3,7 @@ #include +struct net; struct sock; struct inet_hashinfo; struct nlattr; @@ -23,6 +24,10 @@ struct inet_diag_handler { void (*idiag_get_info)(struct sock *sk, struct inet_diag_msg *r, void *info); + + int (*destroy)(struct sk_buff *in_skb, + struct inet_diag_req_v2 *req); + __u16 idiag_type; }; @@ -39,6 +44,10 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb, const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req); +struct sock *inet_diag_find_one_icsk(struct net *net, + struct inet_hashinfo *hashinfo, + struct inet_diag_req_v2 *req); + int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk); extern int inet_diag_register(const struct inet_diag_handler *handler); diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index e79d4283ae40..153f8da18120 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -272,9 +272,9 @@ static inline struct inet6_timewait_sock *inet6_twsk(const struct sock *sk) } #if IS_ENABLED(CONFIG_IPV6) -static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) +static inline struct ipv6_pinfo *inet6_sk(const struct sock *__sk) { - return inet_sk(__sk)->pinet6; + return sk_fullsock(__sk) ? inet_sk(__sk)->pinet6 : NULL; } static inline struct inet6_request_sock * diff --git a/include/linux/mm.h b/include/linux/mm.h index 53c8fccfba15..2e99382a2c7a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -47,6 +47,17 @@ extern int sysctl_legacy_va_layout; #define sysctl_legacy_va_layout 0 #endif +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS +extern const int mmap_rnd_bits_min; +extern const int mmap_rnd_bits_max; +extern int mmap_rnd_bits __read_mostly; +#endif +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS +extern const int mmap_rnd_compat_bits_min; +extern const int mmap_rnd_compat_bits_max; +extern int mmap_rnd_compat_bits __read_mostly; +#endif + #include #include #include diff --git a/include/linux/namei.h b/include/linux/namei.h index 5a5ff57ceed4..f10c7f29f5e0 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -74,6 +74,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct path *); extern struct dentry *lookup_one_len(const char *, struct dentry *, int); +extern struct dentry *lookup_one_len2(const char *, struct vfsmount *mnt, struct dentry *, int); extern int follow_down_one(struct path *); extern int follow_down(struct path *); diff --git a/include/linux/random.h b/include/linux/random.h index bf9085e89fb5..1b91d7d186e7 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -24,6 +24,7 @@ extern const struct file_operations random_fops, urandom_fops; #endif unsigned int get_random_int(void); +unsigned long get_random_long(void); unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len); u32 prandom_u32(void); diff --git a/include/linux/sched.h b/include/linux/sched.h index f952e4364a16..a12909ac8b53 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -55,6 +55,12 @@ struct sched_param { #include +int su_instances(void); +bool su_running(void); +bool su_visible(void); +void su_exec(void); +void su_exit(void); + #define SCHED_ATTR_SIZE_VER0 48 /* sizeof first published struct */ /* @@ -1783,6 +1789,8 @@ static inline void sched_set_io_is_busy(int val) {}; #define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ #define PF_WAKE_UP_IDLE 0x80000000 /* try to wake up on an idle CPU */ +#define PF_SU 0x00000002 /* task is su */ + /* * Only the _current_ task can read/write to tsk->flags, but other * tasks can access tsk->flags in readonly mode for example diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index 46cca4c06848..1a3b383ba4e6 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -11,6 +11,7 @@ struct sock; struct sock_diag_handler { __u8 family; int (*dump)(struct sk_buff *skb, struct nlmsghdr *nlh); + int (*destroy)(struct sk_buff *skb, struct nlmsghdr *nlh); }; int sock_diag_register(const struct sock_diag_handler *h); @@ -26,4 +27,5 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr); int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, struct sk_buff *skb, int attrtype); +int sock_diag_destroy(struct sock *sk, int err); #endif diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index 8e522cbcef29..cb4c867a523f 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -64,6 +64,9 @@ static inline gid_t __kgid_val(kgid_t gid) #define GLOBAL_ROOT_UID KUIDT_INIT(0) #define GLOBAL_ROOT_GID KGIDT_INIT(0) +#define GLOBAL_SYSTEM_UID KUIDT_INIT(1000) +#define GLOBAL_SYSTEM_GID KGIDT_INIT(1000) + #define INVALID_UID KUIDT_INIT(-1) #define INVALID_GID KGIDT_INIT(-1) diff --git a/include/net/sock.h b/include/net/sock.h index 486c816d0d5b..0c411d311a02 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -67,6 +67,7 @@ #include #include #include +#include struct cgroup; struct cgroup_subsys; @@ -1008,6 +1009,7 @@ struct proto { void (*destroy_cgroup)(struct mem_cgroup *memcg); struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg); #endif + int (*diag_destroy)(struct sock *sk, int err); }; /* @@ -2264,6 +2266,15 @@ static inline struct sock *skb_steal_sock(struct sk_buff *skb) return NULL; } +/* This helper checks if a socket is a full socket, + * ie _not_ a timewait or request socket. + * TODO: Check for TCPF_NEW_SYN_RECV when that starts to exist. + */ +static inline bool sk_fullsock(const struct sock *sk) +{ + return (1 << sk->sk_state) & ~(TCPF_TIME_WAIT); +} + extern void sock_enable_timestamp(struct sock *sk, int flag); extern int sock_get_timestamp(struct sock *, struct timeval __user *); extern int sock_get_timestampns(struct sock *, struct timespec __user *); diff --git a/include/net/tcp.h b/include/net/tcp.h index 837b0877836d..eb3efd136f01 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1059,6 +1059,8 @@ extern void tcp_set_state(struct sock *sk, int state); extern void tcp_done(struct sock *sk); +int tcp_abort(struct sock *sk, int err); + static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) { rx_opt->dsack = 0; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 60bb2f9f7b74..c5902767c595 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -343,6 +343,7 @@ enum fuse_opcode { FUSE_BATCH_FORGET = 42, FUSE_FALLOCATE = 43, FUSE_READDIRPLUS = 44, + FUSE_CANONICAL_PATH= 2016, /* CUSE specific operations */ CUSE_INIT = 4096, diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 2944278a8ba7..04c5ff2fc598 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -52,6 +52,8 @@ #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" +#define SDCARDFS_SUPER_MAGIC 0xb550ca10 + #define SMB_SUPER_MAGIC 0x517B #define CGROUP_SUPER_MAGIC 0x27e0eb diff --git a/include/uapi/linux/sock_diag.h b/include/uapi/linux/sock_diag.h index b00e29efb161..472adbb711ed 100644 --- a/include/uapi/linux/sock_diag.h +++ b/include/uapi/linux/sock_diag.h @@ -4,6 +4,7 @@ #include #define SOCK_DIAG_BY_FAMILY 20 +#define SOCK_DESTROY_BACKPORT 21 struct sock_diag_req { __u8 sdiag_family; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7576ce541889..2803a2cd4ca4 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -739,6 +739,18 @@ enum v4l2_mpeg_vidc_extradata { V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO = 19, V4L2_MPEG_VIDC_EXTRADATA_LTR = 20, V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI = 21, +#define V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI \ + V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI + V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI = 26, +#define V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI \ + V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI + V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI = 27, +#define V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY \ + V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY + V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY = 28, +#define V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE \ + V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE + V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE = 29, }; #define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26) @@ -1003,6 +1015,31 @@ enum v4l2_mpeg_vidc_video_priority { #define V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 75) +#define V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 80) + +#define V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 81) + +enum v4l2_cid_mpeg_vidc_video_full_range { + V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE = 0, + V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_ENABLE = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 82) + +#define V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 83) + +#define V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 87) + +enum v4l2_cid_mpeg_vidc_video_vpe_csc_type_enable { + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_DISABLE = 0, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE = 1 +}; + /* Camera class control IDs */ #define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) diff --git a/include/uapi/media/msm_vidc.h b/include/uapi/media/msm_vidc.h index 6fa53ad7997b..2fda501aa004 100644 --- a/include/uapi/media/msm_vidc.h +++ b/include/uapi/media/msm_vidc.h @@ -43,6 +43,19 @@ struct msm_vidc_mpeg2_seqdisp_payload { unsigned int disp_width; unsigned int disp_height; }; + +struct msm_vidc_vc1_seqdisp_payload { + unsigned int prog_seg_format; + unsigned int uv_sampl_fmt; + unsigned int color_format; + unsigned int color_primaries; + unsigned int transfer_char; + unsigned int matrix_coeffs; + unsigned int aspect_ratio; + unsigned int aspect_horiz; + unsigned int aspect_vert; +}; + struct msm_vidc_input_crop_payload { unsigned int size; unsigned int version; @@ -109,6 +122,44 @@ struct msm_vidc_s3d_frame_packing_payload { unsigned int fpa_extension_flag; }; +struct msm_vidc_vpx_colorspace_payload { + unsigned int color_space; + unsigned int yuv_range_flag; + unsigned int sumsampling_x; + unsigned int sumsampling_y; +}; + +struct msm_vidc_mastering_display_colour_sei_payload { + unsigned int nDisplayPrimariesX[3]; + unsigned int nDisplayPrimariesY[3]; + unsigned int nWhitePointX; + unsigned int nWhitePointY; + unsigned int nMaxDisplayMasteringLuminance; + unsigned int nMinDisplayMasteringLuminance; +}; + +struct msm_vidc_content_light_level_sei_payload { + unsigned int nMaxContentLight; + unsigned int nMaxPicAverageLight; +}; + +struct msm_vidc_vui_display_info_payload { + unsigned int video_signal_present_flag; + unsigned int video_format; + unsigned int bit_depth_y; + unsigned int bit_depth_c; + unsigned int video_full_range_flag; + unsigned int color_description_present_flag; + unsigned int color_primaries; + unsigned int transfer_characteristics; + unsigned int matrix_coefficients; + unsigned int chroma_location_info_present_flag; + unsigned int chroma_format_idc; + unsigned int separate_color_plane_flag; + unsigned int chroma_sample_loc_type_top_field; + unsigned int chroma_sample_loc_type_bottom_field; +}; + enum msm_vidc_extradata_type { MSM_VIDC_EXTRADATA_NONE = 0x00000000, MSM_VIDC_EXTRADATA_MB_QUANTIZATION = 0x00000001, @@ -124,8 +175,17 @@ enum msm_vidc_extradata_type { MSM_VIDC_EXTRADATA_STREAM_USERDATA = 0x0000000E, MSM_VIDC_EXTRADATA_FRAME_QP = 0x0000000F, MSM_VIDC_EXTRADATA_FRAME_BITS_INFO = 0x00000010, +#define MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI \ + MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI + MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI = 0x00000015, +#define MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI \ + MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI + MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI = 0x00000016, MSM_VIDC_EXTRADATA_INPUT_CROP = 0x0700000E, MSM_VIDC_EXTRADATA_DIGITAL_ZOOM = 0x07000010, +#define MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO \ + MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO + MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO = 0x070000011, MSM_VIDC_EXTRADATA_MULTISLICE_INFO = 0x7F100000, MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB = 0x7F100001, MSM_VIDC_EXTRADATA_INDEX = 0x7F100002, @@ -133,6 +193,9 @@ enum msm_vidc_extradata_type { MSM_VIDC_EXTRADATA_METADATA_LTR = 0x7F100004, MSM_VIDC_EXTRADATA_METADATA_FILLER = 0x7FE00002, MSM_VIDC_EXTRADATA_METADATA_MBI = 0x7F100005, +#define MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO \ + MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO + MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO = 0x7F100006, }; enum msm_vidc_interlace_type { MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE = 0x01, @@ -151,4 +214,79 @@ enum msm_vidc_userdata_type { MSM_VIDC_USERDATA_TYPE_TOP_FIELD = 0x2, MSM_VIDC_USERDATA_TYPE_BOTTOM_FIELD = 0x3, }; +/* See colour_primaries of ISO/IEC 14496 for significance */ +enum msm_vidc_h264_color_primaries_values { + MSM_VIDC_RESERVED_1 = 0, + MSM_VIDC_BT709_5 = 1, + MSM_VIDC_UNSPECIFIED = 2, + MSM_VIDC_RESERVED_2 = 3, + MSM_VIDC_BT470_6_M = 4, + MSM_VIDC_BT601_6_625 = 5, + MSM_VIDC_BT470_6_BG = MSM_VIDC_BT601_6_625, + MSM_VIDC_BT601_6_525 = 6, + MSM_VIDC_SMPTE_240M = 7, + MSM_VIDC_GENERIC_FILM = 8, + MSM_VIDC_BT2020 = 9, +}; + +enum msm_vidc_vp9_color_primaries_values { + MSM_VIDC_CS_UNKNOWN, + MSM_VIDC_CS_BT_601, + MSM_VIDC_CS_BT_709, + MSM_VIDC_CS_SMPTE_170, + MSM_VIDC_CS_SMPTE_240, + MSM_VIDC_CS_BT_2020, + MSM_VIDC_CS_RESERVED, + MSM_VIDC_CS_RGB, +}; + +enum msm_vidc_h264_matrix_coeff_values { + MSM_VIDC_MATRIX_RGB = 0, + MSM_VIDC_MATRIX_BT_709_5 = 1, + MSM_VIDC_MATRIX_UNSPECIFIED = 2, + MSM_VIDC_MATRIX_RESERVED = 3, + MSM_VIDC_MATRIX_FCC_47 = 4, + MSM_VIDC_MATRIX_601_6_625 = 5, + MSM_VIDC_MATRIX_BT470_BG = MSM_VIDC_MATRIX_601_6_625, + MSM_VIDC_MATRIX_601_6_525 = 6, + MSM_VIDC_MATRIX_SMPTE_170M = MSM_VIDC_MATRIX_601_6_525, + MSM_VIDC_MATRIX_SMPTE_240M = 7, + MSM_VIDC_MATRIX_Y_CG_CO = 8, + MSM_VIDC_MATRIX_BT_2020 = 9, + MSM_VIDC_MATRIX_BT_2020_CONST = 10, +}; + +enum msm_vidc_h264_transfer_chars_values { + MSM_VIDC_TRANSFER_RESERVED_1 = 0, + MSM_VIDC_TRANSFER_BT709_5 = 1, + MSM_VIDC_TRANSFER_UNSPECIFIED = 2, + MSM_VIDC_TRANSFER_RESERVED_2 = 3, + MSM_VIDC_TRANSFER_BT_470_6_M = 4, + MSM_VIDC_TRANSFER_BT_470_6_BG = 5, + MSM_VIDC_TRANSFER_601_6_625 = 6, + MSM_VIDC_TRANSFER_601_6_525 = MSM_VIDC_TRANSFER_601_6_625, + MSM_VIDC_TRANSFER_SMPTE_240M = 7, + MSM_VIDC_TRANSFER_LINEAR = 8, + MSM_VIDC_TRANSFER_LOG_100_1 = 9, + MSM_VIDC_TRANSFER_LOG_100_SQRT10_1 = 10, + MSM_VIDC_TRANSFER_IEC_61966 = 11, + MSM_VIDC_TRANSFER_BT_1361 = 12, + MSM_VIDC_TRANSFER_SRGB = 13, + MSM_VIDC_TRANSFER_BT_2020_10 = 14, + MSM_VIDC_TRANSFER_BT_2020_12 = 15, +}; +enum msm_vidc_video_format { + MSM_VIDC_COMPONENT, + MSM_VIDC_PAL, + MSM_VIDC_NTSC, + MSM_VIDC_SECAM, + MSM_VIDC_MAC, + MSM_VIDC_UNSPECIFIED_FORMAT, + MSM_VIDC_RESERVED_1_FORMAT, + MSM_VIDC_RESERVED_2_FORMAT, +}; +enum msm_vidc_color_desc_flag { + MSM_VIDC_COLOR_DESC_NOT_PRESENT, + MSM_VIDC_COLOR_DESC_PRESENT, +}; #endif diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h index a9f3c6fc3f57..d8c0c4307fca 100644 --- a/include/uapi/scsi/sg.h +++ b/include/uapi/scsi/sg.h @@ -4,77 +4,34 @@ #include /* - History: - Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user - process control of SCSI devices. - Development Sponsored by Killy Corp. NY NY -Original driver (sg.h): -* Copyright (C) 1992 Lawrence Foard -Version 2 and 3 extensions to driver: -* Copyright (C) 1998 - 2006 Douglas Gilbert - - Version: 3.5.34 (20060920) - This version is for 2.6 series kernels. - - For a full changelog see http://www.torque.net/sg - -Map of SG verions to the Linux kernels in which they appear: - ---------- ---------------------------------- - original all kernels < 2.2.6 - 2.1.40 2.2.20 - 3.0.x optional version 3 sg driver for 2.2 series - 3.1.17++ 2.4.0++ - 3.5.30++ 2.6.0++ - -Major new features in SG 3.x driver (cf SG 2.x drivers) - - SG_IO ioctl() combines function if write() and read() - - new interface (sg_io_hdr_t) but still supports old interface - - scatter/gather in user space, direct IO, and mmap supported - - The normal action of this driver is to use the adapter (HBA) driver to DMA - data into kernel buffers and then use the CPU to copy the data into the - user space (vice versa for writes). That is called "indirect" IO due to - the double handling of data. There are two methods offered to remove the - redundant copy: 1) direct IO and 2) using the mmap() system call to map - the reserve buffer (this driver has one reserve buffer per fd) into the - user space. Both have their advantages. - In terms of absolute speed mmap() is faster. If speed is not a concern, - indirect IO should be fine. Read the documentation for more information. - - ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or - 'echo 1 > /sys/module/sg/parameters/allow_dio' is needed. - That attribute is 0 by default. ** - - Historical note: this SCSI pass-through driver has been known as "sg" for - a decade. In broader kernel discussions "sg" is used to refer to scatter - gather techniques. The context should clarify which "sg" is referred to. - - Documentation - ============= - A web site for the SG device driver can be found at: - http://www.torque.net/sg [alternatively check the MAINTAINERS file] - The documentation for the sg version 3 driver can be found at: - http://www.torque.net/sg/p/sg_v3_ho.html - This is a rendering from DocBook source [change the extension to "sgml" - or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon). - The SG_IO ioctl is now found in other parts kernel (e.g. the block layer). - For more information see http://www.torque.net/sg/sg_io.html - - The older, version 2 documents discuss the original sg interface in detail: - http://www.torque.net/sg/p/scsi-generic.txt - http://www.torque.net/sg/p/scsi-generic_long.txt - Also available: /Documentation/scsi/scsi-generic.txt - - Utility and test programs are available at the sg web site. They are - packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils - (for the lk 2.2 series). -*/ + * History: + * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user + * process control of SCSI devices. + * Development Sponsored by Killy Corp. NY NY + * + * Original driver (sg.h): + * Copyright (C) 1992 Lawrence Foard + * Version 2 and 3 extensions to driver: + * Copyright (C) 1998 - 2014 Douglas Gilbert + * + * Version: 3.5.36 (20140603) + * This version is for 2.6 and 3 series kernels. + * + * Documentation + * ============= + * A web site for the SG device driver can be found at: + * http://sg.danny.cz/sg [alternatively check the MAINTAINERS file] + * The documentation for the sg version 3 driver can be found at: + * http://sg.danny.cz/sg/p/sg_v3_ho.html + * Also see: /Documentation/scsi/scsi-generic.txt + * + * For utility and test programs see: http://sg.danny.cz/sg/sg3_utils.html + */ #ifdef __KERNEL__ extern int sg_big_buff; /* for sysctl */ #endif -/* New interface introduced in the 3.x SG drivers follows */ typedef struct sg_iovec /* same structure as used by readv() Linux system */ { /* call. It defines one scatter-gather element. */ @@ -87,7 +44,7 @@ typedef struct sg_io_hdr { int interface_id; /* [i] 'S' for SCSI generic (required) */ int dxfer_direction; /* [i] data transfer direction */ - unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char cmd_len; /* [i] SCSI command length */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ unsigned short iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len; /* [i] byte count of data transfer */ diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 82bb5e81ef57..f912e4f7deaf 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -751,7 +751,7 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir, } mode &= ~current_umask(); - ret = vfs_create(dir, path->dentry, mode, true); + ret = vfs_create2(path->mnt, dir, path->dentry, mode, true); path->dentry->d_fsdata = NULL; if (ret) return ERR_PTR(ret); @@ -767,7 +767,7 @@ static struct file *do_open(struct path *path, int oflag) if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) return ERR_PTR(-EINVAL); acc = oflag2acc[oflag & O_ACCMODE]; - if (inode_permission(path->dentry->d_inode, acc)) + if (inode_permission2(path->mnt, path->dentry->d_inode, acc)) return ERR_PTR(-EACCES); return dentry_open(path, oflag, current_cred()); } @@ -800,7 +800,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ro = mnt_want_write(mnt); /* we'll drop it in any case */ error = 0; mutex_lock(&root->d_inode->i_mutex); - path.dentry = lookup_one_len(name->name, root, strlen(name->name)); + path.dentry = lookup_one_len2(name->name, mnt, root, strlen(name->name)); if (IS_ERR(path.dentry)) { error = PTR_ERR(path.dentry); goto out_putfd; @@ -871,7 +871,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) if (err) goto out_name; mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT); - dentry = lookup_one_len(name->name, mnt->mnt_root, + dentry = lookup_one_len2(name->name, mnt, mnt->mnt_root, strlen(name->name)); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); @@ -883,7 +883,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) err = -ENOENT; } else { ihold(inode); - err = vfs_unlink(dentry->d_parent->d_inode, dentry); + err = vfs_unlink2(mnt, dentry->d_parent->d_inode, dentry); } dput(dentry); diff --git a/kernel/exit.c b/kernel/exit.c index 540bad43812d..e58c525cbc3a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -777,6 +777,10 @@ void do_exit(long code) sched_exit(tsk); + if (tsk->flags & PF_SU) { + su_exit(); + } + /* * tsk->flags are checked in the futex code to protect against * an exiting task cleaning up the robust pi futexes. diff --git a/kernel/fork.c b/kernel/fork.c index a32a6aff9f85..b1e3d07b9667 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -326,6 +326,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) if (err) goto free_ti; + tsk->flags &= ~PF_SU; + tsk->stack = ti; setup_thread_stack(tsk, orig); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index cb4caedf5238..bcc78735ca41 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -114,6 +114,38 @@ do { \ local_irq_restore(dflags); \ } while (0) +static atomic_t __su_instances; + +int su_instances(void) +{ + return atomic_read(&__su_instances); +} + +bool su_running(void) +{ + return su_instances() > 0; +} + +bool su_visible(void) +{ + kuid_t uid = current_uid(); + if (su_running()) + return true; + if (uid_eq(uid, GLOBAL_ROOT_UID) || uid_eq(uid, GLOBAL_SYSTEM_UID)) + return true; + return false; +} + +void su_exec(void) +{ + atomic_inc(&__su_instances); +} + +void su_exit(void) +{ + atomic_dec(&__su_instances); +} + const char *task_event_names[] = {"PUT_PREV_TASK", "PICK_NEXT_TASK", "TASK_WAKE", "TASK_MIGRATE", "TASK_UPDATE", "IRQ_UPDATE"}; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ef82495b8682..3163e6fef132 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1655,6 +1655,28 @@ static struct ctl_table vm_table[] = { .mode = 0644, .proc_handler = proc_doulongvec_minmax, }, +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS + { + .procname = "mmap_rnd_bits", + .data = &mmap_rnd_bits, + .maxlen = sizeof(mmap_rnd_bits), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = (void *)&mmap_rnd_bits_min, + .extra2 = (void *)&mmap_rnd_bits_max, + }, +#endif +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS + { + .procname = "mmap_rnd_compat_bits", + .data = &mmap_rnd_compat_bits, + .maxlen = sizeof(mmap_rnd_compat_bits), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = (void *)&mmap_rnd_compat_bits_min, + .extra2 = (void *)&mmap_rnd_compat_bits_max, + }, +#endif { } }; diff --git a/mm/mmap.c b/mm/mmap.c index aaa20f6b9b54..2a6b12fbcb1d 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -52,6 +52,18 @@ #define arch_rebalance_pgtables(addr, len) (addr) #endif +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS +const int mmap_rnd_bits_min = CONFIG_ARCH_MMAP_RND_BITS_MIN; +const int mmap_rnd_bits_max = CONFIG_ARCH_MMAP_RND_BITS_MAX; +int mmap_rnd_bits __read_mostly = CONFIG_ARCH_MMAP_RND_BITS; +#endif +#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS +const int mmap_rnd_compat_bits_min = CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN; +const int mmap_rnd_compat_bits_max = CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX; +int mmap_rnd_compat_bits __read_mostly = CONFIG_ARCH_MMAP_RND_COMPAT_BITS; +#endif + + static void unmap_region(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, unsigned long start, unsigned long end); diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index c38e7a2b5a8e..3f78978b2173 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -135,7 +135,7 @@ void sock_diag_unregister(const struct sock_diag_handler *hnld) } EXPORT_SYMBOL_GPL(sock_diag_unregister); -static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) { int err; struct sock_diag_req *req = nlmsg_data(nlh); @@ -155,8 +155,12 @@ static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) hndl = sock_diag_handlers[req->sdiag_family]; if (hndl == NULL) err = -ENOENT; - else + else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY) err = hndl->dump(skb, nlh); + else if (nlh->nlmsg_type == SOCK_DESTROY_BACKPORT && hndl->destroy) + err = hndl->destroy(skb, nlh); + else + err = -EOPNOTSUPP; mutex_unlock(&sock_diag_table_mutex); return err; @@ -182,7 +186,8 @@ static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return ret; case SOCK_DIAG_BY_FAMILY: - return __sock_diag_rcv_msg(skb, nlh); + case SOCK_DESTROY_BACKPORT: + return __sock_diag_cmd(skb, nlh); default: return -EINVAL; } @@ -197,6 +202,18 @@ static void sock_diag_rcv(struct sk_buff *skb) mutex_unlock(&sock_diag_mutex); } +int sock_diag_destroy(struct sock *sk, int err) +{ + if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) + return -EPERM; + + if (!sk->sk_prot->diag_destroy) + return -EOPNOTSUPP; + + return sk->sk_prot->diag_destroy(sk, err); +} +EXPORT_SYMBOL_GPL(sock_diag_destroy); + static int __net_init diag_net_init(struct net *net) { struct netlink_kernel_cfg cfg = { diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 9ad2416f8e33..98c604626504 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -480,6 +480,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, newsk->sk_backlog_rcv = dccp_v4_do_rcv; newnp->pktoptions = NULL; newnp->opt = NULL; + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; @@ -555,6 +558,10 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, /* Clone RX bits */ newnp->rxopt.all = np->rxopt.all; + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; + /* Clone pktoptions received with SYN */ newnp->pktoptions = NULL; if (ireq6->pktopts != NULL) { diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 8603ca827104..0ee167c3ee3b 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -433,6 +433,19 @@ config INET_UDP_DIAG Support for UDP socket monitoring interface used by the ss tool. If unsure, say Y. +config INET_DIAG_DESTROY + bool "INET: allow privileged process to administratively close sockets" + depends on INET_DIAG + default n + ---help--- + Provides a SOCK_DESTROY_BACKPORT operation that allows privileged processes + (e.g., a connection manager or a network administration tool such as + ss) to close sockets opened by other processes. Closing a socket in + this way interrupts any blocking read/write/connect operations on + the socket and causes future socket calls to behave as if the socket + had been disconnected. + If unsure, say N. + menuconfig TCP_CONG_ADVANCED bool "TCP: advanced congestion control" ---help--- diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 6dfec2f18214..b7a3d6bd5671 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -690,6 +690,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk, inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port; newsk->sk_write_space = sk_stream_write_space; + inet_sk(newsk)->mc_list = NULL; + newsk->sk_mark = inet_rsk(req)->ir_mark; newicsk->icsk_retransmits = 0; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 14a1ed611b05..a897652c621d 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -304,15 +304,12 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, nlmsg_flags, unlh); } -int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb, - const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req) +struct sock *inet_diag_find_one_icsk(struct net *net, + struct inet_hashinfo *hashinfo, + struct inet_diag_req_v2 *req) { - int err; struct sock *sk; - struct sk_buff *rep; - struct net *net = sock_net(in_skb->sk); - err = -EINVAL; if (req->sdiag_family == AF_INET) { sk = inet_lookup(net, hashinfo, req->id.idiag_dst[0], req->id.idiag_dport, req->id.idiag_src[0], @@ -320,25 +317,53 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s } #if IS_ENABLED(CONFIG_IPV6) else if (req->sdiag_family == AF_INET6) { - sk = inet6_lookup(net, hashinfo, - (struct in6_addr *)req->id.idiag_dst, - req->id.idiag_dport, - (struct in6_addr *)req->id.idiag_src, - req->id.idiag_sport, - req->id.idiag_if); + if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) && + ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src)) + sk = inet_lookup(net, hashinfo, req->id.idiag_dst[3], + req->id.idiag_dport, req->id.idiag_src[3], + req->id.idiag_sport, req->id.idiag_if); + else + sk = inet6_lookup(net, hashinfo, + (struct in6_addr *)req->id.idiag_dst, + req->id.idiag_dport, + (struct in6_addr *)req->id.idiag_src, + req->id.idiag_sport, + req->id.idiag_if); } #endif else { - goto out_nosk; + return ERR_PTR(-EINVAL); } - err = -ENOENT; - if (sk == NULL) - goto out_nosk; + if (!sk) + return ERR_PTR(-ENOENT); - err = sock_diag_check_cookie(sk, req->id.idiag_cookie); - if (err) - goto out; + if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) { + /* NOTE: forward-ports should use sock_gen_put(sk) instead. */ + if (sk->sk_state == TCP_TIME_WAIT) + inet_twsk_put((struct inet_timewait_sock *)sk); + else + sock_put(sk); + return ERR_PTR(-ENOENT); + } + + return sk; +} +EXPORT_SYMBOL_GPL(inet_diag_find_one_icsk); + +int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, + struct sk_buff *in_skb, + const struct nlmsghdr *nlh, + struct inet_diag_req_v2 *req) +{ + struct net *net = sock_net(in_skb->sk); + struct sk_buff *rep; + struct sock *sk; + int err; + + sk = inet_diag_find_one_icsk(net, hashinfo, req); + if (IS_ERR(sk)) + return PTR_ERR(sk); rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL); if (!rep) { @@ -367,12 +392,11 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s else sock_put(sk); } -out_nosk: return err; } EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk); -static int inet_diag_get_exact(struct sk_buff *in_skb, +static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb, const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req) { @@ -382,8 +406,12 @@ static int inet_diag_get_exact(struct sk_buff *in_skb, handler = inet_diag_lock_handler(req->sdiag_protocol); if (IS_ERR(handler)) err = PTR_ERR(handler); - else + else if (cmd == SOCK_DIAG_BY_FAMILY) err = handler->dump_one(in_skb, nlh, req); + else if (cmd == SOCK_DESTROY_BACKPORT && handler->destroy) + err = handler->destroy(in_skb, req); + else + err = -EOPNOTSUPP; inet_diag_unlock_handler(handler); return err; @@ -1083,7 +1111,7 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb, req.idiag_states = rc->idiag_states; req.id = rc->id; - return inet_diag_get_exact(in_skb, nlh, &req); + return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, &req); } static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) @@ -1117,7 +1145,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) return inet_diag_get_exact_compat(skb, nlh); } -static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) +static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h) { int hdrlen = sizeof(struct inet_diag_req_v2); struct net *net = sock_net(skb->sk); @@ -1125,7 +1153,8 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) if (nlmsg_len(h) < hdrlen) return -EINVAL; - if (h->nlmsg_flags & NLM_F_DUMP) { + if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY && + h->nlmsg_flags & NLM_F_DUMP) { if (nlmsg_attrlen(h, hdrlen)) { struct nlattr *attr; attr = nlmsg_find_attr(h, hdrlen, @@ -1143,17 +1172,19 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } } - return inet_diag_get_exact(skb, h, nlmsg_data(h)); + return inet_diag_cmd_exact(h->nlmsg_type, skb, h, nlmsg_data(h)); } static const struct sock_diag_handler inet_diag_handler = { .family = AF_INET, - .dump = inet_diag_handler_dump, + .dump = inet_diag_handler_cmd, + .destroy = inet_diag_handler_cmd, }; static const struct sock_diag_handler inet6_diag_handler = { .family = AF_INET6, - .dump = inet_diag_handler_dump, + .dump = inet_diag_handler_cmd, + .destroy = inet_diag_handler_cmd, }; int inet_diag_register(const struct inet_diag_handler *h) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 043aded548cd..0e09d39e9478 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3399,6 +3399,43 @@ void tcp_done(struct sock *sk) } EXPORT_SYMBOL_GPL(tcp_done); +int tcp_abort(struct sock *sk, int err) +{ + if (sk->sk_state == TCP_TIME_WAIT) { + inet_twsk_put((struct inet_timewait_sock *)sk); + return -EOPNOTSUPP; + } + + /* Don't race with userspace socket closes such as tcp_close. */ + lock_sock(sk); + + if (sk->sk_state == TCP_LISTEN) { + tcp_set_state(sk, TCP_CLOSE); + inet_csk_listen_stop(sk); + } + + /* Don't race with BH socket closes such as inet_csk_listen_stop. */ + local_bh_disable(); + bh_lock_sock(sk); + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_err = err; + /* This barrier is coupled with smp_rmb() in tcp_poll() */ + smp_wmb(); + sk->sk_error_report(sk); + if (tcp_need_reset(sk->sk_state)) + tcp_send_active_reset(sk, GFP_ATOMIC); + tcp_done(sk); + } + + bh_unlock_sock(sk); + local_bh_enable(); + release_sock(sk); + sock_put(sk); + return 0; +} +EXPORT_SYMBOL_GPL(tcp_abort); + extern struct tcp_congestion_ops tcp_reno; static __initdata unsigned long thash_entries; diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index ed3f2ad42e0f..a56461c21b97 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -11,6 +11,8 @@ #include +#include +#include #include #include @@ -46,11 +48,28 @@ static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req); } +#ifdef CONFIG_INET_DIAG_DESTROY +static int tcp_diag_destroy(struct sk_buff *in_skb, + struct inet_diag_req_v2 *req) +{ + struct net *net = sock_net(in_skb->sk); + struct sock *sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req); + + if (IS_ERR(sk)) + return PTR_ERR(sk); + + return sock_diag_destroy(sk, ECONNABORTED); +} +#endif + static const struct inet_diag_handler tcp_diag_handler = { .dump = tcp_diag_dump, .dump_one = tcp_diag_dump_one, .idiag_get_info = tcp_diag_get_info, .idiag_type = IPPROTO_TCP, +#ifdef CONFIG_INET_DIAG_DESTROY + .destroy = tcp_diag_destroy, +#endif }; static int __init tcp_diag_init(void) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a3c8410cfd7e..d9eb8e86123c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1801,7 +1801,7 @@ static __sum16 tcp_v4_checksum_init(struct sk_buff *skb) /* The socket must have it's spinlock held when we get - * here. + * here, unless it is a TCP_LISTEN socket. * * We have a potential double-lock case here, so even when * doing backlog processing we use the BH locking scheme. @@ -2049,6 +2049,11 @@ int tcp_v4_rcv(struct sk_buff *skb) skb->dev = NULL; + if (sk->sk_state == TCP_LISTEN) { + ret = tcp_v4_do_rcv(sk, skb); + goto put_and_return; + } + bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { @@ -2072,6 +2077,7 @@ int tcp_v4_rcv(struct sk_buff *skb) } bh_unlock_sock(sk); +put_and_return: sock_put(sk); return ret; @@ -2919,6 +2925,7 @@ struct proto tcp_prot = { .destroy_cgroup = tcp_destroy_cgroup, .proto_cgroup = tcp_proto_cgroup, #endif + .diag_destroy = tcp_abort, }; EXPORT_SYMBOL(tcp_prot); diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 88a2e8827ef7..5e8559fc7bcf 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -127,6 +127,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, sizeof(*ipv6h)); if (proto == IPPROTO_UDP) { unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); + if (unfrag_ip6hlen < 0) + return ERR_PTR(unfrag_ip6hlen); fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); fptr->frag_off = htons(offset); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 99333e0d0f7f..c92fd76d6978 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -573,6 +573,10 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) struct net *net = dev_net(skb_dst(skb)->dev); hlen = ip6_find_1stfragopt(skb, &prevhdr); + if (hlen < 0) { + err = hlen; + goto fail; + } nexthdr = *prevhdr; mtu = ip6_skb_dst_mtu(skb); @@ -1366,6 +1370,11 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, */ alloclen += sizeof(struct frag_hdr); + copy = datalen - transhdrlen - fraggap; + if (copy < 0) { + err = -EINVAL; + goto error; + } if (transhdrlen) { skb = sock_alloc_send_skb(sk, alloclen + hh_len, @@ -1417,13 +1426,9 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, data += fraggap; pskb_trim_unique(skb_prev, maxfraglen); } - copy = datalen - transhdrlen - fraggap; - - if (copy < 0) { - err = -EINVAL; - kfree_skb(skb); - goto error; - } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { + if (copy > 0 && + getfrag(from, data + transhdrlen, offset, + copy, fraggap, skb) < 0) { err = -EFAULT; kfree_skb(skb); goto error; diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index a5d465105b69..d40ef970746b 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -10,13 +10,12 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { u16 offset = sizeof(struct ipv6hdr); - struct ipv6_opt_hdr *exthdr = - (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); unsigned int packet_len = skb->tail - skb->network_header; int found_rhdr = 0; *nexthdr = &ipv6_hdr(skb)->nexthdr; - while (offset + 1 <= packet_len) { + while (offset <= packet_len) { + struct ipv6_opt_hdr *exthdr; switch (**nexthdr) { @@ -37,12 +36,15 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) return offset; } - offset += ipv6_optlen(exthdr); - *nexthdr = &exthdr->nexthdr; + if (offset + sizeof(struct ipv6_opt_hdr) > packet_len) + return -EINVAL; + exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + offset); + offset += ipv6_optlen(exthdr); + *nexthdr = &exthdr->nexthdr; } - return offset; + return -EINVAL; } EXPORT_SYMBOL(ip6_find_1stfragopt); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index cf349129a3b8..f419bbbd23c6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1137,6 +1137,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->af_specific = &tcp_sock_ipv6_mapped_specific; #endif + newnp->ipv6_mc_list = NULL; newnp->ipv6_ac_list = NULL; newnp->ipv6_fl_list = NULL; newnp->pktoptions = NULL; @@ -1204,6 +1205,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, First: no IPv4 options. */ newinet->inet_opt = NULL; + newnp->ipv6_mc_list = NULL; newnp->ipv6_ac_list = NULL; newnp->ipv6_fl_list = NULL; @@ -1306,7 +1308,7 @@ static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) } /* The socket must have it's spinlock held when we get - * here. + * here, unless it is a TCP_LISTEN socket. * * We have a potential double-lock case here, so even when * doing backlog processing we use the BH locking scheme. @@ -1513,6 +1515,11 @@ static int tcp_v6_rcv(struct sk_buff *skb) skb->dev = NULL; + if (sk->sk_state == TCP_LISTEN) { + ret = tcp_v6_do_rcv(sk, skb); + goto put_and_return; + } + bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { @@ -1536,6 +1543,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) } bh_unlock_sock(sk); +put_and_return: sock_put(sk); return ret ? -1 : 0; @@ -1961,6 +1969,7 @@ struct proto tcpv6_prot = { .proto_cgroup = tcp_proto_cgroup, #endif .clear_sk = tcp_v6_clear_sk, + .diag_destroy = tcp_abort, }; static const struct inet6_protocol tcpv6_protocol = { diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 2f65b022627b..54ceb253a84d 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -94,6 +94,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, * bytes to insert fragment header. */ unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); + if (unfrag_ip6hlen < 0) + return ERR_PTR(unfrag_ip6hlen); nexthdr = *prevhdr; *prevhdr = NEXTHDR_FRAGMENT; unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) + diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 2665bf4b8d05..f86f096aa16a 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1183,11 +1183,10 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg) sipx->sipx_network = ipxif->if_netnum; memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node)); - rc = -EFAULT; + rc = 0; if (copy_to_user(arg, &ifr, sizeof(ifr))) - break; + rc = -EFAULT; ipxitf_put(ipxif); - rc = 0; break; } case SIOCAIPXITFCRT: diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 0d0d416dfab6..ab3e92a4834a 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -821,7 +821,10 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb) * another trick required to cope with how the PROCOM state * machine works. -acme */ + skb_orphan(skb); + sock_hold(sk); skb->sk = sk; + skb->destructor = sock_efree; } if (!sock_owned_by_user(sk)) llc_conn_rcv(sk, skb); diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 78be45cda5c1..a2dd827147bb 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -290,7 +290,10 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb, ev->type = LLC_SAP_EV_TYPE_PDU; ev->reason = 0; + skb_orphan(skb); + sock_hold(sk); skb->sk = sk; + skb->destructor = sock_efree; llc_sap_state_process(sap, skb); } diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index b21fbd63da69..0b4022e3fc3e 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -48,6 +48,7 @@ #include #include #include +#include struct idletimer_tg_attr { struct attribute attr; @@ -73,6 +74,7 @@ struct idletimer_tg { bool work_pending; bool send_nl_msg; bool active; + uid_t uid; bool suspend_time_valid; }; @@ -118,7 +120,8 @@ static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer) char iface_msg[NLMSG_MAX_SIZE]; char state_msg[NLMSG_MAX_SIZE]; char timestamp_msg[NLMSG_MAX_SIZE]; - char *envp[] = { iface_msg, state_msg, timestamp_msg, NULL }; + char uid_msg[NLMSG_MAX_SIZE]; + char *envp[] = { iface_msg, state_msg, timestamp_msg, uid_msg, NULL }; int res; struct timespec ts; uint64_t time_ns; @@ -141,6 +144,16 @@ static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer) return; } + if (state) { + res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID=%u", timer->uid); + if (NLMSG_MAX_SIZE <= res) + pr_err("message too long (%d)", res); + } else { + res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID="); + if (NLMSG_MAX_SIZE <= res) + pr_err("message too long (%d)", res); + } + time_ns = timespec_to_ns(&ts); res = snprintf(timestamp_msg, NLMSG_MAX_SIZE, "TIME_NS=%llu", time_ns); if (NLMSG_MAX_SIZE <= res) { @@ -148,7 +161,8 @@ static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer) pr_err("message too long (%d)", res); } - pr_debug("putting nlmsg: <%s> <%s>\n", iface_msg, state_msg); + pr_debug("putting nlmsg: <%s> <%s> <%s> <%s>\n", iface_msg, state_msg, + timestamp_msg, uid_msg); kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp); return; @@ -304,6 +318,7 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) info->timer->delayed_timer_trigger.tv_sec = 0; info->timer->delayed_timer_trigger.tv_nsec = 0; info->timer->work_pending = false; + info->timer->uid = 0; get_monotonic_boottime(&info->timer->last_modified_timer); info->timer->pm_nb.notifier_call = idletimer_resume; @@ -327,7 +342,8 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) return ret; } -static void reset_timer(const struct idletimer_tg_info *info) +static void reset_timer(const struct idletimer_tg_info *info, + struct sk_buff *skb) { unsigned long now = jiffies; struct idletimer_tg *timer = info->timer; @@ -340,6 +356,17 @@ static void reset_timer(const struct idletimer_tg_info *info) if (!timer_prev || time_before(timer->timer.expires, now)) { pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n", timer->timer.expires, now); + + /* Stores the uid resposible for waking up the radio */ + if (skb && (skb->sk)) { + struct sock *sk = skb->sk; + read_lock_bh(&sk->sk_callback_lock); + if ((sk->sk_socket) && (sk->sk_socket->file) && + (sk->sk_socket->file->f_cred)) + timer->uid = sk->sk_socket->file->f_cred->uid; + read_unlock_bh(&sk->sk_callback_lock); + } + /* checks if there is a pending inactive notification*/ if (timer->work_pending) timer->delayed_timer_trigger = timer->last_modified_timer; @@ -378,7 +405,7 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb, } /* TODO: Avoid modifying timers on each packet */ - reset_timer(info); + reset_timer(info, skb); return XT_CONTINUE; } @@ -406,7 +433,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) info->timer = __idletimer_tg_find_by_label(info->label); if (info->timer) { info->timer->refcnt++; - reset_timer(info); + reset_timer(info, NULL); pr_debug("increased refcnt of timer %s to %u\n", info->label, info->timer->refcnt); } else { diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7b151e643b94..d943b361569e 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -512,7 +512,7 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock, * for dumps is performed here. A dump is allowed to continue * if at least half the ring is unused. */ - while (nlk->cb != NULL && netlink_dump_space(nlk)) { + while (nlk->cb_running && netlink_dump_space(nlk)) { err = netlink_dump(sk); if (err < 0) { sk->sk_err = -err; @@ -699,18 +699,6 @@ static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb) #define netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group, siocb) 0 #endif /* CONFIG_NETLINK_MMAP */ -static void netlink_destroy_callback(struct netlink_callback *cb) -{ - kfree_skb(cb->skb); - kfree(cb); -} - -static void netlink_consume_callback(struct netlink_callback *cb) -{ - consume_skb(cb->skb); - kfree(cb); -} - static void netlink_skb_destructor(struct sk_buff *skb) { #ifdef CONFIG_NETLINK_MMAP @@ -762,12 +750,12 @@ static void netlink_sock_destruct(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); - if (nlk->cb) { - if (nlk->cb->done) - nlk->cb->done(nlk->cb); + if (nlk->cb_running) { + if (nlk->cb.done) + nlk->cb.done(&nlk->cb); - module_put(nlk->cb->module); - netlink_destroy_callback(nlk->cb); + module_put(nlk->cb.module); + kfree_skb(nlk->cb.skb); } skb_queue_purge(&sk->sk_receive_queue); @@ -2264,7 +2252,8 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, skb_free_datagram(sk, skb); - if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { + if (nlk->cb_running && + atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { ret = netlink_dump(sk); if (ret) { sk->sk_err = -ret; @@ -2474,17 +2463,17 @@ static int netlink_dump(struct sock *sk) struct netlink_callback *cb; struct sk_buff *skb = NULL; struct nlmsghdr *nlh; + struct module *module; int len, err = -ENOBUFS; int alloc_size; mutex_lock(nlk->cb_mutex); - - cb = nlk->cb; - if (cb == NULL) { + if (!nlk->cb_running) { err = -EINVAL; goto errout_skb; } + cb = &nlk->cb; alloc_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); if (!netlink_rx_is_mmaped(sk) && @@ -2522,11 +2511,13 @@ static int netlink_dump(struct sock *sk) if (cb->done) cb->done(cb); - nlk->cb = NULL; - mutex_unlock(nlk->cb_mutex); - module_put(cb->module); - netlink_consume_callback(cb); + nlk->cb_running = false; + module = cb->module; + skb = cb->skb; + mutex_unlock(nlk->cb_mutex); + module_put(module); + consume_skb(skb); return 0; errout_skb: @@ -2544,59 +2535,51 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, struct netlink_sock *nlk; int ret; - cb = kzalloc(sizeof(*cb), GFP_KERNEL); - if (cb == NULL) - return -ENOBUFS; - /* Memory mapped dump requests need to be copied to avoid looping * on the pending state in netlink_mmap_sendmsg() while the CB hold * a reference to the skb. */ if (netlink_skb_is_mmaped(skb)) { skb = skb_copy(skb, GFP_KERNEL); - if (skb == NULL) { - kfree(cb); + if (skb == NULL) return -ENOBUFS; - } } else atomic_inc(&skb->users); - cb->dump = control->dump; - cb->done = control->done; - cb->nlh = nlh; - cb->data = control->data; - cb->module = control->module; - cb->min_dump_alloc = control->min_dump_alloc; - cb->skb = skb; - sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid); if (sk == NULL) { - netlink_destroy_callback(cb); - return -ECONNREFUSED; + ret = -ECONNREFUSED; + goto error_free; } - nlk = nlk_sk(sk); + nlk = nlk_sk(sk); mutex_lock(nlk->cb_mutex); /* A dump is in progress... */ - if (nlk->cb) { - mutex_unlock(nlk->cb_mutex); - netlink_destroy_callback(cb); + if (nlk->cb_running) { ret = -EBUSY; - goto out; + goto error_unlock; } /* add reference of module which cb->dump belongs to */ - if (!try_module_get(cb->module)) { - mutex_unlock(nlk->cb_mutex); - netlink_destroy_callback(cb); + if (!try_module_get(control->module)) { ret = -EPROTONOSUPPORT; - goto out; + goto error_unlock; } - nlk->cb = cb; + cb = &nlk->cb; + memset(cb, 0, sizeof(*cb)); + cb->dump = control->dump; + cb->done = control->done; + cb->nlh = nlh; + cb->data = control->data; + cb->module = control->module; + cb->min_dump_alloc = control->min_dump_alloc; + cb->skb = skb; + + nlk->cb_running = true; + mutex_unlock(nlk->cb_mutex); ret = netlink_dump(sk); -out: sock_put(sk); if (ret) @@ -2606,6 +2589,13 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, * signal not to send ACK even if it was requested. */ return -EINTR; + +error_unlock: + sock_put(sk); + mutex_unlock(nlk->cb_mutex); +error_free: + kfree_skb(skb); + return ret; } EXPORT_SYMBOL(__netlink_dump_start); @@ -2825,14 +2815,14 @@ static int netlink_seq_show(struct seq_file *seq, void *v) struct sock *s = v; struct netlink_sock *nlk = nlk_sk(s); - seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %pK %-8d %-8d %-8lu\n", + seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %d %-8d %-8d %-8lu\n", s, s->sk_protocol, nlk->portid, nlk->groups ? (u32)nlk->groups[0] : 0, sk_rmem_alloc_get(s), sk_wmem_alloc_get(s), - nlk->cb, + nlk->cb_running, atomic_read(&s->sk_refcnt), atomic_read(&s->sk_drops), sock_i_ino(s) diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index ed8522265f4e..74c16f079869 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -32,7 +32,8 @@ struct netlink_sock { unsigned long *groups; unsigned long state; wait_queue_head_t wait; - struct netlink_callback *cb; + bool cb_running; + struct netlink_callback cb; struct mutex *cb_mutex; struct mutex cb_def_mutex; void (*netlink_rcv)(struct sk_buff *skb); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 7c2fea69c832..99bd351e41af 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -662,6 +662,16 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, newnp = inet6_sk(newsk); memcpy(newnp, np, sizeof(struct ipv6_pinfo)); + newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; + + rcu_read_lock(); + opt = rcu_dereference(np->opt); + if (opt) + opt = ipv6_dup_options(newsk, opt); + RCU_INIT_POINTER(newnp->opt, opt); + rcu_read_unlock(); rcu_read_lock(); opt = rcu_dereference(np->opt); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 91a6a2903e8d..16de03ebb407 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -400,6 +400,9 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) return -EINVAL; + if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) + return -EINVAL; + return 0; } diff --git a/security/inode.c b/security/inode.c index 43ce6e19015f..94466a5eed50 100644 --- a/security/inode.c +++ b/security/inode.c @@ -105,7 +105,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode, dir = parent->d_inode; mutex_lock(&dir->i_mutex); - dentry = lookup_one_len(name, parent, strlen(name)); + dentry = lookup_one_len2(name, mount, parent, strlen(name)); if (IS_ERR(dentry)) goto out; diff --git a/security/selinux/avc.c b/security/selinux/avc.c index f3dbbc0f15dd..386aafb2e69b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -49,7 +49,7 @@ struct avc_entry { u32 tsid; u16 tclass; struct av_decision avd; - struct avc_operation_node *ops_node; + struct avc_xperms_node *xp_node; }; struct avc_node { @@ -58,6 +58,16 @@ struct avc_node { struct rcu_head rhead; }; +struct avc_xperms_decision_node { + struct extended_perms_decision xpd; + struct list_head xpd_list; /* list of extended_perms_decision */ +}; + +struct avc_xperms_node { + struct extended_perms xp; + struct list_head xpd_head; /* list head of extended_perms_decision */ +}; + struct avc_cache { struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ @@ -66,16 +76,6 @@ struct avc_cache { u32 latest_notif; /* latest revocation notification */ }; -struct avc_operation_decision_node { - struct operation_decision od; - struct list_head od_list; -}; - -struct avc_operation_node { - struct operation ops; - struct list_head od_head; /* list of operation_decision_node */ -}; - struct avc_callback_node { int (*callback) (u32 event); u32 events; @@ -92,9 +92,9 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; static struct avc_cache avc_cache; static struct avc_callback_node *avc_callbacks; static struct kmem_cache *avc_node_cachep; -static struct kmem_cache *avc_operation_decision_node_cachep; -static struct kmem_cache *avc_operation_node_cachep; -static struct kmem_cache *avc_operation_perm_cachep; +static struct kmem_cache *avc_xperms_data_cachep; +static struct kmem_cache *avc_xperms_decision_cachep; +static struct kmem_cache *avc_xperms_cachep; static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) { @@ -185,17 +185,17 @@ void __init avc_init(void) atomic_set(&avc_cache.lru_hint, 0); avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), - 0, SLAB_PANIC, NULL); - avc_operation_node_cachep = kmem_cache_create("avc_operation_node", - sizeof(struct avc_operation_node), - 0, SLAB_PANIC, NULL); - avc_operation_decision_node_cachep = kmem_cache_create( - "avc_operation_decision_node", - sizeof(struct avc_operation_decision_node), - 0, SLAB_PANIC, NULL); - avc_operation_perm_cachep = kmem_cache_create("avc_operation_perm", - sizeof(struct operation_perm), - 0, SLAB_PANIC, NULL); + 0, SLAB_PANIC, NULL); + avc_xperms_cachep = kmem_cache_create("avc_xperms_node", + sizeof(struct avc_xperms_node), + 0, SLAB_PANIC, NULL); + avc_xperms_decision_cachep = kmem_cache_create( + "avc_xperms_decision_node", + sizeof(struct avc_xperms_decision_node), + 0, SLAB_PANIC, NULL); + avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data", + sizeof(struct extended_perms_data), + 0, SLAB_PANIC, NULL); audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } @@ -231,222 +231,214 @@ int avc_get_hash_stats(char *page) } /* - * using a linked list for operation_decision lookup because the list is + * using a linked list for extended_perms_decision lookup because the list is * always small. i.e. less than 5, typically 1 */ -static struct operation_decision *avc_operation_lookup(u8 type, - struct avc_operation_node *ops_node) +static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver, + struct avc_xperms_node *xp_node) { - struct avc_operation_decision_node *od_node; - struct operation_decision *od = NULL; + struct avc_xperms_decision_node *xpd_node; - list_for_each_entry(od_node, &ops_node->od_head, od_list) { - if (od_node->od.type != type) - continue; - od = &od_node->od; - break; + list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) { + if (xpd_node->xpd.driver == driver) + return &xpd_node->xpd; } - return od; + return NULL; } -static inline unsigned int avc_operation_has_perm(struct operation_decision *od, - u16 cmd, u8 specified) +static inline unsigned int +avc_xperms_has_perm(struct extended_perms_decision *xpd, + u8 perm, u8 which) { unsigned int rc = 0; - u8 num = cmd & 0xff; - - if ((specified == OPERATION_ALLOWED) && - (od->specified & OPERATION_ALLOWED)) - rc = security_operation_test(od->allowed->perms, num); - else if ((specified == OPERATION_AUDITALLOW) && - (od->specified & OPERATION_AUDITALLOW)) - rc = security_operation_test(od->auditallow->perms, num); - else if ((specified == OPERATION_DONTAUDIT) && - (od->specified & OPERATION_DONTAUDIT)) - rc = security_operation_test(od->dontaudit->perms, num); + + if ((which == XPERMS_ALLOWED) && + (xpd->used & XPERMS_ALLOWED)) + rc = security_xperm_test(xpd->allowed->p, perm); + else if ((which == XPERMS_AUDITALLOW) && + (xpd->used & XPERMS_AUDITALLOW)) + rc = security_xperm_test(xpd->auditallow->p, perm); + else if ((which == XPERMS_DONTAUDIT) && + (xpd->used & XPERMS_DONTAUDIT)) + rc = security_xperm_test(xpd->dontaudit->p, perm); return rc; } -static void avc_operation_allow_perm(struct avc_operation_node *node, u16 cmd) +static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node, + u8 driver, u8 perm) { - struct operation_decision *od; - u8 type; - u8 num; - - type = cmd >> 8; - num = cmd & 0xff; - security_operation_set(node->ops.type, type); - od = avc_operation_lookup(type, node); - if (od && od->allowed) - security_operation_set(od->allowed->perms, num); + struct extended_perms_decision *xpd; + security_xperm_set(xp_node->xp.drivers.p, driver); + xpd = avc_xperms_decision_lookup(driver, xp_node); + if (xpd && xpd->allowed) + security_xperm_set(xpd->allowed->p, perm); } -static void avc_operation_decision_free( - struct avc_operation_decision_node *od_node) +static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node) { - struct operation_decision *od; - - od = &od_node->od; - if (od->allowed) - kmem_cache_free(avc_operation_perm_cachep, od->allowed); - if (od->auditallow) - kmem_cache_free(avc_operation_perm_cachep, od->auditallow); - if (od->dontaudit) - kmem_cache_free(avc_operation_perm_cachep, od->dontaudit); - kmem_cache_free(avc_operation_decision_node_cachep, od_node); + struct extended_perms_decision *xpd; + + xpd = &xpd_node->xpd; + if (xpd->allowed) + kmem_cache_free(avc_xperms_data_cachep, xpd->allowed); + if (xpd->auditallow) + kmem_cache_free(avc_xperms_data_cachep, xpd->auditallow); + if (xpd->dontaudit) + kmem_cache_free(avc_xperms_data_cachep, xpd->dontaudit); + kmem_cache_free(avc_xperms_decision_cachep, xpd_node); } -static void avc_operation_free(struct avc_operation_node *ops_node) +static void avc_xperms_free(struct avc_xperms_node *xp_node) { - struct avc_operation_decision_node *od_node, *tmp; + struct avc_xperms_decision_node *xpd_node, *tmp; - if (!ops_node) + if (!xp_node) return; - list_for_each_entry_safe(od_node, tmp, &ops_node->od_head, od_list) { - list_del(&od_node->od_list); - avc_operation_decision_free(od_node); + list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) { + list_del(&xpd_node->xpd_list); + avc_xperms_decision_free(xpd_node); } - kmem_cache_free(avc_operation_node_cachep, ops_node); + kmem_cache_free(avc_xperms_cachep, xp_node); } -static void avc_copy_operation_decision(struct operation_decision *dest, - struct operation_decision *src) +static void avc_copy_xperms_decision(struct extended_perms_decision *dest, + struct extended_perms_decision *src) { - dest->type = src->type; - dest->specified = src->specified; - if (dest->specified & OPERATION_ALLOWED) - memcpy(dest->allowed->perms, src->allowed->perms, - sizeof(src->allowed->perms)); - if (dest->specified & OPERATION_AUDITALLOW) - memcpy(dest->auditallow->perms, src->auditallow->perms, - sizeof(src->auditallow->perms)); - if (dest->specified & OPERATION_DONTAUDIT) - memcpy(dest->dontaudit->perms, src->dontaudit->perms, - sizeof(src->dontaudit->perms)); + dest->driver = src->driver; + dest->used = src->used; + if (dest->used & XPERMS_ALLOWED) + memcpy(dest->allowed->p, src->allowed->p, + sizeof(src->allowed->p)); + if (dest->used & XPERMS_AUDITALLOW) + memcpy(dest->auditallow->p, src->auditallow->p, + sizeof(src->auditallow->p)); + if (dest->used & XPERMS_DONTAUDIT) + memcpy(dest->dontaudit->p, src->dontaudit->p, + sizeof(src->dontaudit->p)); } /* - * similar to avc_copy_operation_decision, but only copy decision - * information relevant to this command + * similar to avc_copy_xperms_decision, but only copy decision + * information relevant to this perm */ -static inline void avc_quick_copy_operation_decision(u16 cmd, - struct operation_decision *dest, - struct operation_decision *src) +static inline void avc_quick_copy_xperms_decision(u8 perm, + struct extended_perms_decision *dest, + struct extended_perms_decision *src) { /* * compute index of the u32 of the 256 bits (8 u32s) that contain this * command permission */ - u8 i = (0xff & cmd) >> 5; - - dest->specified = src->specified; - if (dest->specified & OPERATION_ALLOWED) - dest->allowed->perms[i] = src->allowed->perms[i]; - if (dest->specified & OPERATION_AUDITALLOW) - dest->auditallow->perms[i] = src->auditallow->perms[i]; - if (dest->specified & OPERATION_DONTAUDIT) - dest->dontaudit->perms[i] = src->dontaudit->perms[i]; + u8 i = perm >> 5; + + dest->used = src->used; + if (dest->used & XPERMS_ALLOWED) + dest->allowed->p[i] = src->allowed->p[i]; + if (dest->used & XPERMS_AUDITALLOW) + dest->auditallow->p[i] = src->auditallow->p[i]; + if (dest->used & XPERMS_DONTAUDIT) + dest->dontaudit->p[i] = src->dontaudit->p[i]; } -static struct avc_operation_decision_node - *avc_operation_decision_alloc(u8 specified) +static struct avc_xperms_decision_node + *avc_xperms_decision_alloc(u8 which) { - struct avc_operation_decision_node *node; - struct operation_decision *od; + struct avc_xperms_decision_node *xpd_node; + struct extended_perms_decision *xpd; - node = kmem_cache_zalloc(avc_operation_decision_node_cachep, + xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); - if (!node) + if (!xpd_node) return NULL; - od = &node->od; - if (specified & OPERATION_ALLOWED) { - od->allowed = kmem_cache_zalloc(avc_operation_perm_cachep, + xpd = &xpd_node->xpd; + if (which & XPERMS_ALLOWED) { + xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); - if (!od->allowed) + if (!xpd->allowed) goto error; } - if (specified & OPERATION_AUDITALLOW) { - od->auditallow = kmem_cache_zalloc(avc_operation_perm_cachep, + if (which & XPERMS_AUDITALLOW) { + xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); - if (!od->auditallow) + if (!xpd->auditallow) goto error; } - if (specified & OPERATION_DONTAUDIT) { - od->dontaudit = kmem_cache_zalloc(avc_operation_perm_cachep, + if (which & XPERMS_DONTAUDIT) { + xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, GFP_ATOMIC | __GFP_NOMEMALLOC); - if (!od->dontaudit) + if (!xpd->dontaudit) goto error; } - return node; + return xpd_node; error: - avc_operation_decision_free(node); + avc_xperms_decision_free(xpd_node); return NULL; } -static int avc_add_operation(struct avc_node *node, - struct operation_decision *od) +static int avc_add_xperms_decision(struct avc_node *node, + struct extended_perms_decision *src) { - struct avc_operation_decision_node *dest_od; + struct avc_xperms_decision_node *dest_xpd; - node->ae.ops_node->ops.len++; - dest_od = avc_operation_decision_alloc(od->specified); - if (!dest_od) + node->ae.xp_node->xp.len++; + dest_xpd = avc_xperms_decision_alloc(src->used); + if (!dest_xpd) return -ENOMEM; - avc_copy_operation_decision(&dest_od->od, od); - list_add(&dest_od->od_list, &node->ae.ops_node->od_head); + avc_copy_xperms_decision(&dest_xpd->xpd, src); + list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head); return 0; } -static struct avc_operation_node *avc_operation_alloc(void) +static struct avc_xperms_node *avc_xperms_alloc(void) { - struct avc_operation_node *ops; + struct avc_xperms_node *xp_node; - ops = kmem_cache_zalloc(avc_operation_node_cachep, + xp_node = kmem_cache_zalloc(avc_xperms_cachep, GFP_ATOMIC|__GFP_NOMEMALLOC); - if (!ops) - return ops; - INIT_LIST_HEAD(&ops->od_head); - return ops; + if (!xp_node) + return xp_node; + INIT_LIST_HEAD(&xp_node->xpd_head); + return xp_node; } -static int avc_operation_populate(struct avc_node *node, - struct avc_operation_node *src) +static int avc_xperms_populate(struct avc_node *node, + struct avc_xperms_node *src) { - struct avc_operation_node *dest; - struct avc_operation_decision_node *dest_od; - struct avc_operation_decision_node *src_od; + struct avc_xperms_node *dest; + struct avc_xperms_decision_node *dest_xpd; + struct avc_xperms_decision_node *src_xpd; - if (src->ops.len == 0) + if (src->xp.len == 0) return 0; - dest = avc_operation_alloc(); + dest = avc_xperms_alloc(); if (!dest) return -ENOMEM; - memcpy(dest->ops.type, &src->ops.type, sizeof(dest->ops.type)); - dest->ops.len = src->ops.len; + memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p)); + dest->xp.len = src->xp.len; - /* for each source od allocate a destination od and copy */ - list_for_each_entry(src_od, &src->od_head, od_list) { - dest_od = avc_operation_decision_alloc(src_od->od.specified); - if (!dest_od) + /* for each source xpd allocate a destination xpd and copy */ + list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) { + dest_xpd = avc_xperms_decision_alloc(src_xpd->xpd.used); + if (!dest_xpd) goto error; - avc_copy_operation_decision(&dest_od->od, &src_od->od); - list_add(&dest_od->od_list, &dest->od_head); + avc_copy_xperms_decision(&dest_xpd->xpd, &src_xpd->xpd); + list_add(&dest_xpd->xpd_list, &dest->xpd_head); } - node->ae.ops_node = dest; + node->ae.xp_node = dest; return 0; error: - avc_operation_free(dest); + avc_xperms_free(dest); return -ENOMEM; } -static inline u32 avc_operation_audit_required(u32 requested, +static inline u32 avc_xperms_audit_required(u32 requested, struct av_decision *avd, - struct operation_decision *od, - u16 cmd, + struct extended_perms_decision *xpd, + u8 perm, int result, u32 *deniedp) { @@ -455,18 +447,16 @@ static inline u32 avc_operation_audit_required(u32 requested, denied = requested & ~avd->allowed; if (unlikely(denied)) { audited = denied & avd->auditdeny; - if (audited && od) { - if (avc_operation_has_perm(od, cmd, - OPERATION_DONTAUDIT)) + if (audited && xpd) { + if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT)) audited &= ~requested; } } else if (result) { audited = denied = requested; } else { audited = requested & avd->auditallow; - if (audited && od) { - if (!avc_operation_has_perm(od, cmd, - OPERATION_AUDITALLOW)) + if (audited && xpd) { + if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW)) audited &= ~requested; } } @@ -475,16 +465,16 @@ static inline u32 avc_operation_audit_required(u32 requested, return audited; } -static inline int avc_operation_audit(u32 ssid, u32 tsid, u16 tclass, +static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd, - struct operation_decision *od, - u16 cmd, int result, + struct extended_perms_decision *xpd, + u8 perm, int result, struct common_audit_data *ad) { u32 audited, denied; - audited = avc_operation_audit_required( - requested, avd, od, cmd, result, &denied); + audited = avc_xperms_audit_required( + requested, avd, xpd, perm, result, &denied); if (likely(!audited)) return 0; return slow_avc_audit(ssid, tsid, tclass, requested, @@ -494,7 +484,7 @@ static inline int avc_operation_audit(u32 ssid, u32 tsid, u16 tclass, static void avc_node_free(struct rcu_head *rhead) { struct avc_node *node = container_of(rhead, struct avc_node, rhead); - avc_operation_free(node->ae.ops_node); + avc_xperms_free(node->ae.xp_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); } @@ -508,7 +498,7 @@ static void avc_node_delete(struct avc_node *node) static void avc_node_kill(struct avc_node *node) { - avc_operation_free(node->ae.ops_node); + avc_xperms_free(node->ae.xp_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); atomic_dec(&avc_cache.active_nodes); @@ -655,7 +645,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) * @tsid: target security identifier * @tclass: target security class * @avd: resulting av decision - * @ops: resulting operation decisions + * @xp_node: resulting extended permissions * * Insert an AVC entry for the SID pair * (@ssid, @tsid) and class @tclass. @@ -669,7 +659,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) */ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, - struct avc_operation_node *ops_node) + struct avc_xperms_node *xp_node) { struct avc_node *pos, *node = NULL; int hvalue; @@ -686,7 +676,7 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, hvalue = avc_hash(ssid, tsid, tclass); avc_node_populate(node, ssid, tsid, tclass, avd); - rc = avc_operation_populate(node, ops_node); + rc = avc_xperms_populate(node, xp_node); if (rc) { kmem_cache_free(avc_node_cachep, node); return NULL; @@ -824,16 +814,16 @@ static inline int avc_sidcmp(u32 x, u32 y) * @perms : Permission mask bits * @ssid,@tsid,@tclass : identifier of an AVC entry * @seqno : sequence number when decision was made - * @od: operation_decision to be added to the node + * @xpd: extended_perms_decision to be added to the node * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. * otherwise, this function updates the AVC entry. The original AVC-entry object * will release later by RCU. */ -static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, - u16 tclass, u32 seqno, - struct operation_decision *od, +static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, + u32 tsid, u16 tclass, u32 seqno, + struct extended_perms_decision *xpd, u32 flags) { int hvalue, rc = 0; @@ -878,8 +868,8 @@ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); - if (orig->ae.ops_node) { - rc = avc_operation_populate(node, orig->ae.ops_node); + if (orig->ae.xp_node) { + rc = avc_xperms_populate(node, orig->ae.xp_node); if (rc) { kmem_cache_free(avc_node_cachep, node); goto out_unlock; @@ -889,8 +879,8 @@ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, switch (event) { case AVC_CALLBACK_GRANT: node->ae.avd.allowed |= perms; - if (node->ae.ops_node && (flags & AVC_OPERATION_CMD)) - avc_operation_allow_perm(node->ae.ops_node, cmd); + if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS)) + avc_xperms_allow_perm(node->ae.xp_node, driver, xperm); break; case AVC_CALLBACK_TRY_REVOKE: case AVC_CALLBACK_REVOKE: @@ -908,8 +898,8 @@ static int avc_update_node(u32 event, u32 perms, u16 cmd, u32 ssid, u32 tsid, case AVC_CALLBACK_AUDITDENY_DISABLE: node->ae.avd.auditdeny &= ~perms; break; - case AVC_CALLBACK_ADD_OPERATION: - avc_add_operation(node, od); + case AVC_CALLBACK_ADD_XPERMS: + avc_add_xperms_decision(node, xpd); break; } avc_node_replace(node, orig); @@ -983,18 +973,18 @@ int avc_ss_reset(u32 seqno) */ static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, - struct avc_operation_node *ops_node) + struct avc_xperms_node *xp_node) { rcu_read_unlock(); - INIT_LIST_HEAD(&ops_node->od_head); - security_compute_av(ssid, tsid, tclass, avd, &ops_node->ops); + INIT_LIST_HEAD(&xp_node->xpd_head); + security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); rcu_read_lock(); - return avc_insert(ssid, tsid, tclass, avd, ops_node); + return avc_insert(ssid, tsid, tclass, avd, xp_node); } static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested, - u16 cmd, unsigned flags, + u8 driver, u8 xperm, unsigned flags, struct av_decision *avd) { if (flags & AVC_STRICT) @@ -1003,88 +993,87 @@ static noinline int avc_denied(u32 ssid, u32 tsid, if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) return -EACCES; - avc_update_node(AVC_CALLBACK_GRANT, requested, cmd, ssid, + avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, tsid, tclass, avd->seqno, NULL, flags); return 0; } /* - * ioctl commands are comprised of four fields, direction, size, type, and - * number. The avc operation logic filters based on two of them: - * - * type: or code, typically unique to each driver - * number: or function - * - * For example, 0x89 is a socket type, and number 0x27 is the get hardware - * address function. + * The avc extended permissions logic adds an additional 256 bits of + * permissions to an avc node when extended permissions for that node are + * specified in the avtab. If the additional 256 permissions is not adequate, + * as-is the case with ioctls, then multiple may be chained together and the + * driver field is used to specify which set contains the permission. */ -int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, - u16 cmd, struct common_audit_data *ad) +int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, + u8 driver, u8 xperm, struct common_audit_data *ad) { struct avc_node *node; struct av_decision avd; u32 denied; - struct operation_decision *od = NULL; - struct operation_decision od_local; - struct operation_perm allowed; - struct operation_perm auditallow; - struct operation_perm dontaudit; - struct avc_operation_node local_ops_node; - struct avc_operation_node *ops_node; - u8 type = cmd >> 8; + struct extended_perms_decision local_xpd; + struct extended_perms_decision *xpd = NULL; + struct extended_perms_data allowed; + struct extended_perms_data auditallow; + struct extended_perms_data dontaudit; + struct avc_xperms_node local_xp_node; + struct avc_xperms_node *xp_node; int rc = 0, rc2; - ops_node = &local_ops_node; + xp_node = &local_xp_node; BUG_ON(!requested); rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) { - node = avc_compute_av(ssid, tsid, tclass, &avd, ops_node); + node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node); } else { memcpy(&avd, &node->ae.avd, sizeof(avd)); - ops_node = node->ae.ops_node; + xp_node = node->ae.xp_node; } - /* if operations are not defined, only consider av_decision */ - if (!ops_node || !ops_node->ops.len) + /* if extended permissions are not defined, only consider av_decision */ + if (!xp_node || !xp_node->xp.len) goto decision; - od_local.allowed = &allowed; - od_local.auditallow = &auditallow; - od_local.dontaudit = &dontaudit; + local_xpd.allowed = &allowed; + local_xpd.auditallow = &auditallow; + local_xpd.dontaudit = &dontaudit; - /* lookup operation decision */ - od = avc_operation_lookup(type, ops_node); - if (unlikely(!od)) { - /* Compute operation decision if type is flagged */ - if (!security_operation_test(ops_node->ops.type, type)) { + xpd = avc_xperms_decision_lookup(driver, xp_node); + if (unlikely(!xpd)) { + /* + * Compute the extended_perms_decision only if the driver + * is flagged + */ + if (!security_xperm_test(xp_node->xp.drivers.p, driver)) { avd.allowed &= ~requested; goto decision; } rcu_read_unlock(); - security_compute_operation(ssid, tsid, tclass, type, &od_local); + security_compute_xperms_decision(ssid, tsid, tclass, driver, + &local_xpd); rcu_read_lock(); - avc_update_node(AVC_CALLBACK_ADD_OPERATION, requested, cmd, - ssid, tsid, tclass, avd.seqno, &od_local, 0); + avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, + ssid, tsid, tclass, avd.seqno, &local_xpd, 0); } else { - avc_quick_copy_operation_decision(cmd, &od_local, od); + avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); } - od = &od_local; + xpd = &local_xpd; - if (!avc_operation_has_perm(od, cmd, OPERATION_ALLOWED)) + if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED)) avd.allowed &= ~requested; decision: denied = requested & ~(avd.allowed); if (unlikely(denied)) - rc = avc_denied(ssid, tsid, tclass, requested, cmd, - AVC_OPERATION_CMD, &avd); + rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, + AVC_EXTENDED_PERMS, &avd); rcu_read_unlock(); - rc2 = avc_operation_audit(ssid, tsid, tclass, requested, - &avd, od, cmd, rc, ad); + rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, + &avd, xpd, xperm, rc, ad); if (rc2) return rc2; return rc; @@ -1116,7 +1105,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, struct av_decision *avd) { struct avc_node *node; - struct avc_operation_node ops_node; + struct avc_xperms_node xp_node; int rc = 0; u32 denied; @@ -1126,13 +1115,13 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) - node = avc_compute_av(ssid, tsid, tclass, avd, &ops_node); + node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node); else memcpy(avd, &node->ae.avd, sizeof(*avd)); denied = requested & ~(avd->allowed); if (unlikely(denied)) - rc = avc_denied(ssid, tsid, tclass, requested, 0, flags, avd); + rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd); rcu_read_unlock(); return rc; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8b349d16fd6d..ca677d573601 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2863,7 +2863,8 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) return dentry_has_perm(cred, dentry, FILE__SETATTR); - if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)) + if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE) + && !(ia_valid & ATTR_FILE)) av |= FILE__OPEN; return dentry_has_perm(cred, dentry, av); @@ -3172,6 +3173,8 @@ int ioctl_has_perm(const struct cred *cred, struct file *file, struct lsm_ioctlop_audit ioctl; u32 ssid = cred_sid(cred); int rc; + u8 driver = cmd >> 8; + u8 xperm = cmd & 0xff; ad.type = LSM_AUDIT_DATA_IOCTL_OP; ad.u.op = &ioctl; @@ -3190,8 +3193,8 @@ int ioctl_has_perm(const struct cred *cred, struct file *file, if (unlikely(IS_PRIVATE(inode))) return 0; - rc = avc_has_operation(ssid, isec->sid, isec->sclass, - requested, cmd, &ad); + rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, + requested, driver, xperm, &ad); out: return rc; } diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 8109ad846e99..6d65f77fd800 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -142,15 +142,12 @@ static inline int avc_audit(u32 ssid, u32 tsid, } #define AVC_STRICT 1 /* Ignore permissive mode. */ -#define AVC_OPERATION_CMD 2 /* ignore command when updating operations */ +#define AVC_EXTENDED_PERMS 2 /* update extended permissions */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, struct av_decision *avd); -int avc_has_operation(u32 ssid, u32 tsid, u16 tclass, u32 requested, - u16 cmd, struct common_audit_data *ad); - int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata, @@ -163,6 +160,9 @@ static inline int avc_has_perm(u32 ssid, u32 tsid, return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0); } +int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, + u8 driver, u8 perm, struct common_audit_data *ad); + u32 avc_policy_seqno(void); #define AVC_CALLBACK_GRANT 1 @@ -173,7 +173,7 @@ u32 avc_policy_seqno(void); #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 #define AVC_CALLBACK_AUDITDENY_ENABLE 64 #define AVC_CALLBACK_AUDITDENY_DISABLE 128 -#define AVC_CALLBACK_ADD_OPERATION 256 +#define AVC_CALLBACK_ADD_XPERMS 256 int avc_add_callback(int (*callback)(u32 event), u32 events); diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index e72d8de93725..eb25aa9fb313 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -34,14 +34,14 @@ #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 #define POLICYDB_VERSION_DEFAULT_TYPE 28 #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 -#define POLICYDB_VERSION_IOCTL_OPERATIONS 30 +#define POLICYDB_VERSION_XPERMS_IOCTL 30 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #else -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_IOCTL_OPERATIONS +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL #endif /* Mask for just the mount related flags */ @@ -104,29 +104,27 @@ struct av_decision { u32 flags; }; -#define security_operation_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) -#define security_operation_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) +#define XPERMS_ALLOWED 1 +#define XPERMS_AUDITALLOW 2 +#define XPERMS_DONTAUDIT 4 -struct operation_perm { - u32 perms[8]; +#define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) +#define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) +struct extended_perms_data { + u32 p[8]; }; -struct operation_decision { - u8 type; - u8 specified; - struct operation_perm *allowed; - struct operation_perm *auditallow; - struct operation_perm *dontaudit; +struct extended_perms_decision { + u8 used; + u8 driver; + struct extended_perms_data *allowed; + struct extended_perms_data *auditallow; + struct extended_perms_data *dontaudit; }; -#define OPERATION_ALLOWED 1 -#define OPERATION_AUDITALLOW 2 -#define OPERATION_DONTAUDIT 4 -#define OPERATION_ALL (OPERATION_ALLOWED | OPERATION_AUDITALLOW |\ - OPERATION_DONTAUDIT) -struct operation { - u16 len; /* length of operation decision chain */ - u32 type[8]; /* 256 types */ +struct extended_perms { + u16 len; /* length associated decision chain */ + struct extended_perms_data drivers; /* flag drivers that are used */ }; /* definitions of av_decision.flags */ @@ -134,10 +132,10 @@ struct operation { void security_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, - struct operation *ops); + struct extended_perms *xperms); -void security_compute_operation(u32 ssid, u32 tsid, u16 tclass, - u8 type, struct operation_decision *od); +void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, + u8 driver, struct extended_perms_decision *xpermd); void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd); diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 855e464e92ef..dd28eb2af2bb 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "flask.h" #include "av_permissions.h" @@ -76,8 +77,10 @@ static struct nlmsg_perm nlmsg_route_perms[] = static struct nlmsg_perm nlmsg_tcpdiag_perms[] = { - { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, - { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { SOCK_DESTROY_BACKPORT, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, }; static struct nlmsg_perm nlmsg_xfrm_perms[] = @@ -98,6 +101,13 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_MIGRATE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; static struct nlmsg_perm nlmsg_audit_perms[] = diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index dd7466cb2021..640c16b9d3fb 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -24,7 +24,7 @@ #include "policydb.h" static struct kmem_cache *avtab_node_cachep; -static struct kmem_cache *avtab_operation_cachep; +static struct kmem_cache *avtab_xperms_cachep; static inline int avtab_hash(struct avtab_key *keyp, u16 mask) { @@ -38,20 +38,20 @@ avtab_insert_node(struct avtab *h, int hvalue, struct avtab_key *key, struct avtab_datum *datum) { struct avtab_node *newnode; - struct avtab_operation *ops; + struct avtab_extended_perms *xperms; newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); if (newnode == NULL) return NULL; newnode->key = *key; - if (key->specified & AVTAB_OP) { - ops = kmem_cache_zalloc(avtab_operation_cachep, GFP_KERNEL); - if (ops == NULL) { + if (key->specified & AVTAB_XPERMS) { + xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL); + if (xperms == NULL) { kmem_cache_free(avtab_node_cachep, newnode); return NULL; } - *ops = *(datum->u.ops); - newnode->datum.u.ops = ops; + *xperms = *(datum->u.xperms); + newnode->datum.u.xperms = xperms; } else { newnode->datum.u.data = datum->u.data; } @@ -85,7 +85,8 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && (specified & cur->key.specified)) { - if (specified & AVTAB_OPNUM) + /* extended perms may not be unique */ + if (specified & AVTAB_XPERMS) break; return -EEXIST; } @@ -249,9 +250,9 @@ void avtab_destroy(struct avtab *h) while (cur) { temp = cur; cur = cur->next; - if (temp->key.specified & AVTAB_OP) - kmem_cache_free(avtab_operation_cachep, - temp->datum.u.ops); + if (temp->key.specified & AVTAB_XPERMS) + kmem_cache_free(avtab_xperms_cachep, + temp->datum.u.xperms); kmem_cache_free(avtab_node_cachep, temp); } h->htable[i] = NULL; @@ -334,6 +335,32 @@ void avtab_hash_eval(struct avtab *h, char *tag) chain2_len_sum); } +/* + * extended permissions compatibility. Make ToT Android kernels compatible + * with Android M releases + */ +#define AVTAB_OPTYPE_ALLOWED 0x1000 +#define AVTAB_OPTYPE_AUDITALLOW 0x2000 +#define AVTAB_OPTYPE_DONTAUDIT 0x4000 +#define AVTAB_OPTYPE (AVTAB_OPTYPE_ALLOWED | \ + AVTAB_OPTYPE_AUDITALLOW | \ + AVTAB_OPTYPE_DONTAUDIT) +#define AVTAB_XPERMS_OPTYPE 4 + +#define avtab_xperms_to_optype(x) (x << AVTAB_XPERMS_OPTYPE) +#define avtab_optype_to_xperms(x) (x >> AVTAB_XPERMS_OPTYPE) + +static unsigned int avtab_android_m_compat; + +static void avtab_android_m_compat_set(void) +{ + if (!avtab_android_m_compat) { + pr_info("SELinux: Android master kernel running Android" + " M policy in compatibility mode.\n"); + avtab_android_m_compat = 1; + } +} + static uint16_t spec_order[] = { AVTAB_ALLOWED, AVTAB_AUDITDENY, @@ -341,12 +368,9 @@ static uint16_t spec_order[] = { AVTAB_TRANSITION, AVTAB_CHANGE, AVTAB_MEMBER, - AVTAB_OPNUM_ALLOWED, - AVTAB_OPNUM_AUDITALLOW, - AVTAB_OPNUM_DONTAUDIT, - AVTAB_OPTYPE_ALLOWED, - AVTAB_OPTYPE_AUDITALLOW, - AVTAB_OPTYPE_DONTAUDIT + AVTAB_XPERMS_ALLOWED, + AVTAB_XPERMS_AUDITALLOW, + AVTAB_XPERMS_DONTAUDIT }; int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, @@ -359,8 +383,9 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, u32 items, items2, val, vers = pol->policyvers; struct avtab_key key; struct avtab_datum datum; - struct avtab_operation ops; - __le32 buf32[ARRAY_SIZE(ops.op.perms)]; + struct avtab_extended_perms xperms; + __le32 buf32[ARRAY_SIZE(xperms.perms.p)]; + unsigned int android_m_compat_optype = 0; int i, rc; unsigned set; @@ -417,8 +442,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); return -EINVAL; } - if (val & AVTAB_OP) { - printk(KERN_ERR "SELinux: avtab: entry has operations\n"); + if (val & AVTAB_XPERMS) { + printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n"); return -EINVAL; } @@ -444,12 +469,20 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } + items = 0; key.source_type = le16_to_cpu(buf16[items++]); key.target_type = le16_to_cpu(buf16[items++]); key.target_class = le16_to_cpu(buf16[items++]); key.specified = le16_to_cpu(buf16[items++]); + if ((key.specified & AVTAB_OPTYPE) && + (vers == POLICYDB_VERSION_XPERMS_IOCTL)) { + key.specified = avtab_optype_to_xperms(key.specified); + android_m_compat_optype = 1; + avtab_android_m_compat_set(); + } + if (!policydb_type_isvalid(pol, key.source_type) || !policydb_type_isvalid(pol, key.target_type) || !policydb_class_isvalid(pol, key.target_class)) { @@ -467,29 +500,51 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return -EINVAL; } - if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS) - || !(key.specified & AVTAB_OP)) { - rc = next_entry(buf32, fp, sizeof(u32)); + if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && + (key.specified & AVTAB_XPERMS)) { + printk(KERN_ERR "SELinux: avtab: policy version %u does not " + "support extended permissions rules and one " + "was specified\n", vers); + return -EINVAL; + } else if (key.specified & AVTAB_XPERMS) { + memset(&xperms, 0, sizeof(struct avtab_extended_perms)); + rc = next_entry(&xperms.specified, fp, sizeof(u8)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } - datum.u.data = le32_to_cpu(*buf32); - } else { - memset(&ops, 0, sizeof(struct avtab_operation)); - rc = next_entry(&ops.type, fp, sizeof(u8)); + if (avtab_android_m_compat || + ((xperms.specified != AVTAB_XPERMS_IOCTLFUNCTION) && + (xperms.specified != AVTAB_XPERMS_IOCTLDRIVER) && + (vers == POLICYDB_VERSION_XPERMS_IOCTL))) { + xperms.driver = xperms.specified; + if (android_m_compat_optype) + xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; + else + xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; + avtab_android_m_compat_set(); + } else { + rc = next_entry(&xperms.driver, fp, sizeof(u8)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + } + rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } - rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(ops.op.perms)); + for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++) + xperms.perms.p[i] = le32_to_cpu(buf32[i]); + datum.u.xperms = &xperms; + } else { + rc = next_entry(buf32, fp, sizeof(u32)); if (rc) { printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } - for (i = 0; i < ARRAY_SIZE(ops.op.perms); i++) - ops.op.perms[i] = le32_to_cpu(buf32[i]); - datum.u.ops = &ops; + datum.u.data = le32_to_cpu(*buf32); } if ((key.specified & AVTAB_TYPE) && !policydb_type_isvalid(pol, datum.u.data)) { @@ -552,26 +607,36 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) { __le16 buf16[4]; - __le32 buf32[ARRAY_SIZE(cur->datum.u.ops->op.perms)]; + __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; int rc; unsigned int i; buf16[0] = cpu_to_le16(cur->key.source_type); buf16[1] = cpu_to_le16(cur->key.target_type); buf16[2] = cpu_to_le16(cur->key.target_class); - buf16[3] = cpu_to_le16(cur->key.specified); + if (avtab_android_m_compat && (cur->key.specified & AVTAB_XPERMS) && + (cur->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER)) + buf16[3] = cpu_to_le16(avtab_xperms_to_optype(cur->key.specified)); + else + buf16[3] = cpu_to_le16(cur->key.specified); rc = put_entry(buf16, sizeof(u16), 4, fp); if (rc) return rc; - if (cur->key.specified & AVTAB_OP) { - rc = put_entry(&cur->datum.u.ops->type, sizeof(u8), 1, fp); + if (cur->key.specified & AVTAB_XPERMS) { + if (avtab_android_m_compat == 0) { + rc = put_entry(&cur->datum.u.xperms->specified, + sizeof(u8), 1, fp); + if (rc) + return rc; + } + rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); if (rc) return rc; - for (i = 0; i < ARRAY_SIZE(cur->datum.u.ops->op.perms); i++) - buf32[i] = cpu_to_le32(cur->datum.u.ops->op.perms[i]); + for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++) + buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]); rc = put_entry(buf32, sizeof(u32), - ARRAY_SIZE(cur->datum.u.ops->op.perms), fp); + ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); } else { buf32[0] = cpu_to_le32(cur->datum.u.data); rc = put_entry(buf32, sizeof(u32), 1, fp); @@ -608,13 +673,13 @@ void avtab_cache_init(void) avtab_node_cachep = kmem_cache_create("avtab_node", sizeof(struct avtab_node), 0, SLAB_PANIC, NULL); - avtab_operation_cachep = kmem_cache_create("avtab_operation", - sizeof(struct avtab_operation), - 0, SLAB_PANIC, NULL); + avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms", + sizeof(struct avtab_extended_perms), + 0, SLAB_PANIC, NULL); } void avtab_cache_destroy(void) { kmem_cache_destroy(avtab_node_cachep); - kmem_cache_destroy(avtab_operation_cachep); + kmem_cache_destroy(avtab_xperms_cachep); } diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 97acd6fa705e..8133523ca679 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -37,33 +37,42 @@ struct avtab_key { #define AVTAB_MEMBER 0x0020 #define AVTAB_CHANGE 0x0040 #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) -#define AVTAB_OPNUM_ALLOWED 0x0100 -#define AVTAB_OPNUM_AUDITALLOW 0x0200 -#define AVTAB_OPNUM_DONTAUDIT 0x0400 -#define AVTAB_OPNUM (AVTAB_OPNUM_ALLOWED | \ - AVTAB_OPNUM_AUDITALLOW | \ - AVTAB_OPNUM_DONTAUDIT) -#define AVTAB_OPTYPE_ALLOWED 0x1000 -#define AVTAB_OPTYPE_AUDITALLOW 0x2000 -#define AVTAB_OPTYPE_DONTAUDIT 0x4000 -#define AVTAB_OPTYPE (AVTAB_OPTYPE_ALLOWED | \ - AVTAB_OPTYPE_AUDITALLOW | \ - AVTAB_OPTYPE_DONTAUDIT) -#define AVTAB_OP (AVTAB_OPNUM | AVTAB_OPTYPE) +/* extended permissions */ +#define AVTAB_XPERMS_ALLOWED 0x0100 +#define AVTAB_XPERMS_AUDITALLOW 0x0200 +#define AVTAB_XPERMS_DONTAUDIT 0x0400 +#define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \ + AVTAB_XPERMS_AUDITALLOW | \ + AVTAB_XPERMS_DONTAUDIT) #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ u16 specified; /* what field is specified */ }; -struct avtab_operation { - u8 type; - struct operation_perm op; +/* + * For operations that require more than the 32 permissions provided by the avc + * extended permissions may be used to provide 256 bits of permissions. + */ +struct avtab_extended_perms { +/* These are not flags. All 256 values may be used */ +#define AVTAB_XPERMS_IOCTLFUNCTION 0x01 +#define AVTAB_XPERMS_IOCTLDRIVER 0x02 + /* extension of the avtab_key specified */ + u8 specified; /* ioctl, netfilter, ... */ + /* + * if 256 bits is not adequate as is often the case with ioctls, then + * multiple extended perms may be used and the driver field + * specifies which permissions are included. + */ + u8 driver; + /* 256 bits of permissions */ + struct extended_perms_data perms; }; struct avtab_datum { union { u32 data; /* access vector or type value */ - struct avtab_operation *ops; /* ioctl operations */ + struct avtab_extended_perms *xperms; } u; }; diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 16651c7a1541..6618fb45cca0 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -619,18 +619,18 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) return 0; } -void cond_compute_operation(struct avtab *ctab, struct avtab_key *key, - struct operation_decision *od) +void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, + struct extended_perms_decision *xpermd) { struct avtab_node *node; - if (!ctab || !key || !od) + if (!ctab || !key || !xpermd) return; for (node = avtab_search_node(ctab, key); node; node = avtab_search_node_next(node, key->specified)) { if (node->key.specified & AVTAB_ENABLED) - services_compute_operation_num(od, node); + services_compute_xperms_decision(xpermd, node); } return; @@ -639,11 +639,11 @@ void cond_compute_operation(struct avtab *ctab, struct avtab_key *key, * av table, and if so, add them to the result */ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, - struct av_decision *avd, struct operation *ops) + struct av_decision *avd, struct extended_perms *xperms) { struct avtab_node *node; - if (!ctab || !key || !avd || !ops) + if (!ctab || !key || !avd || !xperms) return; for (node = avtab_search_node(ctab, key); node; @@ -663,8 +663,8 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) avd->auditallow |= node->datum.u.data; if ((node->key.specified & AVTAB_ENABLED) && - (node->key.specified & AVTAB_OP)) - services_compute_operation_type(ops, node); + (node->key.specified & AVTAB_XPERMS)) + services_compute_xperms_drivers(xperms, node); } return; } diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 80ee2bb20eee..ddb43e7e1c75 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -74,9 +74,9 @@ int cond_write_bool(void *key, void *datum, void *ptr); int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); void cond_compute_av(struct avtab *ctab, struct avtab_key *key, - struct av_decision *avd, struct operation *ops); -void cond_compute_operation(struct avtab *ctab, struct avtab_key *key, - struct operation_decision *od); + struct av_decision *avd, struct extended_perms *xperms); +void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, + struct extended_perms_decision *xpermd); int evaluate_cond_node(struct policydb *p, struct cond_node *node); #endif /* _CONDITIONAL_H_ */ diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index a683475e1635..ca2c6f47d905 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -149,7 +149,7 @@ static struct policydb_compat_info policydb_compat[] = { .ocon_num = OCON_NUM, }, { - .version = POLICYDB_VERSION_IOCTL_OPERATIONS, + .version = POLICYDB_VERSION_XPERMS_IOCTL, .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 88178da2b834..cf905cdce93f 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -95,7 +95,7 @@ static void context_struct_compute_av(struct context *scontext, struct context *tcontext, u16 tclass, struct av_decision *avd, - struct operation *ops); + struct extended_perms *xperms); struct selinux_mapping { u16 value; /* policy value */ @@ -615,39 +615,40 @@ static void type_attribute_bounds_av(struct context *scontext, } } -/* flag ioctl types that have operation permissions */ -void services_compute_operation_type( - struct operation *ops, +/* + * flag which drivers have permissions + * only looking for ioctl based extended permssions + */ +void services_compute_xperms_drivers( + struct extended_perms *xperms, struct avtab_node *node) { - u8 type; unsigned int i; - if (node->key.specified & AVTAB_OPTYPE) { - /* if allowing one or more complete types */ - for (i = 0; i < ARRAY_SIZE(ops->type); i++) - ops->type[i] |= node->datum.u.ops->op.perms[i]; - } else { - /* if allowing operations within a type */ - type = node->datum.u.ops->type; - security_operation_set(ops->type, type); + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + /* if one or more driver has all permissions allowed */ + for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) + xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; + } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + /* if allowing permissions within a driver */ + security_xperm_set(xperms->drivers.p, + node->datum.u.xperms->driver); } /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ - if (node->key.specified & AVTAB_OPTYPE_ALLOWED || - node->key.specified & AVTAB_OPNUM_ALLOWED) - ops->len = 1; + if (node->key.specified & AVTAB_XPERMS_ALLOWED) + xperms->len = 1; } /* - * Compute access vectors and operations ranges based on a context + * Compute access vectors and extended permissions based on a context * structure pair for the permissions in a particular class. */ static void context_struct_compute_av(struct context *scontext, struct context *tcontext, u16 tclass, struct av_decision *avd, - struct operation *ops) + struct extended_perms *xperms) { struct constraint_node *constraint; struct role_allow *ra; @@ -661,9 +662,9 @@ static void context_struct_compute_av(struct context *scontext, avd->allowed = 0; avd->auditallow = 0; avd->auditdeny = 0xffffffff; - if (ops) { - memset(&ops->type, 0, sizeof(ops->type)); - ops->len = 0; + if (xperms) { + memset(&xperms->drivers, 0, sizeof(xperms->drivers)); + xperms->len = 0; } if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { @@ -679,7 +680,7 @@ static void context_struct_compute_av(struct context *scontext, * this permission check, then use it. */ avkey.target_class = tclass; - avkey.specified = AVTAB_AV | AVTAB_OP; + avkey.specified = AVTAB_AV | AVTAB_XPERMS; sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); BUG_ON(!sattr); tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); @@ -697,12 +698,13 @@ static void context_struct_compute_av(struct context *scontext, avd->auditallow |= node->datum.u.data; else if (node->key.specified == AVTAB_AUDITDENY) avd->auditdeny &= node->datum.u.data; - else if (ops && (node->key.specified & AVTAB_OP)) - services_compute_operation_type(ops, node); + else if (xperms && (node->key.specified & AVTAB_XPERMS)) + services_compute_xperms_drivers(xperms, node); } /* Check conditional av table for additional permissions */ - cond_compute_av(&policydb.te_cond_avtab, &avkey, avd, ops); + cond_compute_av(&policydb.te_cond_avtab, &avkey, + avd, xperms); } } @@ -933,57 +935,65 @@ static void avd_init(struct av_decision *avd) avd->flags = 0; } -void services_compute_operation_num(struct operation_decision *od, +void services_compute_xperms_decision(struct extended_perms_decision *xpermd, struct avtab_node *node) { unsigned int i; - if (node->key.specified & AVTAB_OPNUM) { - if (od->type != node->datum.u.ops->type) + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + if (xpermd->driver != node->datum.u.xperms->driver) return; - } else { - if (!security_operation_test(node->datum.u.ops->op.perms, - od->type)) + } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + if (!security_xperm_test(node->datum.u.xperms->perms.p, + xpermd->driver)) return; + } else { + BUG(); } - if (node->key.specified == AVTAB_OPTYPE_ALLOWED) { - od->specified |= OPERATION_ALLOWED; - memset(od->allowed->perms, 0xff, - sizeof(od->allowed->perms)); - } else if (node->key.specified == AVTAB_OPTYPE_AUDITALLOW) { - od->specified |= OPERATION_AUDITALLOW; - memset(od->auditallow->perms, 0xff, - sizeof(od->auditallow->perms)); - } else if (node->key.specified == AVTAB_OPTYPE_DONTAUDIT) { - od->specified |= OPERATION_DONTAUDIT; - memset(od->dontaudit->perms, 0xff, - sizeof(od->dontaudit->perms)); - } else if (node->key.specified == AVTAB_OPNUM_ALLOWED) { - od->specified |= OPERATION_ALLOWED; - for (i = 0; i < ARRAY_SIZE(od->allowed->perms); i++) - od->allowed->perms[i] |= - node->datum.u.ops->op.perms[i]; - } else if (node->key.specified == AVTAB_OPNUM_AUDITALLOW) { - od->specified |= OPERATION_AUDITALLOW; - for (i = 0; i < ARRAY_SIZE(od->auditallow->perms); i++) - od->auditallow->perms[i] |= - node->datum.u.ops->op.perms[i]; - } else if (node->key.specified == AVTAB_OPNUM_DONTAUDIT) { - od->specified |= OPERATION_DONTAUDIT; - for (i = 0; i < ARRAY_SIZE(od->dontaudit->perms); i++) - od->dontaudit->perms[i] |= - node->datum.u.ops->op.perms[i]; + if (node->key.specified == AVTAB_XPERMS_ALLOWED) { + xpermd->used |= XPERMS_ALLOWED; + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + memset(xpermd->allowed->p, 0xff, + sizeof(xpermd->allowed->p)); + } + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) + xpermd->allowed->p[i] |= + node->datum.u.xperms->perms.p[i]; + } + } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { + xpermd->used |= XPERMS_AUDITALLOW; + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + memset(xpermd->auditallow->p, 0xff, + sizeof(xpermd->auditallow->p)); + } + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) + xpermd->auditallow->p[i] |= + node->datum.u.xperms->perms.p[i]; + } + } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { + xpermd->used |= XPERMS_DONTAUDIT; + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + memset(xpermd->dontaudit->p, 0xff, + sizeof(xpermd->dontaudit->p)); + } + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) + xpermd->dontaudit->p[i] |= + node->datum.u.xperms->perms.p[i]; + } } else { BUG(); } } -void security_compute_operation(u32 ssid, +void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 orig_tclass, - u8 type, - struct operation_decision *od) + u8 driver, + struct extended_perms_decision *xpermd) { u16 tclass; struct context *scontext, *tcontext; @@ -993,11 +1003,11 @@ void security_compute_operation(u32 ssid, struct ebitmap_node *snode, *tnode; unsigned int i, j; - od->type = type; - od->specified = 0; - memset(od->allowed->perms, 0, sizeof(od->allowed->perms)); - memset(od->auditallow->perms, 0, sizeof(od->auditallow->perms)); - memset(od->dontaudit->perms, 0, sizeof(od->dontaudit->perms)); + xpermd->driver = driver; + xpermd->used = 0; + memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); + memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); + memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); read_lock(&policy_rwlock); if (!ss_initialized) @@ -1031,7 +1041,7 @@ void security_compute_operation(u32 ssid, } avkey.target_class = tclass; - avkey.specified = AVTAB_OP; + avkey.specified = AVTAB_XPERMS; sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); BUG_ON(!sattr); @@ -1045,26 +1055,27 @@ void security_compute_operation(u32 ssid, for (node = avtab_search_node(&policydb.te_avtab, &avkey); node; node = avtab_search_node_next(node, avkey.specified)) - services_compute_operation_num(od, node); + services_compute_xperms_decision(xpermd, node); - cond_compute_operation(&policydb.te_cond_avtab, - &avkey, od); + cond_compute_xperms(&policydb.te_cond_avtab, + &avkey, xpermd); } } out: read_unlock(&policy_rwlock); return; allow: - memset(od->allowed->perms, 0xff, sizeof(od->allowed->perms)); + memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); goto out; } + /** * security_compute_av - Compute access vector decisions. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @avd: access vector decisions - * @od: operation decisions + * @xperms: extended permissions * * Compute a set of access vector decisions based on the * SID pair (@ssid, @tsid) for the permissions in @tclass. @@ -1073,14 +1084,14 @@ void security_compute_av(u32 ssid, u32 tsid, u16 orig_tclass, struct av_decision *avd, - struct operation *ops) + struct extended_perms *xperms) { u16 tclass; struct context *scontext = NULL, *tcontext = NULL; read_lock(&policy_rwlock); avd_init(avd); - ops->len = 0; + xperms->len = 0; if (!ss_initialized) goto allow; @@ -1108,7 +1119,7 @@ void security_compute_av(u32 ssid, goto allow; goto out; } - context_struct_compute_av(scontext, tcontext, tclass, avd, ops); + context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); map_decision(orig_tclass, avd, policydb.allow_unknown); out: read_unlock(&policy_rwlock); diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index 569757484d05..6abcd8729ec3 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h @@ -11,10 +11,10 @@ extern struct policydb policydb; -void services_compute_operation_type(struct operation *ops, +void services_compute_xperms_drivers(struct extended_perms *xperms, struct avtab_node *node); -void services_compute_operation_num(struct operation_decision *od, +void services_compute_xperms_decision(struct extended_perms_decision *xpermd, struct avtab_node *node); #endif /* _SS_SERVICES_H_ */