diff options
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 95 |
1 files changed, 87 insertions, 8 deletions
diff --git a/fs/namei.c b/fs/namei.c index aa62dbda93ac..aaaa81036234 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. |
| @@ -1416,27 +1493,27 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
| 1416 | */ | 1493 | */ |
| 1417 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1494 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) |
| 1418 | { | 1495 | { |
| 1419 | int acc_mode, error = 0; | 1496 | int acc_mode, error; |
| 1420 | struct path path; | 1497 | struct path path; |
| 1421 | struct dentry *dir; | 1498 | struct dentry *dir; |
| 1422 | int count = 0; | 1499 | int count = 0; |
| 1423 | 1500 | ||
| 1424 | acc_mode = ACC_MODE(flag); | 1501 | acc_mode = ACC_MODE(flag); |
| 1425 | 1502 | ||
| 1503 | /* O_TRUNC implies we need access checks for write permissions */ | ||
| 1504 | if (flag & O_TRUNC) | ||
| 1505 | acc_mode |= MAY_WRITE; | ||
| 1506 | |||
| 1426 | /* Allow the LSM permission hook to distinguish append | 1507 | /* Allow the LSM permission hook to distinguish append |
| 1427 | access from general write access. */ | 1508 | access from general write access. */ |
| 1428 | if (flag & O_APPEND) | 1509 | if (flag & O_APPEND) |
| 1429 | acc_mode |= MAY_APPEND; | 1510 | acc_mode |= MAY_APPEND; |
| 1430 | 1511 | ||
| 1431 | /* Fill in the open() intent data */ | ||
| 1432 | nd->intent.open.flags = flag; | ||
| 1433 | nd->intent.open.create_mode = mode; | ||
| 1434 | |||
| 1435 | /* | 1512 | /* |
| 1436 | * The simplest case - just a plain lookup. | 1513 | * The simplest case - just a plain lookup. |
| 1437 | */ | 1514 | */ |
| 1438 | if (!(flag & O_CREAT)) { | 1515 | if (!(flag & O_CREAT)) { |
| 1439 | error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd); | 1516 | error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); |
| 1440 | if (error) | 1517 | if (error) |
| 1441 | return error; | 1518 | return error; |
| 1442 | goto ok; | 1519 | goto ok; |
| @@ -1445,7 +1522,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
| 1445 | /* | 1522 | /* |
| 1446 | * Create - we need to know the parent. | 1523 | * Create - we need to know the parent. |
| 1447 | */ | 1524 | */ |
| 1448 | error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd); | 1525 | error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); |
| 1449 | if (error) | 1526 | if (error) |
| 1450 | return error; | 1527 | return error; |
| 1451 | 1528 | ||
| @@ -1520,6 +1597,8 @@ ok: | |||
| 1520 | exit_dput: | 1597 | exit_dput: |
| 1521 | dput_path(&path, nd); | 1598 | dput_path(&path, nd); |
| 1522 | exit: | 1599 | exit: |
| 1600 | if (!IS_ERR(nd->intent.open.file)) | ||
| 1601 | release_open_intent(nd); | ||
| 1523 | path_release(nd); | 1602 | path_release(nd); |
| 1524 | return error; | 1603 | return error; |
| 1525 | 1604 | ||
