@@ -4694,78 +4694,15 @@ static struct vfsmount *lookup_mnt_in_ns(u64 id, struct mnt_namespace *ns)
46944694}
46954695
46964696struct kstatmount {
4697- struct statmount __user * const buf ;
4698- size_t const bufsize ;
4699- struct vfsmount * const mnt ;
4700- u64 const mask ;
4701- struct seq_file seq ;
4697+ struct statmount __user * buf ;
4698+ size_t bufsize ;
4699+ struct vfsmount * mnt ;
4700+ u64 mask ;
47024701 struct path root ;
47034702 struct statmount sm ;
4704- size_t pos ;
4705- int err ;
4703+ struct seq_file seq ;
47064704};
47074705
4708- typedef int (* statmount_func_t )(struct kstatmount * );
4709-
4710- static int statmount_string_seq (struct kstatmount * s , statmount_func_t func )
4711- {
4712- size_t rem = s -> bufsize - s -> pos - sizeof (s -> sm );
4713- struct seq_file * seq = & s -> seq ;
4714- int ret ;
4715-
4716- seq -> count = 0 ;
4717- seq -> size = min (seq -> size , rem );
4718- seq -> buf = kvmalloc (seq -> size , GFP_KERNEL_ACCOUNT );
4719- if (!seq -> buf )
4720- return - ENOMEM ;
4721-
4722- ret = func (s );
4723- if (ret )
4724- return ret ;
4725-
4726- if (seq_has_overflowed (seq )) {
4727- if (seq -> size == rem )
4728- return - EOVERFLOW ;
4729- seq -> size *= 2 ;
4730- if (seq -> size > MAX_RW_COUNT )
4731- return - ENOMEM ;
4732- kvfree (seq -> buf );
4733- return 0 ;
4734- }
4735-
4736- /* Done */
4737- return 1 ;
4738- }
4739-
4740- static void statmount_string (struct kstatmount * s , u64 mask , statmount_func_t func ,
4741- u32 * str )
4742- {
4743- int ret = s -> pos + sizeof (s -> sm ) >= s -> bufsize ? - EOVERFLOW : 0 ;
4744- struct statmount * sm = & s -> sm ;
4745- struct seq_file * seq = & s -> seq ;
4746-
4747- if (s -> err || !(s -> mask & mask ))
4748- return ;
4749-
4750- seq -> size = PAGE_SIZE ;
4751- while (!ret )
4752- ret = statmount_string_seq (s , func );
4753-
4754- if (ret < 0 ) {
4755- s -> err = ret ;
4756- } else {
4757- seq -> buf [seq -> count ++ ] = '\0' ;
4758- if (copy_to_user (s -> buf -> str + s -> pos , seq -> buf , seq -> count )) {
4759- s -> err = - EFAULT ;
4760- } else {
4761- * str = s -> pos ;
4762- s -> pos += seq -> count ;
4763- }
4764- }
4765- kvfree (seq -> buf );
4766- sm -> mask |= mask ;
4767- }
4768-
47694706static u64 mnt_to_attr_flags (struct vfsmount * mnt )
47704707{
47714708 unsigned int mnt_flags = READ_ONCE (mnt -> mnt_flags );
@@ -4848,41 +4785,109 @@ static void statmount_propagate_from(struct kstatmount *s)
48484785 s -> sm .propagate_from = get_dominating_id (m , & current -> fs -> root );
48494786}
48504787
4851- static int statmount_mnt_root (struct kstatmount * s )
4788+ static int statmount_mnt_root (struct kstatmount * s , struct seq_file * seq )
48524789{
4853- struct seq_file * seq = & s -> seq ;
4854- int err = show_path ( seq , s -> mnt -> mnt_root ) ;
4790+ int ret ;
4791+ size_t start = seq -> count ;
48554792
4856- if (!err && !seq_has_overflowed (seq )) {
4857- seq -> buf [seq -> count ] = '\0' ;
4858- seq -> count = string_unescape_inplace (seq -> buf , UNESCAPE_OCTAL );
4859- }
4860- return err ;
4793+ ret = show_path (seq , s -> mnt -> mnt_root );
4794+ if (ret )
4795+ return ret ;
4796+
4797+ if (unlikely (seq_has_overflowed (seq )))
4798+ return - EAGAIN ;
4799+
4800+ /*
4801+ * Unescape the result. It would be better if supplied string was not
4802+ * escaped in the first place, but that's a pretty invasive change.
4803+ */
4804+ seq -> buf [seq -> count ] = '\0' ;
4805+ seq -> count = start ;
4806+ seq_commit (seq , string_unescape_inplace (seq -> buf + start , UNESCAPE_OCTAL ));
4807+ return 0 ;
48614808}
48624809
4863- static int statmount_mnt_point (struct kstatmount * s )
4810+ static int statmount_mnt_point (struct kstatmount * s , struct seq_file * seq )
48644811{
48654812 struct vfsmount * mnt = s -> mnt ;
48664813 struct path mnt_path = { .dentry = mnt -> mnt_root , .mnt = mnt };
4867- int err = seq_path_root ( & s -> seq , & mnt_path , & s -> root , "" ) ;
4814+ int err ;
48684815
4816+ err = seq_path_root (seq , & mnt_path , & s -> root , "" );
48694817 return err == SEQ_SKIP ? 0 : err ;
48704818}
48714819
4872- static int statmount_fs_type (struct kstatmount * s )
4820+ static int statmount_fs_type (struct kstatmount * s , struct seq_file * seq )
48734821{
4874- struct seq_file * seq = & s -> seq ;
48754822 struct super_block * sb = s -> mnt -> mnt_sb ;
48764823
48774824 seq_puts (seq , sb -> s_type -> name );
48784825 return 0 ;
48794826}
48804827
4881- static int do_statmount (struct kstatmount * s )
4828+ static int statmount_string (struct kstatmount * s , u64 flag )
48824829{
4830+ int ret ;
4831+ size_t kbufsize ;
4832+ struct seq_file * seq = & s -> seq ;
48834833 struct statmount * sm = & s -> sm ;
4884- struct mount * m = real_mount (s -> mnt );
4834+
4835+ switch (flag ) {
4836+ case STATMOUNT_FS_TYPE :
4837+ sm -> fs_type = seq -> count ;
4838+ ret = statmount_fs_type (s , seq );
4839+ break ;
4840+ case STATMOUNT_MNT_ROOT :
4841+ sm -> mnt_root = seq -> count ;
4842+ ret = statmount_mnt_root (s , seq );
4843+ break ;
4844+ case STATMOUNT_MNT_POINT :
4845+ sm -> mnt_point = seq -> count ;
4846+ ret = statmount_mnt_point (s , seq );
4847+ break ;
4848+ default :
4849+ WARN_ON_ONCE (true);
4850+ return - EINVAL ;
4851+ }
4852+
4853+ if (unlikely (check_add_overflow (sizeof (* sm ), seq -> count , & kbufsize )))
4854+ return - EOVERFLOW ;
4855+ if (kbufsize >= s -> bufsize )
4856+ return - EOVERFLOW ;
4857+
4858+ /* signal a retry */
4859+ if (unlikely (seq_has_overflowed (seq )))
4860+ return - EAGAIN ;
4861+
4862+ if (ret )
4863+ return ret ;
4864+
4865+ seq -> buf [seq -> count ++ ] = '\0' ;
4866+ sm -> mask |= flag ;
4867+ return 0 ;
4868+ }
4869+
4870+ static int copy_statmount_to_user (struct kstatmount * s )
4871+ {
4872+ struct statmount * sm = & s -> sm ;
4873+ struct seq_file * seq = & s -> seq ;
4874+ char __user * str = ((char __user * )s -> buf ) + sizeof (* sm );
48854875 size_t copysize = min_t (size_t , s -> bufsize , sizeof (* sm ));
4876+
4877+ if (seq -> count && copy_to_user (str , seq -> buf , seq -> count ))
4878+ return - EFAULT ;
4879+
4880+ /* Return the number of bytes copied to the buffer */
4881+ sm -> size = copysize + seq -> count ;
4882+ if (copy_to_user (s -> buf , sm , copysize ))
4883+ return - EFAULT ;
4884+
4885+ return 0 ;
4886+ }
4887+
4888+ static int do_statmount (struct kstatmount * s )
4889+ {
4890+ struct mount * m = real_mount (s -> mnt );
48864891 int err ;
48874892
48884893 /*
@@ -4906,19 +4911,47 @@ static int do_statmount(struct kstatmount *s)
49064911 if (s -> mask & STATMOUNT_PROPAGATE_FROM )
49074912 statmount_propagate_from (s );
49084913
4909- statmount_string (s , STATMOUNT_FS_TYPE , statmount_fs_type , & sm -> fs_type );
4910- statmount_string (s , STATMOUNT_MNT_ROOT , statmount_mnt_root , & sm -> mnt_root );
4911- statmount_string (s , STATMOUNT_MNT_POINT , statmount_mnt_point , & sm -> mnt_point );
4914+ if (s -> mask & STATMOUNT_FS_TYPE )
4915+ err = statmount_string (s , STATMOUNT_FS_TYPE );
49124916
4913- if (s -> err )
4914- return s -> err ;
4917+ if (! err && s -> mask & STATMOUNT_MNT_ROOT )
4918+ err = statmount_string ( s , STATMOUNT_MNT_ROOT ) ;
49154919
4916- /* Return the number of bytes copied to the buffer */
4917- sm -> size = copysize + s -> pos ;
4920+ if (! err && s -> mask & STATMOUNT_MNT_POINT )
4921+ err = statmount_string ( s , STATMOUNT_MNT_POINT ) ;
49184922
4919- if (copy_to_user (s -> buf , sm , copysize ))
4923+ if (err )
4924+ return err ;
4925+
4926+ return 0 ;
4927+ }
4928+
4929+ static inline bool retry_statmount (const long ret , size_t * seq_size )
4930+ {
4931+ if (likely (ret != - EAGAIN ))
4932+ return false;
4933+ if (unlikely (check_mul_overflow (* seq_size , 2 , seq_size )))
4934+ return false;
4935+ if (unlikely (* seq_size > MAX_RW_COUNT ))
4936+ return false;
4937+ return true;
4938+ }
4939+
4940+ static int prepare_kstatmount (struct kstatmount * ks , struct mnt_id_req * kreq ,
4941+ struct statmount __user * buf , size_t bufsize ,
4942+ size_t seq_size )
4943+ {
4944+ if (!access_ok (buf , bufsize ))
49204945 return - EFAULT ;
49214946
4947+ memset (ks , 0 , sizeof (* ks ));
4948+ ks -> mask = kreq -> request_mask ;
4949+ ks -> buf = buf ;
4950+ ks -> bufsize = bufsize ;
4951+ ks -> seq .size = seq_size ;
4952+ ks -> seq .buf = kvmalloc (seq_size , GFP_KERNEL_ACCOUNT );
4953+ if (!ks -> seq .buf )
4954+ return - ENOMEM ;
49224955 return 0 ;
49234956}
49244957
@@ -4928,6 +4961,9 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
49284961{
49294962 struct vfsmount * mnt ;
49304963 struct mnt_id_req kreq ;
4964+ struct kstatmount ks ;
4965+ /* We currently support retrieval of 3 strings. */
4966+ size_t seq_size = 3 * PATH_MAX ;
49314967 int ret ;
49324968
49334969 if (flags )
@@ -4936,23 +4972,30 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
49364972 if (copy_from_user (& kreq , req , sizeof (kreq )))
49374973 return - EFAULT ;
49384974
4975+ retry :
4976+ ret = prepare_kstatmount (& ks , & kreq , buf , bufsize , seq_size );
4977+ if (ret )
4978+ return ret ;
4979+
49394980 down_read (& namespace_sem );
49404981 mnt = lookup_mnt_in_ns (kreq .mnt_id , current -> nsproxy -> mnt_ns );
4941- ret = - ENOENT ;
4942- if (mnt ) {
4943- struct kstatmount s = {
4944- .mask = kreq .request_mask ,
4945- .buf = buf ,
4946- .bufsize = bufsize ,
4947- .mnt = mnt ,
4948- };
4949-
4950- get_fs_root (current -> fs , & s .root );
4951- ret = do_statmount (& s );
4952- path_put (& s .root );
4982+ if (!mnt ) {
4983+ up_read (& namespace_sem );
4984+ kvfree (ks .seq .buf );
4985+ return - ENOENT ;
49534986 }
4987+
4988+ ks .mnt = mnt ;
4989+ get_fs_root (current -> fs , & ks .root );
4990+ ret = do_statmount (& ks );
4991+ path_put (& ks .root );
49544992 up_read (& namespace_sem );
49554993
4994+ if (!ret )
4995+ ret = copy_statmount_to_user (& ks );
4996+ kvfree (ks .seq .buf );
4997+ if (retry_statmount (ret , & seq_size ))
4998+ goto retry ;
49564999 return ret ;
49575000}
49585001
0 commit comments