aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2015-09-04 18:44:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-04 19:54:41 -0400
commita068acf2ee77693e0bf39d6e07139ba704f461c3 (patch)
tree760636f774a9ad528168fa7ceaaf34529167b085
parent46359295a352e01a5a017297c70b7ee0c5da6de6 (diff)
fs: create and use seq_show_option for escaping
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> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/ceph/super.c2
-rw-r--r--fs/cifs/cifsfs.c6
-rw-r--r--fs/ext4/super.c4
-rw-r--r--fs/gfs2/super.c6
-rw-r--r--fs/hfs/super.c4
-rw-r--r--fs/hfsplus/options.c4
-rw-r--r--fs/hostfs/hostfs_kern.c2
-rw-r--r--fs/ocfs2/super.c4
-rw-r--r--fs/overlayfs/super.c6
-rw-r--r--fs/reiserfs/super.c8
-rw-r--r--fs/xfs/xfs_super.c4
-rw-r--r--include/linux/seq_file.h35
-rw-r--r--kernel/cgroup.c7
-rw-r--r--net/ceph/ceph_common.c7
-rw-r--r--security/selinux/hooks.c2
15 files changed, 71 insertions, 30 deletions
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index d1c833c321b9..7b6bfcbf801c 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -479,7 +479,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
479 if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT) 479 if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
480 seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes); 480 seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes);
481 if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) 481 if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
482 seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name); 482 seq_show_option(m, "snapdirname", fsopt->snapdir_name);
483 483
484 return 0; 484 return 0;
485} 485}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 0a9fb6b53126..6a1119e87fbb 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -394,17 +394,17 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
394 struct sockaddr *srcaddr; 394 struct sockaddr *srcaddr;
395 srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; 395 srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
396 396
397 seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string); 397 seq_show_option(s, "vers", tcon->ses->server->vals->version_string);
398 cifs_show_security(s, tcon->ses); 398 cifs_show_security(s, tcon->ses);
399 cifs_show_cache_flavor(s, cifs_sb); 399 cifs_show_cache_flavor(s, cifs_sb);
400 400
401 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) 401 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
402 seq_puts(s, ",multiuser"); 402 seq_puts(s, ",multiuser");
403 else if (tcon->ses->user_name) 403 else if (tcon->ses->user_name)
404 seq_printf(s, ",username=%s", tcon->ses->user_name); 404 seq_show_option(s, "username", tcon->ses->user_name);
405 405
406 if (tcon->ses->domainName) 406 if (tcon->ses->domainName)
407 seq_printf(s, ",domain=%s", tcon->ses->domainName); 407 seq_show_option(s, "domain", tcon->ses->domainName);
408 408
409 if (srcaddr->sa_family != AF_UNSPEC) { 409 if (srcaddr->sa_family != AF_UNSPEC) {
410 struct sockaddr_in *saddr4; 410 struct sockaddr_in *saddr4;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index ee3878262a49..a63c7b0a10cf 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1776,10 +1776,10 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
1776 } 1776 }
1777 1777
1778 if (sbi->s_qf_names[USRQUOTA]) 1778 if (sbi->s_qf_names[USRQUOTA])
1779 seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); 1779 seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]);
1780 1780
1781 if (sbi->s_qf_names[GRPQUOTA]) 1781 if (sbi->s_qf_names[GRPQUOTA])
1782 seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); 1782 seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]);
1783#endif 1783#endif
1784} 1784}
1785 1785
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 2982445947e1..894fb01a91da 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1334,11 +1334,11 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
1334 if (is_ancestor(root, sdp->sd_master_dir)) 1334 if (is_ancestor(root, sdp->sd_master_dir))
1335 seq_puts(s, ",meta"); 1335 seq_puts(s, ",meta");
1336 if (args->ar_lockproto[0]) 1336 if (args->ar_lockproto[0])
1337 seq_printf(s, ",lockproto=%s", args->ar_lockproto); 1337 seq_show_option(s, "lockproto", args->ar_lockproto);
1338 if (args->ar_locktable[0]) 1338 if (args->ar_locktable[0])
1339 seq_printf(s, ",locktable=%s", args->ar_locktable); 1339 seq_show_option(s, "locktable", args->ar_locktable);
1340 if (args->ar_hostdata[0]) 1340 if (args->ar_hostdata[0])
1341 seq_printf(s, ",hostdata=%s", args->ar_hostdata); 1341 seq_show_option(s, "hostdata", args->ar_hostdata);
1342 if (args->ar_spectator) 1342 if (args->ar_spectator)
1343 seq_puts(s, ",spectator"); 1343 seq_puts(s, ",spectator");
1344 if (args->ar_localflocks) 1344 if (args->ar_localflocks)
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 55c03b9e9070..4574fdd3d421 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -136,9 +136,9 @@ static int hfs_show_options(struct seq_file *seq, struct dentry *root)
136 struct hfs_sb_info *sbi = HFS_SB(root->d_sb); 136 struct hfs_sb_info *sbi = HFS_SB(root->d_sb);
137 137
138 if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f)) 138 if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f))
139 seq_printf(seq, ",creator=%.4s", (char *)&sbi->s_creator); 139 seq_show_option_n(seq, "creator", (char *)&sbi->s_creator, 4);
140 if (sbi->s_type != cpu_to_be32(0x3f3f3f3f)) 140 if (sbi->s_type != cpu_to_be32(0x3f3f3f3f))
141 seq_printf(seq, ",type=%.4s", (char *)&sbi->s_type); 141 seq_show_option_n(seq, "type", (char *)&sbi->s_type, 4);
142 seq_printf(seq, ",uid=%u,gid=%u", 142 seq_printf(seq, ",uid=%u,gid=%u",
143 from_kuid_munged(&init_user_ns, sbi->s_uid), 143 from_kuid_munged(&init_user_ns, sbi->s_uid),
144 from_kgid_munged(&init_user_ns, sbi->s_gid)); 144 from_kgid_munged(&init_user_ns, sbi->s_gid));
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index c90b72ee676d..bb806e58c977 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -218,9 +218,9 @@ int hfsplus_show_options(struct seq_file *seq, struct dentry *root)
218 struct hfsplus_sb_info *sbi = HFSPLUS_SB(root->d_sb); 218 struct hfsplus_sb_info *sbi = HFSPLUS_SB(root->d_sb);
219 219
220 if (sbi->creator != HFSPLUS_DEF_CR_TYPE) 220 if (sbi->creator != HFSPLUS_DEF_CR_TYPE)
221 seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); 221 seq_show_option_n(seq, "creator", (char *)&sbi->creator, 4);
222 if (sbi->type != HFSPLUS_DEF_CR_TYPE) 222 if (sbi->type != HFSPLUS_DEF_CR_TYPE)
223 seq_printf(seq, ",type=%.4s", (char *)&sbi->type); 223 seq_show_option_n(seq, "type", (char *)&sbi->type, 4);
224 seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, 224 seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask,
225 from_kuid_munged(&init_user_ns, sbi->uid), 225 from_kuid_munged(&init_user_ns, sbi->uid),
226 from_kgid_munged(&init_user_ns, sbi->gid)); 226 from_kgid_munged(&init_user_ns, sbi->gid));
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 059597b23f67..2ac99db3750e 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -260,7 +260,7 @@ static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
260 size_t offset = strlen(root_ino) + 1; 260 size_t offset = strlen(root_ino) + 1;
261 261
262 if (strlen(root_path) > offset) 262 if (strlen(root_path) > offset)
263 seq_printf(seq, ",%s", root_path + offset); 263 seq_show_option(seq, root_path + offset, NULL);
264 264
265 if (append) 265 if (append)
266 seq_puts(seq, ",append"); 266 seq_puts(seq, ",append");
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 3a9a1af39ad7..2de4c8a9340c 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1563,8 +1563,8 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
1563 seq_printf(s, ",localflocks,"); 1563 seq_printf(s, ",localflocks,");
1564 1564
1565 if (osb->osb_cluster_stack[0]) 1565 if (osb->osb_cluster_stack[0])
1566 seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN, 1566 seq_show_option_n(s, "cluster_stack", osb->osb_cluster_stack,
1567 osb->osb_cluster_stack); 1567 OCFS2_STACK_LABEL_LEN);
1568 if (opts & OCFS2_MOUNT_USRQUOTA) 1568 if (opts & OCFS2_MOUNT_USRQUOTA)
1569 seq_printf(s, ",usrquota"); 1569 seq_printf(s, ",usrquota");
1570 if (opts & OCFS2_MOUNT_GRPQUOTA) 1570 if (opts & OCFS2_MOUNT_GRPQUOTA)
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 7466ff339c66..79073d68b475 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -588,10 +588,10 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
588 struct super_block *sb = dentry->d_sb; 588 struct super_block *sb = dentry->d_sb;
589 struct ovl_fs *ufs = sb->s_fs_info; 589 struct ovl_fs *ufs = sb->s_fs_info;
590 590
591 seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); 591 seq_show_option(m, "lowerdir", ufs->config.lowerdir);
592 if (ufs->config.upperdir) { 592 if (ufs->config.upperdir) {
593 seq_printf(m, ",upperdir=%s", ufs->config.upperdir); 593 seq_show_option(m, "upperdir", ufs->config.upperdir);
594 seq_printf(m, ",workdir=%s", ufs->config.workdir); 594 seq_show_option(m, "workdir", ufs->config.workdir);
595 } 595 }
596 return 0; 596 return 0;
597} 597}
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 0e4cf728126f..4a62fe8cc3bf 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -714,18 +714,20 @@ static int reiserfs_show_options(struct seq_file *seq, struct dentry *root)
714 seq_puts(seq, ",acl"); 714 seq_puts(seq, ",acl");
715 715
716 if (REISERFS_SB(s)->s_jdev) 716 if (REISERFS_SB(s)->s_jdev)
717 seq_printf(seq, ",jdev=%s", REISERFS_SB(s)->s_jdev); 717 seq_show_option(seq, "jdev", REISERFS_SB(s)->s_jdev);
718 718
719 if (journal->j_max_commit_age != journal->j_default_max_commit_age) 719 if (journal->j_max_commit_age != journal->j_default_max_commit_age)
720 seq_printf(seq, ",commit=%d", journal->j_max_commit_age); 720 seq_printf(seq, ",commit=%d", journal->j_max_commit_age);
721 721
722#ifdef CONFIG_QUOTA 722#ifdef CONFIG_QUOTA
723 if (REISERFS_SB(s)->s_qf_names[USRQUOTA]) 723 if (REISERFS_SB(s)->s_qf_names[USRQUOTA])
724 seq_printf(seq, ",usrjquota=%s", REISERFS_SB(s)->s_qf_names[USRQUOTA]); 724 seq_show_option(seq, "usrjquota",
725 REISERFS_SB(s)->s_qf_names[USRQUOTA]);
725 else if (opts & (1 << REISERFS_USRQUOTA)) 726 else if (opts & (1 << REISERFS_USRQUOTA))
726 seq_puts(seq, ",usrquota"); 727 seq_puts(seq, ",usrquota");
727 if (REISERFS_SB(s)->s_qf_names[GRPQUOTA]) 728 if (REISERFS_SB(s)->s_qf_names[GRPQUOTA])
728 seq_printf(seq, ",grpjquota=%s", REISERFS_SB(s)->s_qf_names[GRPQUOTA]); 729 seq_show_option(seq, "grpjquota",
730 REISERFS_SB(s)->s_qf_names[GRPQUOTA]);
729 else if (opts & (1 << REISERFS_GRPQUOTA)) 731 else if (opts & (1 << REISERFS_GRPQUOTA))
730 seq_puts(seq, ",grpquota"); 732 seq_puts(seq, ",grpquota");
731 if (REISERFS_SB(s)->s_jquota_fmt) { 733 if (REISERFS_SB(s)->s_jquota_fmt) {
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 1fb16562c159..bbd9b1f10ffb 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -511,9 +511,9 @@ xfs_showargs(
511 seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10); 511 seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10);
512 512
513 if (mp->m_logname) 513 if (mp->m_logname)
514 seq_printf(m, "," MNTOPT_LOGDEV "=%s", mp->m_logname); 514 seq_show_option(m, MNTOPT_LOGDEV, mp->m_logname);
515 if (mp->m_rtname) 515 if (mp->m_rtname)
516 seq_printf(m, "," MNTOPT_RTDEV "=%s", mp->m_rtname); 516 seq_show_option(m, MNTOPT_RTDEV, mp->m_rtname);
517 517
518 if (mp->m_dalign > 0) 518 if (mp->m_dalign > 0)
519 seq_printf(m, "," MNTOPT_SUNIT "=%d", 519 seq_printf(m, "," MNTOPT_SUNIT "=%d",
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 912a7c482649..d4c7271382cb 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -149,6 +149,41 @@ static inline struct user_namespace *seq_user_ns(struct seq_file *seq)
149#endif 149#endif
150} 150}
151 151
152/**
153 * seq_show_options - display mount options with appropriate escapes.
154 * @m: the seq_file handle
155 * @name: the mount option name
156 * @value: the mount option name's value, can be NULL
157 */
158static inline void seq_show_option(struct seq_file *m, const char *name,
159 const char *value)
160{
161 seq_putc(m, ',');
162 seq_escape(m, name, ",= \t\n\\");
163 if (value) {
164 seq_putc(m, '=');
165 seq_escape(m, value, ", \t\n\\");
166 }
167}
168
169/**
170 * seq_show_option_n - display mount options with appropriate escapes
171 * where @value must be a specific length.
172 * @m: the seq_file handle
173 * @name: the mount option name
174 * @value: the mount option name's value, cannot be NULL
175 * @length: the length of @value to display
176 *
177 * This is a macro since this uses "length" to define the size of the
178 * stack buffer.
179 */
180#define seq_show_option_n(m, name, value, length) { \
181 char val_buf[length + 1]; \
182 strncpy(val_buf, value, length); \
183 val_buf[length] = '\0'; \
184 seq_show_option(m, name, val_buf); \
185}
186
152#define SEQ_START_TOKEN ((void *)1) 187#define SEQ_START_TOKEN ((void *)1)
153/* 188/*
154 * Helpers for iteration over list_head-s in seq_files 189 * Helpers for iteration over list_head-s in seq_files
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index f3f5cd5e2c0d..a8538e443784 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1342,7 +1342,7 @@ static int cgroup_show_options(struct seq_file *seq,
1342 if (root != &cgrp_dfl_root) 1342 if (root != &cgrp_dfl_root)
1343 for_each_subsys(ss, ssid) 1343 for_each_subsys(ss, ssid)
1344 if (root->subsys_mask & (1 << ssid)) 1344 if (root->subsys_mask & (1 << ssid))
1345 seq_printf(seq, ",%s", ss->legacy_name); 1345 seq_show_option(seq, ss->name, NULL);
1346 if (root->flags & CGRP_ROOT_NOPREFIX) 1346 if (root->flags & CGRP_ROOT_NOPREFIX)
1347 seq_puts(seq, ",noprefix"); 1347 seq_puts(seq, ",noprefix");
1348 if (root->flags & CGRP_ROOT_XATTR) 1348 if (root->flags & CGRP_ROOT_XATTR)
@@ -1350,13 +1350,14 @@ static int cgroup_show_options(struct seq_file *seq,
1350 1350
1351 spin_lock(&release_agent_path_lock); 1351 spin_lock(&release_agent_path_lock);
1352 if (strlen(root->release_agent_path)) 1352 if (strlen(root->release_agent_path))
1353 seq_printf(seq, ",release_agent=%s", root->release_agent_path); 1353 seq_show_option(seq, "release_agent",
1354 root->release_agent_path);
1354 spin_unlock(&release_agent_path_lock); 1355 spin_unlock(&release_agent_path_lock);
1355 1356
1356 if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags)) 1357 if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags))
1357 seq_puts(seq, ",clone_children"); 1358 seq_puts(seq, ",clone_children");
1358 if (strlen(root->name)) 1359 if (strlen(root->name))
1359 seq_printf(seq, ",name=%s", root->name); 1360 seq_show_option(seq, "name", root->name);
1360 return 0; 1361 return 0;
1361} 1362}
1362 1363
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index f30329f72641..69a4d30a9ccf 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -517,8 +517,11 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client)
517 struct ceph_options *opt = client->options; 517 struct ceph_options *opt = client->options;
518 size_t pos = m->count; 518 size_t pos = m->count;
519 519
520 if (opt->name) 520 if (opt->name) {
521 seq_printf(m, "name=%s,", opt->name); 521 seq_puts(m, "name=");
522 seq_escape(m, opt->name, ", \t\n\\");
523 seq_putc(m, ',');
524 }
522 if (opt->key) 525 if (opt->key)
523 seq_puts(m, "secret=<hidden>,"); 526 seq_puts(m, "secret=<hidden>,");
524 527
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 564079c5c49d..cdf4c589a391 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1100,7 +1100,7 @@ static void selinux_write_opts(struct seq_file *m,
1100 seq_puts(m, prefix); 1100 seq_puts(m, prefix);
1101 if (has_comma) 1101 if (has_comma)
1102 seq_putc(m, '\"'); 1102 seq_putc(m, '\"');
1103 seq_puts(m, opts->mnt_opts[i]); 1103 seq_escape(m, opts->mnt_opts[i], "\"\n\\");
1104 if (has_comma) 1104 if (has_comma)
1105 seq_putc(m, '\"'); 1105 seq_putc(m, '\"');
1106 } 1106 }