--- /dev/null
+From 5d0ddfebb93069061880fc57ee4ba7246bd1e1ee Mon Sep 17 00:00:00 2001
+From: Jiang Liu <jiang.liu@linux.intel.com>
+Date: Fri, 21 Aug 2015 15:36:23 +0800
+Subject: ACPI, PCI: Penalize legacy IRQ used by ACPI SCI
+
+From: Jiang Liu <jiang.liu@linux.intel.com>
+
+commit 5d0ddfebb93069061880fc57ee4ba7246bd1e1ee upstream.
+
+Nick Meier reported a regression with HyperV that "
+ After rebooting the VM, the following messages are logged in syslog
+ when trying to load the tulip driver:
+ tulip: Linux Tulip drivers version 1.1.15 (Feb 27, 2007)
+ tulip: 0000:00:0a.0: PCI INT A: failed to register GSI
+ tulip: Cannot enable tulip board #0, aborting
+ tulip: probe of 0000:00:0a.0 failed with error -16
+ Errors occur in 3.19.0 kernel
+ Works in 3.17 kernel.
+"
+
+According to the ACPI dump file posted by Nick at
+https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1440072
+
+The ACPI MADT table includes an interrupt source overridden entry for
+ACPI SCI:
+[236h 0566 1] Subtable Type : 02 <Interrupt Source Override>
+[237h 0567 1] Length : 0A
+[238h 0568 1] Bus : 00
+[239h 0569 1] Source : 09
+[23Ah 0570 4] Interrupt : 00000009
+[23Eh 0574 2] Flags (decoded below) : 000D
+ Polarity : 1
+ Trigger Mode : 3
+
+And in DSDT table, we have _PRT method to define PCI interrupts, which
+eventually goes to:
+ Name (PRSA, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared, )
+ {3,4,5,7,9,10,11,12,14,15}
+ })
+ Name (PRSB, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared, )
+ {3,4,5,7,9,10,11,12,14,15}
+ })
+ Name (PRSC, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared, )
+ {3,4,5,7,9,10,11,12,14,15}
+ })
+ Name (PRSD, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared, )
+ {3,4,5,7,9,10,11,12,14,15}
+ })
+
+According to the MADT and DSDT tables, IRQ 9 may be used for:
+ 1) ACPI SCI in level, high mode
+ 2) PCI legacy IRQ in level, low mode
+So there's a conflict in polarity setting for IRQ 9.
+
+Prior to commit cd68f6bd53cf ("x86, irq, acpi: Get rid of special
+handling of GSI for ACPI SCI"), ACPI SCI is handled specially and
+there's no check for conflicts between ACPI SCI and PCI legagy IRQ.
+And it seems that the HyperV hypervisor doesn't make use of the
+polarity configuration in IOAPIC entry, so it just works.
+
+Commit cd68f6bd53cf gets rid of the specially handling of ACPI SCI,
+and then the pin attribute checking code discloses the conflicts
+between ACPI SCI and PCI legacy IRQ on HyperV virtual machine,
+and rejects the request to assign IRQ9 to PCI devices.
+
+So penalize legacy IRQ used by ACPI SCI and mark it unusable if ACPI
+SCI attributes conflict with PCI IRQ attributes.
+
+Please refer to following links for more information:
+https://bugzilla.kernel.org/show_bug.cgi?id=101301
+https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1440072
+
+Fixes: cd68f6bd53cf ("x86, irq, acpi: Get rid of special handling of GSI for ACPI SCI")
+Reported-and-tested-by: Nick Meier <nmeier@microsoft.com>
+Acked-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/acpi/boot.c | 1 +
+ drivers/acpi/pci_link.c | 16 ++++++++++++++++
+ include/linux/acpi.h | 2 +-
+ 3 files changed, 18 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/acpi/boot.c
++++ b/arch/x86/kernel/acpi/boot.c
+@@ -489,6 +489,7 @@ static void __init acpi_sci_ioapic_setup
+ polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
+
+ mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
++ acpi_penalize_sci_irq(bus_irq, trigger, polarity);
+
+ /*
+ * stash over-ride to indicate we've been here
+--- a/drivers/acpi/pci_link.c
++++ b/drivers/acpi/pci_link.c
+@@ -826,6 +826,22 @@ void acpi_penalize_isa_irq(int irq, int
+ }
+
+ /*
++ * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict with
++ * PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be use for
++ * PCI IRQs.
++ */
++void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
++{
++ if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
++ if (trigger != ACPI_MADT_TRIGGER_LEVEL ||
++ polarity != ACPI_MADT_POLARITY_ACTIVE_LOW)
++ acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_ALWAYS;
++ else
++ acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
++ }
++}
++
++/*
+ * Over-ride default table to reserve additional IRQs for use by ISA
+ * e.g. acpi_irq_isa=5
+ * Useful for telling ACPI how not to interfere with your ISA sound card.
+--- a/include/linux/acpi.h
++++ b/include/linux/acpi.h
+@@ -198,7 +198,7 @@ struct pci_dev;
+
+ int acpi_pci_irq_enable (struct pci_dev *dev);
+ void acpi_penalize_isa_irq(int irq, int active);
+-
++void acpi_penalize_sci_irq(int irq, int trigger, int polarity);
+ void acpi_pci_irq_disable (struct pci_dev *dev);
+
+ extern int ec_read(u8 addr, u8 *val);
--- /dev/null
+From a068acf2ee77693e0bf39d6e07139ba704f461c3 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Fri, 4 Sep 2015 15:44:57 -0700
+Subject: fs: create and use seq_show_option for escaping
+
+From: Kees Cook <keescook@chromium.org>
+
+commit a068acf2ee77693e0bf39d6e07139ba704f461c3 upstream.
+
+Many file systems that implement the show_options hook fail to correctly
+escape their output which could lead to unescaped characters (e.g. new
+lines) leaking into /proc/mounts and /proc/[pid]/mountinfo files. This
+could lead to confusion, spoofed entries (resulting in things like
+systemd issuing false d-bus "mount" notifications), and who knows what
+else. This looks like it would only be the root user stepping on
+themselves, but it's possible weird things could happen in containers or
+in other situations with delegated mount privileges.
+
+Here's an example using overlay with setuid fusermount trusting the
+contents of /proc/mounts (via the /etc/mtab symlink). Imagine the use
+of "sudo" is something more sneaky:
+
+ $ BASE="ovl"
+ $ MNT="$BASE/mnt"
+ $ LOW="$BASE/lower"
+ $ UP="$BASE/upper"
+ $ WORK="$BASE/work/ 0 0
+ none /proc fuse.pwn user_id=1000"
+ $ mkdir -p "$LOW" "$UP" "$WORK"
+ $ sudo mount -t overlay -o "lowerdir=$LOW,upperdir=$UP,workdir=$WORK" none /mnt
+ $ cat /proc/mounts
+ none /root/ovl/mnt overlay rw,relatime,lowerdir=ovl/lower,upperdir=ovl/upper,workdir=ovl/work/ 0 0
+ none /proc fuse.pwn user_id=1000 0 0
+ $ fusermount -u /proc
+ $ cat /proc/mounts
+ cat: /proc/mounts: No such file or directory
+
+This fixes the problem by adding new seq_show_option and
+seq_show_option_n helpers, and updating the vulnerable show_option
+handlers to use them as needed. Some, like SELinux, need to be open
+coded due to unusual existing escape mechanisms.
+
+[akpm@linux-foundation.org: add lost chunk, per Kees]
+[keescook@chromium.org: seq_show_option should be using const parameters]
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
+Acked-by: Jan Kara <jack@suse.com>
+Acked-by: Paul Moore <paul@paul-moore.com>
+Cc: J. R. Okajima <hooanon05g@gmail.com>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ceph/super.c | 2 +-
+ fs/cifs/cifsfs.c | 6 +++---
+ fs/ext4/super.c | 4 ++--
+ fs/gfs2/super.c | 6 +++---
+ fs/hfs/super.c | 4 ++--
+ fs/hfsplus/options.c | 4 ++--
+ fs/hostfs/hostfs_kern.c | 2 +-
+ fs/ocfs2/super.c | 4 ++--
+ fs/overlayfs/super.c | 6 +++---
+ fs/reiserfs/super.c | 8 +++++---
+ fs/xfs/xfs_super.c | 4 ++--
+ include/linux/seq_file.h | 35 +++++++++++++++++++++++++++++++++++
+ kernel/cgroup.c | 7 ++++---
+ net/ceph/ceph_common.c | 7 +++++--
+ security/selinux/hooks.c | 2 +-
+ 15 files changed, 71 insertions(+), 30 deletions(-)
+
+--- a/fs/ceph/super.c
++++ b/fs/ceph/super.c
+@@ -466,7 +466,7 @@ static int ceph_show_options(struct seq_
+ if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
+ seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes);
+ if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
+- seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name);
++ seq_show_option(m, "snapdirname", fsopt->snapdir_name);
+
+ return 0;
+ }
+--- a/fs/cifs/cifsfs.c
++++ b/fs/cifs/cifsfs.c
+@@ -394,17 +394,17 @@ cifs_show_options(struct seq_file *s, st
+ struct sockaddr *srcaddr;
+ srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
+
+- seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string);
++ seq_show_option(s, "vers", tcon->ses->server->vals->version_string);
+ cifs_show_security(s, tcon->ses);
+ cifs_show_cache_flavor(s, cifs_sb);
+
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
+ seq_puts(s, ",multiuser");
+ else if (tcon->ses->user_name)
+- seq_printf(s, ",username=%s", tcon->ses->user_name);
++ seq_show_option(s, "username", tcon->ses->user_name);
+
+ if (tcon->ses->domainName)
+- seq_printf(s, ",domain=%s", tcon->ses->domainName);
++ seq_show_option(s, "domain", tcon->ses->domainName);
+
+ if (srcaddr->sa_family != AF_UNSPEC) {
+ struct sockaddr_in *saddr4;
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1738,10 +1738,10 @@ static inline void ext4_show_quota_optio
+ }
+
+ if (sbi->s_qf_names[USRQUOTA])
+- seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
++ seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]);
+
+ if (sbi->s_qf_names[GRPQUOTA])
+- seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
++ seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]);
+ #endif
+ }
+
+--- a/fs/gfs2/super.c
++++ b/fs/gfs2/super.c
+@@ -1334,11 +1334,11 @@ static int gfs2_show_options(struct seq_
+ if (is_ancestor(root, sdp->sd_master_dir))
+ seq_puts(s, ",meta");
+ if (args->ar_lockproto[0])
+- seq_printf(s, ",lockproto=%s", args->ar_lockproto);
++ seq_show_option(s, "lockproto", args->ar_lockproto);
+ if (args->ar_locktable[0])
+- seq_printf(s, ",locktable=%s", args->ar_locktable);
++ seq_show_option(s, "locktable", args->ar_locktable);
+ if (args->ar_hostdata[0])
+- seq_printf(s, ",hostdata=%s", args->ar_hostdata);
++ seq_show_option(s, "hostdata", args->ar_hostdata);
+ if (args->ar_spectator)
+ seq_puts(s, ",spectator");
+ if (args->ar_localflocks)
+--- a/fs/hfs/super.c
++++ b/fs/hfs/super.c
+@@ -135,9 +135,9 @@ static int hfs_show_options(struct seq_f
+ struct hfs_sb_info *sbi = HFS_SB(root->d_sb);
+
+ if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f))
+- seq_printf(seq, ",creator=%.4s", (char *)&sbi->s_creator);
++ seq_show_option_n(seq, "creator", (char *)&sbi->s_creator, 4);
+ if (sbi->s_type != cpu_to_be32(0x3f3f3f3f))
+- seq_printf(seq, ",type=%.4s", (char *)&sbi->s_type);
++ seq_show_option_n(seq, "type", (char *)&sbi->s_type, 4);
+ seq_printf(seq, ",uid=%u,gid=%u",
+ from_kuid_munged(&init_user_ns, sbi->s_uid),
+ from_kgid_munged(&init_user_ns, sbi->s_gid));
+--- a/fs/hfsplus/options.c
++++ b/fs/hfsplus/options.c
+@@ -218,9 +218,9 @@ int hfsplus_show_options(struct seq_file
+ struct hfsplus_sb_info *sbi = HFSPLUS_SB(root->d_sb);
+
+ if (sbi->creator != HFSPLUS_DEF_CR_TYPE)
+- seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
++ seq_show_option_n(seq, "creator", (char *)&sbi->creator, 4);
+ if (sbi->type != HFSPLUS_DEF_CR_TYPE)
+- seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
++ seq_show_option_n(seq, "type", (char *)&sbi->type, 4);
+ seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask,
+ from_kuid_munged(&init_user_ns, sbi->uid),
+ from_kgid_munged(&init_user_ns, sbi->gid));
+--- a/fs/hostfs/hostfs_kern.c
++++ b/fs/hostfs/hostfs_kern.c
+@@ -260,7 +260,7 @@ static int hostfs_show_options(struct se
+ size_t offset = strlen(root_ino) + 1;
+
+ if (strlen(root_path) > offset)
+- seq_printf(seq, ",%s", root_path + offset);
++ seq_show_option(seq, root_path + offset, NULL);
+
+ if (append)
+ seq_puts(seq, ",append");
+--- a/fs/ocfs2/super.c
++++ b/fs/ocfs2/super.c
+@@ -1550,8 +1550,8 @@ static int ocfs2_show_options(struct seq
+ seq_printf(s, ",localflocks,");
+
+ if (osb->osb_cluster_stack[0])
+- seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN,
+- osb->osb_cluster_stack);
++ seq_show_option_n(s, "cluster_stack", osb->osb_cluster_stack,
++ OCFS2_STACK_LABEL_LEN);
+ if (opts & OCFS2_MOUNT_USRQUOTA)
+ seq_printf(s, ",usrquota");
+ if (opts & OCFS2_MOUNT_GRPQUOTA)
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -517,10 +517,10 @@ static int ovl_show_options(struct seq_f
+ struct super_block *sb = dentry->d_sb;
+ struct ovl_fs *ufs = sb->s_fs_info;
+
+- seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir);
++ seq_show_option(m, "lowerdir", ufs->config.lowerdir);
+ if (ufs->config.upperdir) {
+- seq_printf(m, ",upperdir=%s", ufs->config.upperdir);
+- seq_printf(m, ",workdir=%s", ufs->config.workdir);
++ seq_show_option(m, "upperdir", ufs->config.upperdir);
++ seq_show_option(m, "workdir", ufs->config.workdir);
+ }
+ return 0;
+ }
+--- a/fs/reiserfs/super.c
++++ b/fs/reiserfs/super.c
+@@ -714,18 +714,20 @@ static int reiserfs_show_options(struct
+ seq_puts(seq, ",acl");
+
+ if (REISERFS_SB(s)->s_jdev)
+- seq_printf(seq, ",jdev=%s", REISERFS_SB(s)->s_jdev);
++ seq_show_option(seq, "jdev", REISERFS_SB(s)->s_jdev);
+
+ if (journal->j_max_commit_age != journal->j_default_max_commit_age)
+ seq_printf(seq, ",commit=%d", journal->j_max_commit_age);
+
+ #ifdef CONFIG_QUOTA
+ if (REISERFS_SB(s)->s_qf_names[USRQUOTA])
+- seq_printf(seq, ",usrjquota=%s", REISERFS_SB(s)->s_qf_names[USRQUOTA]);
++ seq_show_option(seq, "usrjquota",
++ REISERFS_SB(s)->s_qf_names[USRQUOTA]);
+ else if (opts & (1 << REISERFS_USRQUOTA))
+ seq_puts(seq, ",usrquota");
+ if (REISERFS_SB(s)->s_qf_names[GRPQUOTA])
+- seq_printf(seq, ",grpjquota=%s", REISERFS_SB(s)->s_qf_names[GRPQUOTA]);
++ seq_show_option(seq, "grpjquota",
++ REISERFS_SB(s)->s_qf_names[GRPQUOTA]);
+ else if (opts & (1 << REISERFS_GRPQUOTA))
+ seq_puts(seq, ",grpquota");
+ if (REISERFS_SB(s)->s_jquota_fmt) {
+--- a/fs/xfs/xfs_super.c
++++ b/fs/xfs/xfs_super.c
+@@ -504,9 +504,9 @@ xfs_showargs(
+ seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10);
+
+ if (mp->m_logname)
+- seq_printf(m, "," MNTOPT_LOGDEV "=%s", mp->m_logname);
++ seq_show_option(m, MNTOPT_LOGDEV, mp->m_logname);
+ if (mp->m_rtname)
+- seq_printf(m, "," MNTOPT_RTDEV "=%s", mp->m_rtname);
++ seq_show_option(m, MNTOPT_RTDEV, mp->m_rtname);
+
+ if (mp->m_dalign > 0)
+ seq_printf(m, "," MNTOPT_SUNIT "=%d",
+--- a/include/linux/seq_file.h
++++ b/include/linux/seq_file.h
+@@ -148,6 +148,41 @@ static inline struct user_namespace *seq
+ #endif
+ }
+
++/**
++ * seq_show_options - display mount options with appropriate escapes.
++ * @m: the seq_file handle
++ * @name: the mount option name
++ * @value: the mount option name's value, can be NULL
++ */
++static inline void seq_show_option(struct seq_file *m, const char *name,
++ const char *value)
++{
++ seq_putc(m, ',');
++ seq_escape(m, name, ",= \t\n\\");
++ if (value) {
++ seq_putc(m, '=');
++ seq_escape(m, value, ", \t\n\\");
++ }
++}
++
++/**
++ * seq_show_option_n - display mount options with appropriate escapes
++ * where @value must be a specific length.
++ * @m: the seq_file handle
++ * @name: the mount option name
++ * @value: the mount option name's value, cannot be NULL
++ * @length: the length of @value to display
++ *
++ * This is a macro since this uses "length" to define the size of the
++ * stack buffer.
++ */
++#define seq_show_option_n(m, name, value, length) { \
++ char val_buf[length + 1]; \
++ strncpy(val_buf, value, length); \
++ val_buf[length] = '\0'; \
++ seq_show_option(m, name, val_buf); \
++}
++
+ #define SEQ_START_TOKEN ((void *)1)
+ /*
+ * Helpers for iteration over list_head-s in seq_files
+--- a/kernel/cgroup.c
++++ b/kernel/cgroup.c
+@@ -1319,7 +1319,7 @@ static int cgroup_show_options(struct se
+
+ for_each_subsys(ss, ssid)
+ if (root->subsys_mask & (1 << ssid))
+- seq_printf(seq, ",%s", ss->name);
++ seq_show_option(seq, ss->name, NULL);
+ if (root->flags & CGRP_ROOT_NOPREFIX)
+ seq_puts(seq, ",noprefix");
+ if (root->flags & CGRP_ROOT_XATTR)
+@@ -1327,13 +1327,14 @@ static int cgroup_show_options(struct se
+
+ spin_lock(&release_agent_path_lock);
+ if (strlen(root->release_agent_path))
+- seq_printf(seq, ",release_agent=%s", root->release_agent_path);
++ seq_show_option(seq, "release_agent",
++ root->release_agent_path);
+ spin_unlock(&release_agent_path_lock);
+
+ if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags))
+ seq_puts(seq, ",clone_children");
+ if (strlen(root->name))
+- seq_printf(seq, ",name=%s", root->name);
++ seq_show_option(seq, "name", root->name);
+ return 0;
+ }
+
+--- a/net/ceph/ceph_common.c
++++ b/net/ceph/ceph_common.c
+@@ -495,8 +495,11 @@ int ceph_print_client_options(struct seq
+ struct ceph_options *opt = client->options;
+ size_t pos = m->count;
+
+- if (opt->name)
+- seq_printf(m, "name=%s,", opt->name);
++ if (opt->name) {
++ seq_puts(m, "name=");
++ seq_escape(m, opt->name, ", \t\n\\");
++ seq_putc(m, ',');
++ }
+ if (opt->key)
+ seq_puts(m, "secret=<hidden>,");
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -1095,7 +1095,7 @@ static void selinux_write_opts(struct se
+ seq_puts(m, prefix);
+ if (has_comma)
+ seq_putc(m, '\"');
+- seq_puts(m, opts->mnt_opts[i]);
++ seq_escape(m, opts->mnt_opts[i], "\"\n\\");
+ if (has_comma)
+ seq_putc(m, '\"');
+ }