1
0

051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. From 3fe6e52f062643676eb4518d68cee3bc1272091b Mon Sep 17 00:00:00 2001
  2. From: Antonio Murdaca <amurdaca@redhat.com>
  3. Date: Thu, 7 Apr 2016 15:48:25 +0200
  4. Subject: [PATCH] ovl: override creds with the ones from the superblock mounter
  5. In user namespace the whiteout creation fails with -EPERM because the
  6. current process isn't capable(CAP_SYS_ADMIN) when setting xattr.
  7. A simple reproducer:
  8. $ mkdir upper lower work merged lower/dir
  9. $ sudo mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged
  10. $ unshare -m -p -f -U -r bash
  11. Now as root in the user namespace:
  12. \# touch merged/dir/{1,2,3} # this will force a copy up of lower/dir
  13. \# rm -fR merged/*
  14. This ends up failing with -EPERM after the files in dir has been
  15. correctly deleted:
  16. unlinkat(4, "2", 0) = 0
  17. unlinkat(4, "1", 0) = 0
  18. unlinkat(4, "3", 0) = 0
  19. close(4) = 0
  20. unlinkat(AT_FDCWD, "merged/dir", AT_REMOVEDIR) = -1 EPERM (Operation not
  21. permitted)
  22. Interestingly, if you don't place files in merged/dir you can remove it,
  23. meaning if upper/dir does not exist, creating the char device file works
  24. properly in that same location.
  25. This patch uses ovl_sb_creator_cred() to get the cred struct from the
  26. superblock mounter and override the old cred with these new ones so that
  27. the whiteout creation is possible because overlay is wrong in assuming that
  28. the creds it will get with prepare_creds will be in the initial user
  29. namespace. The old cap_raise game is removed in favor of just overriding
  30. the old cred struct.
  31. This patch also drops from ovl_copy_up_one() the following two lines:
  32. override_cred->fsuid = stat->uid;
  33. override_cred->fsgid = stat->gid;
  34. This is because the correct uid and gid are taken directly with the stat
  35. struct and correctly set with ovl_set_attr().
  36. Signed-off-by: Antonio Murdaca <runcom@redhat.com>
  37. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  38. ---
  39. fs/overlayfs/copy_up.c | 26 +------------------
  40. fs/overlayfs/dir.c | 67 ++++--------------------------------------------
  41. fs/overlayfs/overlayfs.h | 1 +
  42. fs/overlayfs/readdir.c | 14 +++-------
  43. fs/overlayfs/super.c | 18 ++++++++++++-
  44. 5 files changed, 27 insertions(+), 99 deletions(-)
  45. --- a/fs/overlayfs/copy_up.c
  46. +++ b/fs/overlayfs/copy_up.c
  47. @@ -317,7 +317,6 @@ int ovl_copy_up_one(struct dentry *paren
  48. struct dentry *upperdir;
  49. struct dentry *upperdentry;
  50. const struct cred *old_cred;
  51. - struct cred *override_cred;
  52. char *link = NULL;
  53. if (WARN_ON(!workdir))
  54. @@ -336,28 +335,7 @@ int ovl_copy_up_one(struct dentry *paren
  55. return PTR_ERR(link);
  56. }
  57. - err = -ENOMEM;
  58. - override_cred = prepare_creds();
  59. - if (!override_cred)
  60. - goto out_free_link;
  61. -
  62. - override_cred->fsuid = stat->uid;
  63. - override_cred->fsgid = stat->gid;
  64. - /*
  65. - * CAP_SYS_ADMIN for copying up extended attributes
  66. - * CAP_DAC_OVERRIDE for create
  67. - * CAP_FOWNER for chmod, timestamp update
  68. - * CAP_FSETID for chmod
  69. - * CAP_CHOWN for chown
  70. - * CAP_MKNOD for mknod
  71. - */
  72. - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
  73. - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
  74. - cap_raise(override_cred->cap_effective, CAP_FOWNER);
  75. - cap_raise(override_cred->cap_effective, CAP_FSETID);
  76. - cap_raise(override_cred->cap_effective, CAP_CHOWN);
  77. - cap_raise(override_cred->cap_effective, CAP_MKNOD);
  78. - old_cred = override_creds(override_cred);
  79. + old_cred = ovl_override_creds(dentry->d_sb);
  80. err = -EIO;
  81. if (lock_rename(workdir, upperdir) != NULL) {
  82. @@ -380,9 +358,7 @@ int ovl_copy_up_one(struct dentry *paren
  83. out_unlock:
  84. unlock_rename(workdir, upperdir);
  85. revert_creds(old_cred);
  86. - put_cred(override_cred);
  87. -out_free_link:
  88. if (link)
  89. free_page((unsigned long) link);
  90. --- a/fs/overlayfs/dir.c
  91. +++ b/fs/overlayfs/dir.c
  92. @@ -408,28 +408,13 @@ static int ovl_create_or_link(struct den
  93. err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
  94. } else {
  95. const struct cred *old_cred;
  96. - struct cred *override_cred;
  97. - err = -ENOMEM;
  98. - override_cred = prepare_creds();
  99. - if (!override_cred)
  100. - goto out_iput;
  101. -
  102. - /*
  103. - * CAP_SYS_ADMIN for setting opaque xattr
  104. - * CAP_DAC_OVERRIDE for create in workdir, rename
  105. - * CAP_FOWNER for removing whiteout from sticky dir
  106. - */
  107. - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
  108. - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
  109. - cap_raise(override_cred->cap_effective, CAP_FOWNER);
  110. - old_cred = override_creds(override_cred);
  111. + old_cred = ovl_override_creds(dentry->d_sb);
  112. err = ovl_create_over_whiteout(dentry, inode, &stat, link,
  113. hardlink);
  114. revert_creds(old_cred);
  115. - put_cred(override_cred);
  116. }
  117. if (!err)
  118. @@ -659,32 +644,11 @@ static int ovl_do_remove(struct dentry *
  119. if (OVL_TYPE_PURE_UPPER(type)) {
  120. err = ovl_remove_upper(dentry, is_dir);
  121. } else {
  122. - const struct cred *old_cred;
  123. - struct cred *override_cred;
  124. -
  125. - err = -ENOMEM;
  126. - override_cred = prepare_creds();
  127. - if (!override_cred)
  128. - goto out_drop_write;
  129. -
  130. - /*
  131. - * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
  132. - * CAP_DAC_OVERRIDE for create in workdir, rename
  133. - * CAP_FOWNER for removing whiteout from sticky dir
  134. - * CAP_FSETID for chmod of opaque dir
  135. - * CAP_CHOWN for chown of opaque dir
  136. - */
  137. - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
  138. - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
  139. - cap_raise(override_cred->cap_effective, CAP_FOWNER);
  140. - cap_raise(override_cred->cap_effective, CAP_FSETID);
  141. - cap_raise(override_cred->cap_effective, CAP_CHOWN);
  142. - old_cred = override_creds(override_cred);
  143. + const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
  144. err = ovl_remove_and_whiteout(dentry, is_dir);
  145. revert_creds(old_cred);
  146. - put_cred(override_cred);
  147. }
  148. out_drop_write:
  149. ovl_drop_write(dentry);
  150. @@ -723,7 +687,6 @@ static int ovl_rename2(struct inode *old
  151. bool new_is_dir = false;
  152. struct dentry *opaquedir = NULL;
  153. const struct cred *old_cred = NULL;
  154. - struct cred *override_cred = NULL;
  155. err = -EINVAL;
  156. if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
  157. @@ -792,26 +755,8 @@ static int ovl_rename2(struct inode *old
  158. old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
  159. new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
  160. - if (old_opaque || new_opaque) {
  161. - err = -ENOMEM;
  162. - override_cred = prepare_creds();
  163. - if (!override_cred)
  164. - goto out_drop_write;
  165. -
  166. - /*
  167. - * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
  168. - * CAP_DAC_OVERRIDE for create in workdir
  169. - * CAP_FOWNER for removing whiteout from sticky dir
  170. - * CAP_FSETID for chmod of opaque dir
  171. - * CAP_CHOWN for chown of opaque dir
  172. - */
  173. - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
  174. - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
  175. - cap_raise(override_cred->cap_effective, CAP_FOWNER);
  176. - cap_raise(override_cred->cap_effective, CAP_FSETID);
  177. - cap_raise(override_cred->cap_effective, CAP_CHOWN);
  178. - old_cred = override_creds(override_cred);
  179. - }
  180. + if (old_opaque || new_opaque)
  181. + old_cred = ovl_override_creds(old->d_sb);
  182. if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
  183. opaquedir = ovl_check_empty_and_clear(new);
  184. @@ -942,10 +887,8 @@ out_dput_old:
  185. out_unlock:
  186. unlock_rename(new_upperdir, old_upperdir);
  187. out_revert_creds:
  188. - if (old_opaque || new_opaque) {
  189. + if (old_opaque || new_opaque)
  190. revert_creds(old_cred);
  191. - put_cred(override_cred);
  192. - }
  193. out_drop_write:
  194. ovl_drop_write(old);
  195. out:
  196. --- a/fs/overlayfs/overlayfs.h
  197. +++ b/fs/overlayfs/overlayfs.h
  198. @@ -150,6 +150,7 @@ void ovl_drop_write(struct dentry *dentr
  199. bool ovl_dentry_is_opaque(struct dentry *dentry);
  200. void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
  201. bool ovl_is_whiteout(struct dentry *dentry);
  202. +const struct cred *ovl_override_creds(struct super_block *sb);
  203. void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
  204. struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
  205. unsigned int flags);
  206. --- a/fs/overlayfs/readdir.c
  207. +++ b/fs/overlayfs/readdir.c
  208. @@ -36,6 +36,7 @@ struct ovl_dir_cache {
  209. struct ovl_readdir_data {
  210. struct dir_context ctx;
  211. + struct dentry *dentry;
  212. bool is_lowest;
  213. struct rb_root root;
  214. struct list_head *list;
  215. @@ -205,17 +206,8 @@ static int ovl_check_whiteouts(struct de
  216. struct ovl_cache_entry *p;
  217. struct dentry *dentry;
  218. const struct cred *old_cred;
  219. - struct cred *override_cred;
  220. -
  221. - override_cred = prepare_creds();
  222. - if (!override_cred)
  223. - return -ENOMEM;
  224. - /*
  225. - * CAP_DAC_OVERRIDE for lookup
  226. - */
  227. - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
  228. - old_cred = override_creds(override_cred);
  229. + old_cred = ovl_override_creds(rdd->dentry->d_sb);
  230. err = mutex_lock_killable(&dir->d_inode->i_mutex);
  231. if (!err) {
  232. @@ -231,7 +223,6 @@ static int ovl_check_whiteouts(struct de
  233. mutex_unlock(&dir->d_inode->i_mutex);
  234. }
  235. revert_creds(old_cred);
  236. - put_cred(override_cred);
  237. return err;
  238. }
  239. @@ -287,6 +278,7 @@ static int ovl_dir_read_merged(struct de
  240. struct path realpath;
  241. struct ovl_readdir_data rdd = {
  242. .ctx.actor = ovl_fill_merge,
  243. + .dentry = dentry,
  244. .list = list,
  245. .root = RB_ROOT,
  246. .is_lowest = false,
  247. --- a/fs/overlayfs/super.c
  248. +++ b/fs/overlayfs/super.c
  249. @@ -42,6 +42,8 @@ struct ovl_fs {
  250. long lower_namelen;
  251. /* pathnames of lower and upper dirs, for show_options */
  252. struct ovl_config config;
  253. + /* creds of process who forced instantiation of super block */
  254. + const struct cred *creator_cred;
  255. };
  256. struct ovl_dir_cache;
  257. @@ -246,6 +248,13 @@ bool ovl_is_whiteout(struct dentry *dent
  258. return inode && IS_WHITEOUT(inode);
  259. }
  260. +const struct cred *ovl_override_creds(struct super_block *sb)
  261. +{
  262. + struct ovl_fs *ofs = sb->s_fs_info;
  263. +
  264. + return override_creds(ofs->creator_cred);
  265. +}
  266. +
  267. static bool ovl_is_opaquedir(struct dentry *dentry)
  268. {
  269. int res;
  270. @@ -587,6 +596,7 @@ static void ovl_put_super(struct super_b
  271. kfree(ufs->config.lowerdir);
  272. kfree(ufs->config.upperdir);
  273. kfree(ufs->config.workdir);
  274. + put_cred(ufs->creator_cred);
  275. kfree(ufs);
  276. }
  277. @@ -1087,10 +1097,14 @@ static int ovl_fill_super(struct super_b
  278. else
  279. sb->s_d_op = &ovl_dentry_operations;
  280. + ufs->creator_cred = prepare_creds();
  281. + if (!ufs->creator_cred)
  282. + goto out_put_lower_mnt;
  283. +
  284. err = -ENOMEM;
  285. oe = ovl_alloc_entry(numlower);
  286. if (!oe)
  287. - goto out_put_lower_mnt;
  288. + goto out_put_cred;
  289. root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
  290. if (!root_dentry)
  291. @@ -1123,6 +1137,8 @@ static int ovl_fill_super(struct super_b
  292. out_free_oe:
  293. kfree(oe);
  294. +out_put_cred:
  295. + put_cred(ufs->creator_cred);
  296. out_put_lower_mnt:
  297. for (i = 0; i < ufs->numlower; i++)
  298. mntput(ufs->lower_mnt[i]);