From 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 21 Feb 2023 18:24:12 -0800 Subject: Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - Add dedicated kmem_cache for typical/small skb->head, avoid having to access struct page at kfree time, and improve memory use. - Introduce sysctl to set default RPS configuration for new netdevs. - Define Netlink protocol specification format which can be used to describe messages used by each family and auto-generate parsers. Add tools for generating kernel data structures and uAPI headers. - Expose all net/core sysctls inside netns. - Remove 4s sleep in netpoll if carrier is instantly detected on boot. - Add configurable limit of MDB entries per port, and port-vlan. - Continue populating drop reasons throughout the stack. - Retire a handful of legacy Qdiscs and classifiers. Protocols: - Support IPv4 big TCP (TSO frames larger than 64kB). - Add IP_LOCAL_PORT_RANGE socket option, to control local port range on socket by socket basis. - Track and report in procfs number of MPTCP sockets used. - Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path manager. - IPv6: don't check net.ipv6.route.max_size and rely on garbage collection to free memory (similarly to IPv4). - Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986). - ICMP: add per-rate limit counters. - Add support for user scanning requests in ieee802154. - Remove static WEP support. - Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting. - WiFi 7 EHT channel puncturing support (client & AP). BPF: - Add a rbtree data structure following the "next-gen data structure" precedent set by recently added linked list, that is, by using kfunc + kptr instead of adding a new BPF map type. - Expose XDP hints via kfuncs with initial support for RX hash and timestamp metadata. - Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to better support decap on GRE tunnel devices not operating in collect metadata. - Improve x86 JIT's codegen for PROBE_MEM runtime error checks. - Remove the need for trace_printk_lock for bpf_trace_printk and bpf_trace_vprintk helpers. - Extend libbpf's bpf_tracing.h support for tracing arguments of kprobes/uprobes and syscall as a special case. - Significantly reduce the search time for module symbols by livepatch and BPF. - Enable cpumasks to be used as kptrs, which is useful for tracing programs tracking which tasks end up running on which CPUs in different time intervals. - Add support for BPF trampoline on s390x and riscv64. - Add capability to export the XDP features supported by the NIC. - Add __bpf_kfunc tag for marking kernel functions as kfuncs. - Add cgroup.memory=nobpf kernel parameter option to disable BPF memory accounting for container environments. Netfilter: - Remove the CLUSTERIP target. It has been marked as obsolete for years, and we still have WARN splats wrt races of the out-of-band /proc interface installed by this target. - Add 'destroy' commands to nf_tables. They are identical to the existing 'delete' commands, but do not return an error if the referenced object (set, chain, rule...) did not exist. Driver API: - Improve cpumask_local_spread() locality to help NICs set the right IRQ affinity on AMD platforms. - Separate C22 and C45 MDIO bus transactions more clearly. - Introduce new DCB table to control DSCP rewrite on egress. - Support configuration of Physical Layer Collision Avoidance (PLCA) Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of shared medium Ethernet. - Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing preemption of low priority frames by high priority frames. - Add support for controlling MACSec offload using netlink SET. - Rework devlink instance refcounts to allow registration and de-registration under the instance lock. Split the code into multiple files, drop some of the unnecessarily granular locks and factor out common parts of netlink operation handling. - Add TX frame aggregation parameters (for USB drivers). - Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning messages with notifications for debug. - Allow offloading of UDP NEW connections via act_ct. - Add support for per action HW stats in TC. - Support hardware miss to TC action (continue processing in SW from a specific point in the action chain). - Warn if old Wireless Extension user space interface is used with modern cfg80211/mac80211 drivers. Do not support Wireless Extensions for Wi-Fi 7 devices at all. Everyone should switch to using nl80211 interface instead. - Improve the CAN bit timing configuration. Use extack to return error messages directly to user space, update the SJW handling, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. New hardware / drivers: - Ethernet: - nVidia BlueField-3 support (control traffic driver) - Ethernet support for imx93 SoCs - Motorcomm yt8531 gigabit Ethernet PHY - onsemi NCN26000 10BASE-T1S PHY (with support for PLCA) - Microchip LAN8841 PHY (incl. cable diagnostics and PTP) - Amlogic gxl MDIO mux - WiFi: - RealTek RTL8188EU (rtl8xxxu) - Qualcomm Wi-Fi 7 devices (ath12k) - CAN: - Renesas R-Car V4H Drivers: - Bluetooth: - Set Per Platform Antenna Gain (PPAG) for Intel controllers. - Ethernet NICs: - Intel (1G, igc): - support TSN / Qbv / packet scheduling features of i226 model - Intel (100G, ice): - use GNSS subsystem instead of TTY - multi-buffer XDP support - extend support for GPIO pins to E823 devices - nVidia/Mellanox: - update the shared buffer configuration on PFC commands - implement PTP adjphase function for HW offset control - TC support for Geneve and GRE with VF tunnel offload - more efficient crypto key management method - multi-port eswitch support - Netronome/Corigine: - add DCB IEEE support - support IPsec offloading for NFP3800 - Freescale/NXP (enetc): - support XDP_REDIRECT for XDP non-linear buffers - improve reconfig, avoid link flap and waiting for idle - support MAC Merge layer - Other NICs: - sfc/ef100: add basic devlink support for ef100 - ionic: rx_push mode operation (writing descriptors via MMIO) - bnxt: use the auxiliary bus abstraction for RDMA - r8169: disable ASPM and reset bus in case of tx timeout - cpsw: support QSGMII mode for J721e CPSW9G - cpts: support pulse-per-second output - ngbe: add an mdio bus driver - usbnet: optimize usbnet_bh() by avoiding unnecessary queuing - r8152: handle devices with FW with NCM support - amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation - virtio-net: support multi buffer XDP - virtio/vsock: replace virtio_vsock_pkt with sk_buff - tsnep: XDP support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add support for latency TLV (in FW control messages) - Microchip (sparx5): - separate explicit and implicit traffic forwarding rules, make the implicit rules always active - add support for egress DSCP rewrite - IS0 VCAP support (Ingress Classification) - IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS etc.) - ES2 VCAP support (Egress Access Control) - support for Per-Stream Filtering and Policing (802.1Q, 8.6.5.1) - Ethernet embedded switches: - Marvell (mv88e6xxx): - add MAB (port auth) offload support - enable PTP receive for mv88e6390 - NXP (ocelot): - support MAC Merge layer - support for the the vsc7512 internal copper phys - Microchip: - lan9303: convert to PHYLINK - lan966x: support TC flower filter statistics - lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x - lan937x: support Credit Based Shaper configuration - ksz9477: support Energy Efficient Ethernet - other: - qca8k: convert to regmap read/write API, use bulk operations - rswitch: Improve TX timestamp accuracy - Intel WiFi (iwlwifi): - EHT (Wi-Fi 7) rate reporting - STEP equalizer support: transfer some STEP (connection to radio on platforms with integrated wifi) related parameters from the BIOS to the firmware. - Qualcomm 802.11ax WiFi (ath11k): - IPQ5018 support - Fine Timing Measurement (FTM) responder role support - channel 177 support - MediaTek WiFi (mt76): - per-PHY LED support - mt7996: EHT (Wi-Fi 7) support - Wireless Ethernet Dispatch (WED) reset support - switch to using page pool allocator - RealTek WiFi (rtw89): - support new version of Bluetooth co-existance - Mobile: - rmnet: support TX aggregation" * tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits) page_pool: add a comment explaining the fragment counter usage net: ethtool: fix __ethtool_dev_mm_supported() implementation ethtool: pse-pd: Fix double word in comments xsk: add linux/vmalloc.h to xsk.c sefltests: netdevsim: wait for devlink instance after netns removal selftest: fib_tests: Always cleanup before exit net/mlx5e: Align IPsec ASO result memory to be as required by hardware net/mlx5e: TC, Set CT miss to the specific ct action instance net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG net/mlx5: Refactor tc miss handling to a single function net/mlx5: Kconfig: Make tc offload depend on tc skb extension net/sched: flower: Support hardware miss to tc action net/sched: flower: Move filter handle initialization earlier net/sched: cls_api: Support hardware miss to tc action net/sched: Rename user cookie and act cookie sfc: fix builds without CONFIG_RTC_LIB sfc: clean up some inconsistent indentings net/mlx4_en: Introduce flexible array to silence overflow warning net: lan966x: Fix possible deadlock inside PTP net/ulp: Remove redundant ->clone() test in inet_clone_ulp(). ... --- security/apparmor/.gitignore | 4 + security/apparmor/Kconfig | 123 ++ security/apparmor/Makefile | 114 ++ security/apparmor/apparmorfs.c | 2691 +++++++++++++++++++++++++++++ security/apparmor/audit.c | 290 ++++ security/apparmor/capability.c | 162 ++ security/apparmor/crypto.c | 123 ++ security/apparmor/domain.c | 1464 ++++++++++++++++ security/apparmor/file.c | 662 +++++++ security/apparmor/include/apparmor.h | 65 + security/apparmor/include/apparmorfs.h | 134 ++ security/apparmor/include/audit.h | 197 +++ security/apparmor/include/capability.h | 46 + security/apparmor/include/cred.h | 175 ++ security/apparmor/include/crypto.h | 37 + security/apparmor/include/domain.h | 33 + security/apparmor/include/file.h | 162 ++ security/apparmor/include/ipc.h | 18 + security/apparmor/include/label.h | 468 +++++ security/apparmor/include/lib.h | 304 ++++ security/apparmor/include/match.h | 196 +++ security/apparmor/include/mount.h | 50 + security/apparmor/include/net.h | 113 ++ security/apparmor/include/path.h | 32 + security/apparmor/include/perms.h | 219 +++ security/apparmor/include/policy.h | 380 ++++ security/apparmor/include/policy_compat.h | 33 + security/apparmor/include/policy_ns.h | 165 ++ security/apparmor/include/policy_unpack.h | 181 ++ security/apparmor/include/procattr.h | 17 + security/apparmor/include/resource.h | 46 + security/apparmor/include/secid.h | 37 + security/apparmor/include/sig_names.h | 101 ++ security/apparmor/include/task.h | 98 ++ security/apparmor/ipc.c | 110 ++ security/apparmor/label.c | 2162 +++++++++++++++++++++++ security/apparmor/lib.c | 483 ++++++ security/apparmor/lsm.c | 1942 +++++++++++++++++++++ security/apparmor/match.c | 790 +++++++++ security/apparmor/mount.c | 731 ++++++++ security/apparmor/net.c | 261 +++ security/apparmor/nulldfa.in | 107 ++ security/apparmor/path.c | 217 +++ security/apparmor/policy.c | 1340 ++++++++++++++ security/apparmor/policy_compat.c | 318 ++++ security/apparmor/policy_ns.c | 433 +++++ security/apparmor/policy_unpack.c | 1436 +++++++++++++++ security/apparmor/policy_unpack_test.c | 608 +++++++ security/apparmor/procattr.c | 135 ++ security/apparmor/resource.c | 198 +++ security/apparmor/secid.c | 149 ++ security/apparmor/stacksplitdfa.in | 114 ++ security/apparmor/task.c | 295 ++++ 53 files changed, 20769 insertions(+) create mode 100644 security/apparmor/.gitignore create mode 100644 security/apparmor/Kconfig create mode 100644 security/apparmor/Makefile create mode 100644 security/apparmor/apparmorfs.c create mode 100644 security/apparmor/audit.c create mode 100644 security/apparmor/capability.c create mode 100644 security/apparmor/crypto.c create mode 100644 security/apparmor/domain.c create mode 100644 security/apparmor/file.c create mode 100644 security/apparmor/include/apparmor.h create mode 100644 security/apparmor/include/apparmorfs.h create mode 100644 security/apparmor/include/audit.h create mode 100644 security/apparmor/include/capability.h create mode 100644 security/apparmor/include/cred.h create mode 100644 security/apparmor/include/crypto.h create mode 100644 security/apparmor/include/domain.h create mode 100644 security/apparmor/include/file.h create mode 100644 security/apparmor/include/ipc.h create mode 100644 security/apparmor/include/label.h create mode 100644 security/apparmor/include/lib.h create mode 100644 security/apparmor/include/match.h create mode 100644 security/apparmor/include/mount.h create mode 100644 security/apparmor/include/net.h create mode 100644 security/apparmor/include/path.h create mode 100644 security/apparmor/include/perms.h create mode 100644 security/apparmor/include/policy.h create mode 100644 security/apparmor/include/policy_compat.h create mode 100644 security/apparmor/include/policy_ns.h create mode 100644 security/apparmor/include/policy_unpack.h create mode 100644 security/apparmor/include/procattr.h create mode 100644 security/apparmor/include/resource.h create mode 100644 security/apparmor/include/secid.h create mode 100644 security/apparmor/include/sig_names.h create mode 100644 security/apparmor/include/task.h create mode 100644 security/apparmor/ipc.c create mode 100644 security/apparmor/label.c create mode 100644 security/apparmor/lib.c create mode 100644 security/apparmor/lsm.c create mode 100644 security/apparmor/match.c create mode 100644 security/apparmor/mount.c create mode 100644 security/apparmor/net.c create mode 100644 security/apparmor/nulldfa.in create mode 100644 security/apparmor/path.c create mode 100644 security/apparmor/policy.c create mode 100644 security/apparmor/policy_compat.c create mode 100644 security/apparmor/policy_ns.c create mode 100644 security/apparmor/policy_unpack.c create mode 100644 security/apparmor/policy_unpack_test.c create mode 100644 security/apparmor/procattr.c create mode 100644 security/apparmor/resource.c create mode 100644 security/apparmor/secid.c create mode 100644 security/apparmor/stacksplitdfa.in create mode 100644 security/apparmor/task.c (limited to 'security/apparmor') diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore new file mode 100644 index 000000000..6d1eb1c15 --- /dev/null +++ b/security/apparmor/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +net_names.h +capability_names.h +rlim_names.h diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig new file mode 100644 index 000000000..e0d1dd0a1 --- /dev/null +++ b/security/apparmor/Kconfig @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: GPL-2.0-only +config SECURITY_APPARMOR + bool "AppArmor support" + depends on SECURITY && NET + select AUDIT + select SECURITY_PATH + select SECURITYFS + select SECURITY_NETWORK + default n + help + This enables the AppArmor security module. + Required userspace tools (if they are not included in your + distribution) and further information may be found at + http://apparmor.wiki.kernel.org + + If you are unsure how to answer this question, answer N. + +config SECURITY_APPARMOR_DEBUG + bool "Build AppArmor with debug code" + depends on SECURITY_APPARMOR + default n + help + Build apparmor with debugging logic in apparmor. Not all + debugging logic will necessarily be enabled. A submenu will + provide fine grained control of the debug options that are + available. + +config SECURITY_APPARMOR_DEBUG_ASSERTS + bool "Build AppArmor with debugging asserts" + depends on SECURITY_APPARMOR_DEBUG + default y + help + Enable code assertions made with AA_BUG. These are primarily + function entry preconditions but also exist at other key + points. If the assert is triggered it will trigger a WARN + message. + +config SECURITY_APPARMOR_DEBUG_MESSAGES + bool "Debug messages enabled by default" + depends on SECURITY_APPARMOR_DEBUG + default n + help + Set the default value of the apparmor.debug kernel parameter. + When enabled, various debug messages will be logged to + the kernel message buffer. + +config SECURITY_APPARMOR_INTROSPECT_POLICY + bool "Allow loaded policy to be introspected" + depends on SECURITY_APPARMOR + default y + help + This option selects whether introspection of loaded policy + is available to userspace via the apparmor filesystem. This + adds to kernel memory usage. It is required for introspection + of loaded policy, and check point and restore support. It + can be disabled for embedded systems where reducing memory and + cpu is paramount. + +config SECURITY_APPARMOR_HASH + bool "Enable introspection of sha1 hashes for loaded profiles" + depends on SECURITY_APPARMOR_INTROSPECT_POLICY + select CRYPTO + select CRYPTO_SHA1 + default y + help + This option selects whether introspection of loaded policy + hashes is available to userspace via the apparmor + filesystem. This option provides a light weight means of + checking loaded policy. This option adds to policy load + time and can be disabled for small embedded systems. + +config SECURITY_APPARMOR_HASH_DEFAULT + bool "Enable policy hash introspection by default" + depends on SECURITY_APPARMOR_HASH + default y + help + This option selects whether sha1 hashing of loaded policy + is enabled by default. The generation of sha1 hashes for + loaded policy provide system administrators a quick way + to verify that policy in the kernel matches what is expected, + however it can slow down policy load on some devices. In + these cases policy hashing can be disabled by default and + enabled only if needed. + +config SECURITY_APPARMOR_EXPORT_BINARY + bool "Allow exporting the raw binary policy" + depends on SECURITY_APPARMOR_INTROSPECT_POLICY + select ZSTD_COMPRESS + select ZSTD_DECOMPRESS + default y + help + This option allows reading back binary policy as it was loaded. + It increases the amount of kernel memory needed by policy and + also increases policy load time. This option is required for + checkpoint and restore support, and debugging of loaded policy. + +config SECURITY_APPARMOR_PARANOID_LOAD + bool "Perform full verification of loaded policy" + depends on SECURITY_APPARMOR + default y + help + This options allows controlling whether apparmor does a full + verification of loaded policy. This should not be disabled + except for embedded systems where the image is read only, + includes policy, and has some form of integrity check. + Disabling the check will speed up policy loads. + +config SECURITY_APPARMOR_KUNIT_TEST + tristate "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS + depends on KUNIT && SECURITY_APPARMOR + default KUNIT_ALL_TESTS + help + This builds the AppArmor KUnit tests. + + KUnit tests run during boot and output the results to the debug log + in TAP format (https://testanything.org/). Only useful for kernel devs + running KUnit test harness and are not for inclusion into a + production build. + + For more information on KUnit and unit tests in general please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile new file mode 100644 index 000000000..b9c5879dd --- /dev/null +++ b/security/apparmor/Makefile @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for AppArmor Linux Security Module +# +obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o + +apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \ + path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ + resource.o secid.o file.o policy_ns.o label.o mount.o net.o \ + policy_compat.o +apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o + +obj-$(CONFIG_SECURITY_APPARMOR_KUNIT_TEST) += apparmor_policy_unpack_test.o +apparmor_policy_unpack_test-objs += policy_unpack_test.o + +clean-files := capability_names.h rlim_names.h net_names.h + +# Build a lower case string table of address family names +# Transform lines from +# #define AF_LOCAL 1 /* POSIX name for AF_UNIX */ +# #define AF_INET 2 /* Internet IP Protocol */ +# to +# [1] = "local", +# [2] = "inet", +# +# and build the securityfs entries for the mapping. +# Transforms lines from +# #define AF_INET 2 /* Internet IP Protocol */ +# to +# #define AA_SFS_AF_MASK "local inet" +quiet_cmd_make-af = GEN $@ +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ + echo "};" >> $@ ;\ + printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\ + sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\ + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ + +# Build a lower case string table of sock type names +# Transform lines from +# SOCK_STREAM = 1, +# to +# [1] = "stream", +quiet_cmd_make-sock = GEN $@ +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ + sed $^ >>$@ -r -n \ + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ + echo "};" >> $@ + +# Build a lower case string table of capability names +# Transforms lines from +# #define CAP_DAC_OVERRIDE 1 +# to +# [1] = "dac_override", +quiet_cmd_make-caps = GEN $@ +cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\ + sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \ + -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\ + echo "};" >> $@ ;\ + printf '%s' '\#define AA_SFS_CAPS_MASK "' >> $@ ;\ + sed $< -r -n -e '/CAP_FS_MASK/d' \ + -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \ + tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ + + +# Build a lower case string table of rlimit names. +# Transforms lines from +# #define RLIMIT_STACK 3 /* max stack size */ +# to +# [RLIMIT_STACK] = "stack", +# +# and build a second integer table (with the second sed cmd), that maps +# RLIMIT defines to the order defined in asm-generic/resource.h This is +# required by policy load to map policy ordering of RLIMITs to internal +# ordering for architectures that redefine an RLIMIT. +# Transforms lines from +# #define RLIMIT_STACK 3 /* max stack size */ +# to +# RLIMIT_STACK, +# +# and build the securityfs entries for the mapping. +# Transforms lines from +# #define RLIMIT_FSIZE 1 /* Maximum filesize */ +# #define RLIMIT_STACK 3 /* max stack size */ +# to +# #define AA_SFS_RLIMIT_MASK "fsize stack" +quiet_cmd_make-rlim = GEN $@ +cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ + > $@ ;\ + sed $< >> $@ -r -n \ + -e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\ + echo "};" >> $@ ;\ + echo "static const int rlim_map[RLIM_NLIMITS] = {" >> $@ ;\ + sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\ + echo "};" >> $@ ; \ + printf '%s' '\#define AA_SFS_RLIMIT_MASK "' >> $@ ;\ + sed -r -n 's/^\# ?define[ \t]+RLIMIT_([A-Z0-9_]+).*/\L\1/p' $< | \ + tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ + +$(obj)/capability.o : $(obj)/capability_names.h +$(obj)/net.o : $(obj)/net_names.h +$(obj)/resource.o : $(obj)/rlim_names.h +$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ + $(src)/Makefile + $(call cmd,make-caps) +$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ + $(src)/Makefile + $(call cmd,make-rlim) +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \ + $(srctree)/include/linux/net.h \ + $(src)/Makefile + $(call cmd,make-af) + $(call cmd,make-sock) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c new file mode 100644 index 000000000..db7a51acf --- /dev/null +++ b/security/apparmor/apparmorfs.c @@ -0,0 +1,2691 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AppArmor security module + * + * This file contains AppArmor /sys/kernel/security/apparmor interface functions + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2010 Canonical Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "include/apparmor.h" +#include "include/apparmorfs.h" +#include "include/audit.h" +#include "include/cred.h" +#include "include/crypto.h" +#include "include/ipc.h" +#include "include/label.h" +#include "include/policy.h" +#include "include/policy_ns.h" +#include "include/resource.h" +#include "include/policy_unpack.h" +#include "include/task.h" + +/* + * The apparmor filesystem interface used for policy load and introspection + * The interface is split into two main components based on their function + * a securityfs component: + * used for static files that are always available, and which allows + * userspace to specificy the location of the security filesystem. + * + * fns and data are prefixed with + * aa_sfs_ + * + * an apparmorfs component: + * used loaded policy content and introspection. It is not part of a + * regular mounted filesystem and is available only through the magic + * policy symlink in the root of the securityfs apparmor/ directory. + * Tasks queries will be magically redirected to the correct portion + * of the policy tree based on their confinement. + * + * fns and data are prefixed with + * aafs_ + * + * The aa_fs_ prefix is used to indicate the fn is used by both the + * securityfs and apparmorfs filesystems. + */ + + +/* + * support fns + */ + +struct rawdata_f_data { + struct aa_loaddata *loaddata; +}; + +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY +#define RAWDATA_F_DATA_BUF(p) (char *)(p + 1) + +static void rawdata_f_data_free(struct rawdata_f_data *private) +{ + if (!private) + return; + + aa_put_loaddata(private->loaddata); + kvfree(private); +} + +static struct rawdata_f_data *rawdata_f_data_alloc(size_t size) +{ + struct rawdata_f_data *ret; + + if (size > SIZE_MAX - sizeof(*ret)) + return ERR_PTR(-EINVAL); + + ret = kvzalloc(sizeof(*ret) + size, GFP_KERNEL); + if (!ret) + return ERR_PTR(-ENOMEM); + + return ret; +} +#endif + +/** + * mangle_name - mangle a profile name to std profile layout form + * @name: profile name to mangle (NOT NULL) + * @target: buffer to store mangled name, same length as @name (MAYBE NULL) + * + * Returns: length of mangled name + */ +static int mangle_name(const char *name, char *target) +{ + char *t = target; + + while (*name == '/' || *name == '.') + name++; + + if (target) { + for (; *name; name++) { + if (*name == '/') + *(t)++ = '.'; + else if (isspace(*name)) + *(t)++ = '_'; + else if (isalnum(*name) || strchr("._-", *name)) + *(t)++ = *name; + } + + *t = 0; + } else { + int len = 0; + for (; *name; name++) { + if (isalnum(*name) || isspace(*name) || + strchr("/._-", *name)) + len++; + } + + return len; + } + + return t - target; +} + + +/* + * aafs - core fns and data for the policy tree + */ + +#define AAFS_NAME "apparmorfs" +static struct vfsmount *aafs_mnt; +static int aafs_count; + + +static int aafs_show_path(struct seq_file *seq, struct dentry *dentry) +{ + seq_printf(seq, "%s:[%lu]", AAFS_NAME, d_inode(dentry)->i_ino); + return 0; +} + +static void aafs_free_inode(struct inode *inode) +{ + if (S_ISLNK(inode->i_mode)) + kfree(inode->i_link); + free_inode_nonrcu(inode); +} + +static const struct super_operations aafs_super_ops = { + .statfs = simple_statfs, + .free_inode = aafs_free_inode, + .show_path = aafs_show_path, +}; + +static int apparmorfs_fill_super(struct super_block *sb, struct fs_context *fc) +{ + static struct tree_descr files[] = { {""} }; + int error; + + error = simple_fill_super(sb, AAFS_MAGIC, files); + if (error) + return error; + sb->s_op = &aafs_super_ops; + + return 0; +} + +static int apparmorfs_get_tree(struct fs_context *fc) +{ + return get_tree_single(fc, apparmorfs_fill_super); +} + +static const struct fs_context_operations apparmorfs_context_ops = { + .get_tree = apparmorfs_get_tree, +}; + +static int apparmorfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &apparmorfs_context_ops; + return 0; +} + +static struct file_system_type aafs_ops = { + .owner = THIS_MODULE, + .name = AAFS_NAME, + .init_fs_context = apparmorfs_init_fs_context, + .kill_sb = kill_anon_super, +}; + +/** + * __aafs_setup_d_inode - basic inode setup for apparmorfs + * @dir: parent directory for the dentry + * @dentry: dentry we are seting the inode up for + * @mode: permissions the file should have + * @data: data to store on inode.i_private, available in open() + * @link: if symlink, symlink target string + * @fops: struct file_operations that should be used + * @iops: struct of inode_operations that should be used + */ +static int __aafs_setup_d_inode(struct inode *dir, struct dentry *dentry, + umode_t mode, void *data, char *link, + const struct file_operations *fops, + const struct inode_operations *iops) +{ + struct inode *inode = new_inode(dir->i_sb); + + AA_BUG(!dir); + AA_BUG(!dentry); + + if (!inode) + return -ENOMEM; + + inode->i_ino = get_next_ino(); + inode->i_mode = mode; + inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); + inode->i_private = data; + if (S_ISDIR(mode)) { + inode->i_op = iops ? iops : &simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + inc_nlink(inode); + inc_nlink(dir); + } else if (S_ISLNK(mode)) { + inode->i_op = iops ? iops : &simple_symlink_inode_operations; + inode->i_link = link; + } else { + inode->i_fop = fops; + } + d_instantiate(dentry, inode); + dget(dentry); + + return 0; +} + +/** + * aafs_create - create a dentry in the apparmorfs filesystem + * + * @name: name of dentry to create + * @mode: permissions the file should have + * @parent: parent directory for this dentry + * @data: data to store on inode.i_private, available in open() + * @link: if symlink, symlink target string + * @fops: struct file_operations that should be used for + * @iops: struct of inode_operations that should be used + * + * This is the basic "create a xxx" function for apparmorfs. + * + * Returns a pointer to a dentry if it succeeds, that must be free with + * aafs_remove(). Will return ERR_PTR on failure. + */ +static struct dentry *aafs_create(const char *name, umode_t mode, + struct dentry *parent, void *data, void *link, + const struct file_operations *fops, + const struct inode_operations *iops) +{ + struct dentry *dentry; + struct inode *dir; + int error; + + AA_BUG(!name); + AA_BUG(!parent); + + if (!(mode & S_IFMT)) + mode = (mode & S_IALLUGO) | S_IFREG; + + error = simple_pin_fs(&aafs_ops, &aafs_mnt, &aafs_count); + if (error) + return ERR_PTR(error); + + dir = d_inode(parent); + + inode_lock(dir); + dentry = lookup_one_len(name, parent, strlen(name)); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto fail_lock; + } + + if (d_really_is_positive(dentry)) { + error = -EEXIST; + goto fail_dentry; + } + + error = __aafs_setup_d_inode(dir, dentry, mode, data, link, fops, iops); + if (error) + goto fail_dentry; + inode_unlock(dir); + + return dentry; + +fail_dentry: + dput(dentry); + +fail_lock: + inode_unlock(dir); + simple_release_fs(&aafs_mnt, &aafs_count); + + return ERR_PTR(error); +} + +/** + * aafs_create_file - create a file in the apparmorfs filesystem + * + * @name: name of dentry to create + * @mode: permissions the file should have + * @parent: parent directory for this dentry + * @data: data to store on inode.i_private, available in open() + * @fops: struct file_operations that should be used for + * + * see aafs_create + */ +static struct dentry *aafs_create_file(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops) +{ + return aafs_create(name, mode, parent, data, NULL, fops, NULL); +} + +/** + * aafs_create_dir - create a directory in the apparmorfs filesystem + * + * @name: name of dentry to create + * @parent: parent directory for this dentry + * + * see aafs_create + */ +static struct dentry *aafs_create_dir(const char *name, struct dentry *parent) +{ + return aafs_create(name, S_IFDIR | 0755, parent, NULL, NULL, NULL, + NULL); +} + +/** + * aafs_remove - removes a file or directory from the apparmorfs filesystem + * + * @dentry: dentry of the file/directory/symlink to removed. + */ +static void aafs_remove(struct dentry *dentry) +{ + struct inode *dir; + + if (!dentry || IS_ERR(dentry)) + return; + + dir = d_inode(dentry->d_parent); + inode_lock(dir); + if (simple_positive(dentry)) { + if (d_is_dir(dentry)) + simple_rmdir(dir, dentry); + else + simple_unlink(dir, dentry); + d_delete(dentry); + dput(dentry); + } + inode_unlock(dir); + simple_release_fs(&aafs_mnt, &aafs_count); +} + + +/* + * aa_fs - policy load/replace/remove + */ + +/** + * aa_simple_write_to_buffer - common routine for getting policy from user + * @userbuf: user buffer to copy data from (NOT NULL) + * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size) + * @copy_size: size of data to copy from user buffer + * @pos: position write is at in the file (NOT NULL) + * + * Returns: kernel buffer containing copy of user buffer data or an + * ERR_PTR on failure. + */ +static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, + size_t alloc_size, + size_t copy_size, + loff_t *pos) +{ + struct aa_loaddata *data; + + AA_BUG(copy_size > alloc_size); + + if (*pos != 0) + /* only writes from pos 0, that is complete writes */ + return ERR_PTR(-ESPIPE); + + /* freed by caller to simple_write_to_buffer */ + data = aa_loaddata_alloc(alloc_size); + if (IS_ERR(data)) + return data; + + data->size = copy_size; + if (copy_from_user(data->data, userbuf, copy_size)) { + aa_put_loaddata(data); + return ERR_PTR(-EFAULT); + } + + return data; +} + +static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, + loff_t *pos, struct aa_ns *ns) +{ + struct aa_loaddata *data; + struct aa_label *label; + ssize_t error; + + label = begin_current_label_crit_section(); + + /* high level check about policy management - fine grained in + * below after unpack + */ + error = aa_may_manage_policy(label, ns, mask); + if (error) + goto end_section; + + data = aa_simple_write_to_buffer(buf, size, size, pos); + error = PTR_ERR(data); + if (!IS_ERR(data)) { + error = aa_replace_profiles(ns, label, mask, data); + aa_put_loaddata(data); + } +end_section: + end_current_label_crit_section(label); + + return error; +} + +/* .load file hook fn to load policy */ +static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, + loff_t *pos) +{ + struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); + int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns); + + aa_put_ns(ns); + + return error; +} + +static const struct file_operations aa_fs_profile_load = { + .write = profile_load, + .llseek = default_llseek, +}; + +/* .replace file hook fn to load and/or replace policy */ +static ssize_t profile_replace(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); + int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY, + buf, size, pos, ns); + aa_put_ns(ns); + + return error; +} + +static const struct file_operations aa_fs_profile_replace = { + .write = profile_replace, + .llseek = default_llseek, +}; + +/* .remove file hook fn to remove loaded policy */ +static ssize_t profile_remove(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct aa_loaddata *data; + struct aa_label *label; + ssize_t error; + struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); + + label = begin_current_label_crit_section(); + /* high level check about policy management - fine grained in + * below after unpack + */ + error = aa_may_manage_policy(label, ns, AA_MAY_REMOVE_POLICY); + if (error) + goto out; + + /* + * aa_remove_profile needs a null terminated string so 1 extra + * byte is allocated and the copied data is null terminated. + */ + data = aa_simple_write_to_buffer(buf, size + 1, size, pos); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { + data->data[size] = 0; + error = aa_remove_profiles(ns, label, data->data, size); + aa_put_loaddata(data); + } + out: + end_current_label_crit_section(label); + aa_put_ns(ns); + return error; +} + +static const struct file_operations aa_fs_profile_remove = { + .write = profile_remove, + .llseek = default_llseek, +}; + +struct aa_revision { + struct aa_ns *ns; + long last_read; +}; + +/* revision file hook fn for policy loads */ +static int ns_revision_release(struct inode *inode, struct file *file) +{ + struct aa_revision *rev = file->private_data; + + if (rev) { + aa_put_ns(rev->ns); + kfree(rev); + } + + return 0; +} + +static ssize_t ns_revision_read(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + struct aa_revision *rev = file->private_data; + char buffer[32]; + long last_read; + int avail; + + mutex_lock_nested(&rev->ns->lock, rev->ns->level); + last_read = rev->last_read; + if (last_read == rev->ns->revision) { + mutex_unlock(&rev->ns->lock); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + if (wait_event_interruptible(rev->ns->wait, + last_read != + READ_ONCE(rev->ns->revision))) + return -ERESTARTSYS; + mutex_lock_nested(&rev->ns->lock, rev->ns->level); + } + + avail = sprintf(buffer, "%ld\n", rev->ns->revision); + if (*ppos + size > avail) { + rev->last_read = rev->ns->revision; + *ppos = 0; + } + mutex_unlock(&rev->ns->lock); + + return simple_read_from_buffer(buf, size, ppos, buffer, avail); +} + +static int ns_revision_open(struct inode *inode, struct file *file) +{ + struct aa_revision *rev = kzalloc(sizeof(*rev), GFP_KERNEL); + + if (!rev) + return -ENOMEM; + + rev->ns = aa_get_ns(inode->i_private); + if (!rev->ns) + rev->ns = aa_get_current_ns(); + file->private_data = rev; + + return 0; +} + +static __poll_t ns_revision_poll(struct file *file, poll_table *pt) +{ + struct aa_revision *rev = file->private_data; + __poll_t mask = 0; + + if (rev) { + mutex_lock_nested(&rev->ns->lock, rev->ns->level); + poll_wait(file, &rev->ns->wait, pt); + if (rev->last_read < rev->ns->revision) + mask |= EPOLLIN | EPOLLRDNORM; + mutex_unlock(&rev->ns->lock); + } + + return mask; +} + +void __aa_bump_ns_revision(struct aa_ns *ns) +{ + WRITE_ONCE(ns->revision, READ_ONCE(ns->revision) + 1); + wake_up_interruptible(&ns->wait); +} + +static const struct file_operations aa_fs_ns_revision_fops = { + .owner = THIS_MODULE, + .open = ns_revision_open, + .poll = ns_revision_poll, + .read = ns_revision_read, + .llseek = generic_file_llseek, + .release = ns_revision_release, +}; + +static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, + const char *match_str, size_t match_len) +{ + struct aa_ruleset *rules = list_first_entry(&profile->rules, + typeof(*rules), list); + struct aa_perms tmp = { }; + aa_state_t state = DFA_NOMATCH; + + if (profile_unconfined(profile)) + return; + if (rules->file.dfa && *match_str == AA_CLASS_FILE) { + state = aa_dfa_match_len(rules->file.dfa, + rules->file.start[AA_CLASS_FILE], + match_str + 1, match_len - 1); + if (state) { + struct path_cond cond = { }; + + tmp = *(aa_lookup_fperms(&(rules->file), state, &cond)); + } + } else if (rules->policy.dfa) { + if (!RULE_MEDIATES(rules, *match_str)) + return; /* no change to current perms */ + state = aa_dfa_match_len(rules->policy.dfa, + rules->policy.start[0], + match_str, match_len); + if (state) + tmp = *aa_lookup_perms(&rules->policy, state); + } + aa_apply_modes_to_perms(profile, &tmp); + aa_perms_accum_raw(perms, &tmp); +} + + +/** + * query_data - queries a policy and writes its data to buf + * @buf: the resulting data is stored here (NOT NULL) + * @buf_len: size of buf + * @query: query string used to retrieve data + * @query_len: size of query including second NUL byte + * + * The buffers pointed to by buf and query may overlap. The query buffer is + * parsed before buf is written to. + * + * The query should look like "