diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 101 |
1 files changed, 87 insertions, 14 deletions
diff --git a/fs/namei.c b/fs/namei.c index aa62dbda93ac..c5769c4fcab1 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/syscalls.h> | 28 | #include <linux/syscalls.h> |
29 | #include <linux/mount.h> | 29 | #include <linux/mount.h> |
30 | #include <linux/audit.h> | 30 | #include <linux/audit.h> |
31 | #include <linux/file.h> | ||
31 | #include <asm/namei.h> | 32 | #include <asm/namei.h> |
32 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
33 | 34 | ||
@@ -317,6 +318,18 @@ void path_release_on_umount(struct nameidata *nd) | |||
317 | mntput_no_expire(nd->mnt); | 318 | mntput_no_expire(nd->mnt); |
318 | } | 319 | } |
319 | 320 | ||
321 | /** | ||
322 | * release_open_intent - free up open intent resources | ||
323 | * @nd: pointer to nameidata | ||
324 | */ | ||
325 | void release_open_intent(struct nameidata *nd) | ||
326 | { | ||
327 | if (nd->intent.open.file->f_dentry == NULL) | ||
328 | put_filp(nd->intent.open.file); | ||
329 | else | ||
330 | fput(nd->intent.open.file); | ||
331 | } | ||
332 | |||
320 | /* | 333 | /* |
321 | * Internal lookup() using the new generic dcache. | 334 | * Internal lookup() using the new generic dcache. |
322 | * SMP-safe | 335 | * SMP-safe |
@@ -750,6 +763,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
750 | struct qstr this; | 763 | struct qstr this; |
751 | unsigned int c; | 764 | unsigned int c; |
752 | 765 | ||
766 | nd->flags |= LOOKUP_CONTINUE; | ||
753 | err = exec_permission_lite(inode, nd); | 767 | err = exec_permission_lite(inode, nd); |
754 | if (err == -EAGAIN) { | 768 | if (err == -EAGAIN) { |
755 | err = permission(inode, MAY_EXEC, nd); | 769 | err = permission(inode, MAY_EXEC, nd); |
@@ -802,7 +816,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
802 | if (err < 0) | 816 | if (err < 0) |
803 | break; | 817 | break; |
804 | } | 818 | } |
805 | nd->flags |= LOOKUP_CONTINUE; | ||
806 | /* This does the actual lookups.. */ | 819 | /* This does the actual lookups.. */ |
807 | err = do_lookup(nd, &this, &next); | 820 | err = do_lookup(nd, &this, &next); |
808 | if (err) | 821 | if (err) |
@@ -1052,6 +1065,70 @@ out: | |||
1052 | return retval; | 1065 | return retval; |
1053 | } | 1066 | } |
1054 | 1067 | ||
1068 | static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, | ||
1069 | struct nameidata *nd, int open_flags, int create_mode) | ||
1070 | { | ||
1071 | struct file *filp = get_empty_filp(); | ||
1072 | int err; | ||
1073 | |||
1074 | if (filp == NULL) | ||
1075 | return -ENFILE; | ||
1076 | nd->intent.open.file = filp; | ||
1077 | nd->intent.open.flags = open_flags; | ||
1078 | nd->intent.open.create_mode = create_mode; | ||
1079 | err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd); | ||
1080 | if (IS_ERR(nd->intent.open.file)) { | ||
1081 | if (err == 0) { | ||
1082 | err = PTR_ERR(nd->intent.open.file); | ||
1083 | path_release(nd); | ||
1084 | } | ||
1085 | } else if (err != 0) | ||
1086 | release_open_intent(nd); | ||
1087 | return err; | ||
1088 | } | ||
1089 | |||
1090 | /** | ||
1091 | * path_lookup_open - lookup a file path with open intent | ||
1092 | * @name: pointer to file name | ||
1093 | * @lookup_flags: lookup intent flags | ||
1094 | * @nd: pointer to nameidata | ||
1095 | * @open_flags: open intent flags | ||
1096 | */ | ||
1097 | int path_lookup_open(const char *name, unsigned int lookup_flags, | ||
1098 | struct nameidata *nd, int open_flags) | ||
1099 | { | ||
1100 | return __path_lookup_intent_open(name, lookup_flags, nd, | ||
1101 | open_flags, 0); | ||
1102 | } | ||
1103 | |||
1104 | /** | ||
1105 | * path_lookup_create - lookup a file path with open + create intent | ||
1106 | * @name: pointer to file name | ||
1107 | * @lookup_flags: lookup intent flags | ||
1108 | * @nd: pointer to nameidata | ||
1109 | * @open_flags: open intent flags | ||
1110 | * @create_mode: create intent flags | ||
1111 | */ | ||
1112 | int path_lookup_create(const char *name, unsigned int lookup_flags, | ||
1113 | struct nameidata *nd, int open_flags, int create_mode) | ||
1114 | { | ||
1115 | return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd, | ||
1116 | open_flags, create_mode); | ||
1117 | } | ||
1118 | |||
1119 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | ||
1120 | struct nameidata *nd, int open_flags) | ||
1121 | { | ||
1122 | char *tmp = getname(name); | ||
1123 | int err = PTR_ERR(tmp); | ||
1124 | |||
1125 | if (!IS_ERR(tmp)) { | ||
1126 | err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0); | ||
1127 | putname(tmp); | ||
1128 | } | ||
1129 | return err; | ||
1130 | } | ||
1131 | |||
1055 | /* | 1132 | /* |
1056 | * Restricted form of lookup. Doesn't follow links, single-component only, | 1133 | * Restricted form of lookup. Doesn't follow links, single-component only, |
1057 | * needs parent already locked. Doesn't follow mounts. | 1134 | * needs parent already locked. Doesn't follow mounts. |
@@ -1234,9 +1311,6 @@ static inline int may_create(struct inode *dir, struct dentry *child, | |||
1234 | } | 1311 | } |
1235 | 1312 | ||
1236 | /* | 1313 | /* |
1237 | * Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security | ||
1238 | * reasons. | ||
1239 | * | ||
1240 | * O_DIRECTORY translates into forcing a directory lookup. | 1314 | * O_DIRECTORY translates into forcing a directory lookup. |
1241 | */ | 1315 | */ |
1242 | static inline int lookup_flags(unsigned int f) | 1316 | static inline int lookup_flags(unsigned int f) |
@@ -1246,9 +1320,6 @@ static inline int lookup_flags(unsigned int f) | |||
1246 | if (f & O_NOFOLLOW) | 1320 | if (f & O_NOFOLLOW) |
1247 | retval &= ~LOOKUP_FOLLOW; | 1321 | retval &= ~LOOKUP_FOLLOW; |
1248 | 1322 | ||
1249 | if ((f & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) | ||
1250 | retval &= ~LOOKUP_FOLLOW; | ||
1251 | |||
1252 | if (f & O_DIRECTORY) | 1323 | if (f & O_DIRECTORY) |
1253 | retval |= LOOKUP_DIRECTORY; | 1324 | retval |= LOOKUP_DIRECTORY; |
1254 | 1325 | ||
@@ -1416,27 +1487,27 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1416 | */ | 1487 | */ |
1417 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1488 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) |
1418 | { | 1489 | { |
1419 | int acc_mode, error = 0; | 1490 | int acc_mode, error; |
1420 | struct path path; | 1491 | struct path path; |
1421 | struct dentry *dir; | 1492 | struct dentry *dir; |
1422 | int count = 0; | 1493 | int count = 0; |
1423 | 1494 | ||
1424 | acc_mode = ACC_MODE(flag); | 1495 | acc_mode = ACC_MODE(flag); |
1425 | 1496 | ||
1497 | /* O_TRUNC implies we need access checks for write permissions */ | ||
1498 | if (flag & O_TRUNC) | ||
1499 | acc_mode |= MAY_WRITE; | ||
1500 | |||
1426 | /* Allow the LSM permission hook to distinguish append | 1501 | /* Allow the LSM permission hook to distinguish append |
1427 | access from general write access. */ | 1502 | access from general write access. */ |
1428 | if (flag & O_APPEND) | 1503 | if (flag & O_APPEND) |
1429 | acc_mode |= MAY_APPEND; | 1504 | acc_mode |= MAY_APPEND; |
1430 | 1505 | ||
1431 | /* Fill in the open() intent data */ | ||
1432 | nd->intent.open.flags = flag; | ||
1433 | nd->intent.open.create_mode = mode; | ||
1434 | |||
1435 | /* | 1506 | /* |
1436 | * The simplest case - just a plain lookup. | 1507 | * The simplest case - just a plain lookup. |
1437 | */ | 1508 | */ |
1438 | if (!(flag & O_CREAT)) { | 1509 | if (!(flag & O_CREAT)) { |
1439 | error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd); | 1510 | error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); |
1440 | if (error) | 1511 | if (error) |
1441 | return error; | 1512 | return error; |
1442 | goto ok; | 1513 | goto ok; |
@@ -1445,7 +1516,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1445 | /* | 1516 | /* |
1446 | * Create - we need to know the parent. | 1517 | * Create - we need to know the parent. |
1447 | */ | 1518 | */ |
1448 | error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd); | 1519 | error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); |
1449 | if (error) | 1520 | if (error) |
1450 | return error; | 1521 | return error; |
1451 | 1522 | ||
@@ -1520,6 +1591,8 @@ ok: | |||
1520 | exit_dput: | 1591 | exit_dput: |
1521 | dput_path(&path, nd); | 1592 | dput_path(&path, nd); |
1522 | exit: | 1593 | exit: |
1594 | if (!IS_ERR(nd->intent.open.file)) | ||
1595 | release_open_intent(nd); | ||
1523 | path_release(nd); | 1596 | path_release(nd); |
1524 | return error; | 1597 | return error; |
1525 | 1598 | ||