Add a simple helper to link with a kernel space file name and switch the early init code over to it. Remove the now unused ksys_link.
Unified · Split
| @@ -122,6 +122,39 @@ int __init init_eaccess(const char *filename) · 121 unmodified lines | |||
| 122 | return error; | 122 | return error; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | int __init init_link(const char *oldname, const char *newname) | ||
| 126 | { | ||
| 127 | struct dentry *new_dentry; | ||
| 128 | struct path old_path, new_path; | ||
| 129 | int error; | ||
| 130 | |||
| 131 | error = kern_path(oldname, 0, &old_path); | ||
| 132 | if (error) | ||
| 133 | return error; | ||
| 134 | |||
| 135 | new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0); | ||
| 136 | error = PTR_ERR(new_dentry); | ||
| 137 | if (IS_ERR(new_dentry)) | ||
| 138 | goto out; | ||
| 139 | |||
| 140 | error = -EXDEV; | ||
| 141 | if (old_path.mnt != new_path.mnt) | ||
| 142 | goto out_dput; | ||
| 143 | error = may_linkat(&old_path); | ||
| 144 | if (unlikely(error)) | ||
| 145 | goto out_dput; | ||
| 146 | error = security_path_link(old_path.dentry, &new_path, new_dentry); | ||
| 147 | if (error) | ||
| 148 | goto out_dput; | ||
| 149 | error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, | ||
| 150 | NULL); | ||
| 151 | out_dput: | ||
| 152 | done_path_create(&new_path, new_dentry); | ||
| 153 | out: | ||
| 154 | path_put(&old_path); | ||
| 155 | return error; | ||
| 156 | } | ||
| 157 | |||
| 125 | int __init init_unlink(const char *pathname) | 158 | int __init init_unlink(const char *pathname) |
| 126 | { | 159 | { |
| 127 | return do_unlinkat(AT_FDCWD, getname_kernel(pathname)); | 160 | return do_unlinkat(AT_FDCWD, getname_kernel(pathname)); |
| @@ -69,8 +69,7 @@ long do_rmdir(int dfd, struct filename *name); · 68 unmodified lines | |||
| 69 | long do_unlinkat(int dfd, struct filename *name); | 69 | long do_unlinkat(int dfd, struct filename *name); |
| 70 | long do_symlinkat(const char __user *oldname, int newdfd, | 70 | long do_symlinkat(const char __user *oldname, int newdfd, |
| 71 | const char __user *newname); | 71 | const char __user *newname); |
| 72 | int do_linkat(int olddfd, const char __user *oldname, int newdfd, | 72 | int may_linkat(struct path *link); |
| 73 | const char __user *newname, int flags); | ||
| 74 | 73 | ||
| 75 | /* | 74 | /* |
| 76 | * namespace.c | 75 | * namespace.c |
| @@ -1024,7 +1024,7 @@ static bool safe_hardlink_source(struct inode *inode) · 1023 unmodified lines | |||
| 1024 | * | 1024 | * |
| 1025 | * Returns 0 if successful, -ve on error. | 1025 | * Returns 0 if successful, -ve on error. |
| 1026 | */ | 1026 | */ |
| 1027 | static int may_linkat(struct path *link) | 1027 | int may_linkat(struct path *link) |
| 1028 | { | 1028 | { |
| 1029 | struct inode *inode = link->dentry->d_inode; | 1029 | struct inode *inode = link->dentry->d_inode; |
| 1030 | 1030 | ||
| @@ -4086,7 +4086,7 @@ EXPORT_SYMBOL(vfs_link); · 3055 unmodified lines | |||
| 4086 | * with linux 2.0, and to avoid hard-linking to directories | 4086 | * with linux 2.0, and to avoid hard-linking to directories |
| 4087 | * and other special files. --ADM | 4087 | * and other special files. --ADM |
| 4088 | */ | 4088 | */ |
| 4089 | int do_linkat(int olddfd, const char __user *oldname, int newdfd, | 4089 | static int do_linkat(int olddfd, const char __user *oldname, int newdfd, |
| 4090 | const char __user *newname, int flags) | 4090 | const char __user *newname, int flags) |
| 4091 | { | 4091 | { |
| 4092 | struct dentry *new_dentry; | 4092 | struct dentry *new_dentry; |
| @@ -8,5 +8,6 @@ int __init init_chroot(const char *filename); · 7 unmodified lines | |||
| 8 | int __init init_chown(const char *filename, uid_t user, gid_t group, int flags); | 8 | int __init init_chown(const char *filename, uid_t user, gid_t group, int flags); |
| 9 | int __init init_chmod(const char *filename, umode_t mode); | 9 | int __init init_chmod(const char *filename, umode_t mode); |
| 10 | int __init init_eaccess(const char *filename); | 10 | int __init init_eaccess(const char *filename); |
| 11 | int __init init_link(const char *oldname, const char *newname); | ||
| 11 | int __init init_unlink(const char *pathname); | 12 | int __init init_unlink(const char *pathname); |
| 12 | int __init init_rmdir(const char *pathname); | 13 | int __init init_rmdir(const char *pathname); |
| @@ -1295,15 +1295,6 @@ static inline long ksys_mknod(const char __user *filename, umode_t mode, · 1294 unmodified lines | |||
| 1295 | return do_mknodat(AT_FDCWD, filename, mode, dev); | 1295 | return do_mknodat(AT_FDCWD, filename, mode, dev); |
| 1296 | } | 1296 | } |
| 1297 | 1297 | ||
| 1298 | extern int do_linkat(int olddfd, const char __user *oldname, int newdfd, | ||
| 1299 | const char __user *newname, int flags); | ||
| 1300 | |||
| 1301 | static inline long ksys_link(const char __user *oldname, | ||
| 1302 | const char __user *newname) | ||
| 1303 | { | ||
| 1304 | return do_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | extern int do_fchownat(int dfd, const char __user *filename, uid_t user, | 1298 | extern int do_fchownat(int dfd, const char __user *filename, uid_t user, |
| 1308 | gid_t group, int flag); | 1299 | gid_t group, int flag); |
| 1309 | 1300 | ||
| @@ -312,7 +312,7 @@ static int __init maybe_link(void) · 311 unmodified lines | |||
| 312 | char *old = find_link(major, minor, ino, mode, collected); | 312 | char *old = find_link(major, minor, ino, mode, collected); |
| 313 | if (old) { | 313 | if (old) { |
| 314 | clean_path(collected, 0); | 314 | clean_path(collected, 0); |
| 315 | return (ksys_link(old, collected) < 0) ? -1 : 1; | 315 | return (init_link(old, collected) < 0) ? -1 : 1; |
| 316 | } | 316 | } |
| 317 | } | 317 | } |
| 318 | return 0; | 318 | return 0; |