compat.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. * linux/fs/compat.c
  3. *
  4. * Kernel compatibililty routines for e.g. 32 bit syscall support
  5. * on 64 bit kernels.
  6. *
  7. * Copyright (C) 2002 Stephen Rothwell, IBM Corporation
  8. * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
  9. * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
  10. * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
  11. * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License version 2 as
  15. * published by the Free Software Foundation.
  16. */
  17. #include <linux/stddef.h>
  18. #include <linux/kernel.h>
  19. #include <linux/linkage.h>
  20. #include <linux/compat.h>
  21. #include <linux/errno.h>
  22. #include <linux/time.h>
  23. #include <linux/cred.h>
  24. #include <linux/fs.h>
  25. #include <linux/fcntl.h>
  26. #include <linux/namei.h>
  27. #include <linux/file.h>
  28. #include <linux/fdtable.h>
  29. #include <linux/vfs.h>
  30. #include <linux/ioctl.h>
  31. #include <linux/init.h>
  32. #include <linux/ncp_mount.h>
  33. #include <linux/nfs4_mount.h>
  34. #include <linux/syscalls.h>
  35. #include <linux/ctype.h>
  36. #include <linux/dirent.h>
  37. #include <linux/fsnotify.h>
  38. #include <linux/highuid.h>
  39. #include <linux/personality.h>
  40. #include <linux/rwsem.h>
  41. #include <linux/tsacct_kern.h>
  42. #include <linux/security.h>
  43. #include <linux/highmem.h>
  44. #include <linux/signal.h>
  45. #include <linux/mm.h>
  46. #include <linux/fs_struct.h>
  47. #include <linux/slab.h>
  48. #include <linux/pagemap.h>
  49. #include <linux/aio.h>
  50. #include <linux/uaccess.h>
  51. #include <asm/mmu_context.h>
  52. #include <asm/ioctls.h>
  53. #include "internal.h"
  54. static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
  55. {
  56. struct compat_stat tmp;
  57. if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
  58. return -EOVERFLOW;
  59. memset(&tmp, 0, sizeof(tmp));
  60. tmp.st_dev = old_encode_dev(stat->dev);
  61. tmp.st_ino = stat->ino;
  62. if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  63. return -EOVERFLOW;
  64. tmp.st_mode = stat->mode;
  65. tmp.st_nlink = stat->nlink;
  66. if (tmp.st_nlink != stat->nlink)
  67. return -EOVERFLOW;
  68. SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
  69. SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
  70. tmp.st_rdev = old_encode_dev(stat->rdev);
  71. if ((u64) stat->size > MAX_NON_LFS)
  72. return -EOVERFLOW;
  73. tmp.st_size = stat->size;
  74. tmp.st_atime = stat->atime.tv_sec;
  75. tmp.st_atime_nsec = stat->atime.tv_nsec;
  76. tmp.st_mtime = stat->mtime.tv_sec;
  77. tmp.st_mtime_nsec = stat->mtime.tv_nsec;
  78. tmp.st_ctime = stat->ctime.tv_sec;
  79. tmp.st_ctime_nsec = stat->ctime.tv_nsec;
  80. tmp.st_blocks = stat->blocks;
  81. tmp.st_blksize = stat->blksize;
  82. return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  83. }
  84. COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename,
  85. struct compat_stat __user *, statbuf)
  86. {
  87. struct kstat stat;
  88. int error;
  89. error = vfs_stat(filename, &stat);
  90. if (error)
  91. return error;
  92. return cp_compat_stat(&stat, statbuf);
  93. }
  94. COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename,
  95. struct compat_stat __user *, statbuf)
  96. {
  97. struct kstat stat;
  98. int error;
  99. error = vfs_lstat(filename, &stat);
  100. if (error)
  101. return error;
  102. return cp_compat_stat(&stat, statbuf);
  103. }
  104. #ifndef __ARCH_WANT_STAT64
  105. COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd,
  106. const char __user *, filename,
  107. struct compat_stat __user *, statbuf, int, flag)
  108. {
  109. struct kstat stat;
  110. int error;
  111. error = vfs_fstatat(dfd, filename, &stat, flag);
  112. if (error)
  113. return error;
  114. return cp_compat_stat(&stat, statbuf);
  115. }
  116. #endif
  117. COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd,
  118. struct compat_stat __user *, statbuf)
  119. {
  120. struct kstat stat;
  121. int error = vfs_fstat(fd, &stat);
  122. if (!error)
  123. error = cp_compat_stat(&stat, statbuf);
  124. return error;
  125. }
  126. /* A write operation does a read from user space and vice versa */
  127. #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
  128. ssize_t compat_rw_copy_check_uvector(int type,
  129. const struct compat_iovec __user *uvector, unsigned long nr_segs,
  130. unsigned long fast_segs, struct iovec *fast_pointer,
  131. struct iovec **ret_pointer)
  132. {
  133. compat_ssize_t tot_len;
  134. struct iovec *iov = *ret_pointer = fast_pointer;
  135. ssize_t ret = 0;
  136. int seg;
  137. /*
  138. * SuS says "The readv() function *may* fail if the iovcnt argument
  139. * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
  140. * traditionally returned zero for zero segments, so...
  141. */
  142. if (nr_segs == 0)
  143. goto out;
  144. ret = -EINVAL;
  145. if (nr_segs > UIO_MAXIOV)
  146. goto out;
  147. if (nr_segs > fast_segs) {
  148. ret = -ENOMEM;
  149. iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
  150. if (iov == NULL)
  151. goto out;
  152. }
  153. *ret_pointer = iov;
  154. ret = -EFAULT;
  155. if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
  156. goto out;
  157. /*
  158. * Single unix specification:
  159. * We should -EINVAL if an element length is not >= 0 and fitting an
  160. * ssize_t.
  161. *
  162. * In Linux, the total length is limited to MAX_RW_COUNT, there is
  163. * no overflow possibility.
  164. */
  165. tot_len = 0;
  166. ret = -EINVAL;
  167. for (seg = 0; seg < nr_segs; seg++) {
  168. compat_uptr_t buf;
  169. compat_ssize_t len;
  170. if (__get_user(len, &uvector->iov_len) ||
  171. __get_user(buf, &uvector->iov_base)) {
  172. ret = -EFAULT;
  173. goto out;
  174. }
  175. if (len < 0) /* size_t not fitting in compat_ssize_t .. */
  176. goto out;
  177. if (type >= 0 &&
  178. !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
  179. ret = -EFAULT;
  180. goto out;
  181. }
  182. if (len > MAX_RW_COUNT - tot_len)
  183. len = MAX_RW_COUNT - tot_len;
  184. tot_len += len;
  185. iov->iov_base = compat_ptr(buf);
  186. iov->iov_len = (compat_size_t) len;
  187. uvector++;
  188. iov++;
  189. }
  190. ret = tot_len;
  191. out:
  192. return ret;
  193. }
  194. struct compat_ncp_mount_data {
  195. compat_int_t version;
  196. compat_uint_t ncp_fd;
  197. __compat_uid_t mounted_uid;
  198. compat_pid_t wdog_pid;
  199. unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
  200. compat_uint_t time_out;
  201. compat_uint_t retry_count;
  202. compat_uint_t flags;
  203. __compat_uid_t uid;
  204. __compat_gid_t gid;
  205. compat_mode_t file_mode;
  206. compat_mode_t dir_mode;
  207. };
  208. struct compat_ncp_mount_data_v4 {
  209. compat_int_t version;
  210. compat_ulong_t flags;
  211. compat_ulong_t mounted_uid;
  212. compat_long_t wdog_pid;
  213. compat_uint_t ncp_fd;
  214. compat_uint_t time_out;
  215. compat_uint_t retry_count;
  216. compat_ulong_t uid;
  217. compat_ulong_t gid;
  218. compat_ulong_t file_mode;
  219. compat_ulong_t dir_mode;
  220. };
  221. static void *do_ncp_super_data_conv(void *raw_data)
  222. {
  223. int version = *(unsigned int *)raw_data;
  224. if (version == 3) {
  225. struct compat_ncp_mount_data *c_n = raw_data;
  226. struct ncp_mount_data *n = raw_data;
  227. n->dir_mode = c_n->dir_mode;
  228. n->file_mode = c_n->file_mode;
  229. n->gid = c_n->gid;
  230. n->uid = c_n->uid;
  231. memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
  232. n->wdog_pid = c_n->wdog_pid;
  233. n->mounted_uid = c_n->mounted_uid;
  234. } else if (version == 4) {
  235. struct compat_ncp_mount_data_v4 *c_n = raw_data;
  236. struct ncp_mount_data_v4 *n = raw_data;
  237. n->dir_mode = c_n->dir_mode;
  238. n->file_mode = c_n->file_mode;
  239. n->gid = c_n->gid;
  240. n->uid = c_n->uid;
  241. n->retry_count = c_n->retry_count;
  242. n->time_out = c_n->time_out;
  243. n->ncp_fd = c_n->ncp_fd;
  244. n->wdog_pid = c_n->wdog_pid;
  245. n->mounted_uid = c_n->mounted_uid;
  246. n->flags = c_n->flags;
  247. } else if (version != 5) {
  248. return NULL;
  249. }
  250. return raw_data;
  251. }
  252. struct compat_nfs_string {
  253. compat_uint_t len;
  254. compat_uptr_t data;
  255. };
  256. static inline void compat_nfs_string(struct nfs_string *dst,
  257. struct compat_nfs_string *src)
  258. {
  259. dst->data = compat_ptr(src->data);
  260. dst->len = src->len;
  261. }
  262. struct compat_nfs4_mount_data_v1 {
  263. compat_int_t version;
  264. compat_int_t flags;
  265. compat_int_t rsize;
  266. compat_int_t wsize;
  267. compat_int_t timeo;
  268. compat_int_t retrans;
  269. compat_int_t acregmin;
  270. compat_int_t acregmax;
  271. compat_int_t acdirmin;
  272. compat_int_t acdirmax;
  273. struct compat_nfs_string client_addr;
  274. struct compat_nfs_string mnt_path;
  275. struct compat_nfs_string hostname;
  276. compat_uint_t host_addrlen;
  277. compat_uptr_t host_addr;
  278. compat_int_t proto;
  279. compat_int_t auth_flavourlen;
  280. compat_uptr_t auth_flavours;
  281. };
  282. static int do_nfs4_super_data_conv(void *raw_data)
  283. {
  284. int version = *(compat_uint_t *) raw_data;
  285. if (version == 1) {
  286. struct compat_nfs4_mount_data_v1 *raw = raw_data;
  287. struct nfs4_mount_data *real = raw_data;
  288. /* copy the fields backwards */
  289. real->auth_flavours = compat_ptr(raw->auth_flavours);
  290. real->auth_flavourlen = raw->auth_flavourlen;
  291. real->proto = raw->proto;
  292. real->host_addr = compat_ptr(raw->host_addr);
  293. real->host_addrlen = raw->host_addrlen;
  294. compat_nfs_string(&real->hostname, &raw->hostname);
  295. compat_nfs_string(&real->mnt_path, &raw->mnt_path);
  296. compat_nfs_string(&real->client_addr, &raw->client_addr);
  297. real->acdirmax = raw->acdirmax;
  298. real->acdirmin = raw->acdirmin;
  299. real->acregmax = raw->acregmax;
  300. real->acregmin = raw->acregmin;
  301. real->retrans = raw->retrans;
  302. real->timeo = raw->timeo;
  303. real->wsize = raw->wsize;
  304. real->rsize = raw->rsize;
  305. real->flags = raw->flags;
  306. real->version = raw->version;
  307. }
  308. return 0;
  309. }
  310. #define NCPFS_NAME "ncpfs"
  311. #define NFS4_NAME "nfs4"
  312. COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
  313. const char __user *, dir_name,
  314. const char __user *, type, compat_ulong_t, flags,
  315. const void __user *, data)
  316. {
  317. char *kernel_type;
  318. void *options;
  319. char *kernel_dev;
  320. int retval;
  321. kernel_type = copy_mount_string(type);
  322. retval = PTR_ERR(kernel_type);
  323. if (IS_ERR(kernel_type))
  324. goto out;
  325. kernel_dev = copy_mount_string(dev_name);
  326. retval = PTR_ERR(kernel_dev);
  327. if (IS_ERR(kernel_dev))
  328. goto out1;
  329. options = copy_mount_options(data);
  330. retval = PTR_ERR(options);
  331. if (IS_ERR(options))
  332. goto out2;
  333. if (kernel_type && options) {
  334. if (!strcmp(kernel_type, NCPFS_NAME)) {
  335. do_ncp_super_data_conv(options);
  336. } else if (!strcmp(kernel_type, NFS4_NAME)) {
  337. retval = -EINVAL;
  338. if (do_nfs4_super_data_conv(options))
  339. goto out3;
  340. }
  341. }
  342. retval = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
  343. out3:
  344. kfree(options);
  345. out2:
  346. kfree(kernel_dev);
  347. out1:
  348. kfree(kernel_type);
  349. out:
  350. return retval;
  351. }
  352. /*
  353. * Exactly like fs/open.c:sys_open(), except that it doesn't set the
  354. * O_LARGEFILE flag.
  355. */
  356. COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
  357. {
  358. return do_sys_open(AT_FDCWD, filename, flags, mode);
  359. }
  360. /*
  361. * Exactly like fs/open.c:sys_openat(), except that it doesn't set the
  362. * O_LARGEFILE flag.
  363. */
  364. COMPAT_SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, umode_t, mode)
  365. {
  366. return do_sys_open(dfd, filename, flags, mode);
  367. }
  368. #ifdef CONFIG_FHANDLE
  369. /*
  370. * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
  371. * doesn't set the O_LARGEFILE flag.
  372. */
  373. COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
  374. struct file_handle __user *, handle, int, flags)
  375. {
  376. return do_handle_open(mountdirfd, handle, flags);
  377. }
  378. #endif