0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/magic.h>
0012 #include <linux/mount.h>
0013 #include <linux/namei.h>
0014 #include <linux/nsproxy.h>
0015 #include <linux/path.h>
0016 #include <linux/sched.h>
0017 #include <linux/slab.h>
0018 #include <linux/fs_struct.h>
0019
0020 #include "include/apparmor.h"
0021 #include "include/path.h"
0022 #include "include/policy.h"
0023
0024
0025 static int prepend(char **buffer, int buflen, const char *str, int namelen)
0026 {
0027 buflen -= namelen;
0028 if (buflen < 0)
0029 return -ENAMETOOLONG;
0030 *buffer -= namelen;
0031 memcpy(*buffer, str, namelen);
0032 return 0;
0033 }
0034
0035 #define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 static int disconnect(const struct path *path, char *buf, char **name,
0049 int flags, const char *disconnected)
0050 {
0051 int error = 0;
0052
0053 if (!(flags & PATH_CONNECT_PATH) &&
0054 !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
0055 our_mnt(path->mnt))) {
0056
0057
0058
0059 error = -EACCES;
0060 if (**name == '/')
0061 *name = *name + 1;
0062 } else {
0063 if (**name != '/')
0064
0065 error = prepend(name, *name - buf, "/", 1);
0066 if (!error && disconnected)
0067 error = prepend(name, *name - buf, disconnected,
0068 strlen(disconnected));
0069 }
0070
0071 return error;
0072 }
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 static int d_namespace_path(const struct path *path, char *buf, char **name,
0089 int flags, const char *disconnected)
0090 {
0091 char *res;
0092 int error = 0;
0093 int connected = 1;
0094 int isdir = (flags & PATH_IS_DIR) ? 1 : 0;
0095 int buflen = aa_g_path_max - isdir;
0096
0097 if (path->mnt->mnt_flags & MNT_INTERNAL) {
0098
0099 res = dentry_path(path->dentry, buf, buflen);
0100 *name = res;
0101 if (IS_ERR(res)) {
0102 *name = buf;
0103 return PTR_ERR(res);
0104 }
0105 if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
0106 strncmp(*name, "/sys/", 5) == 0) {
0107
0108
0109
0110 error = prepend(name, *name - buf, "/proc", 5);
0111 goto out;
0112 } else
0113 error = disconnect(path, buf, name, flags,
0114 disconnected);
0115 goto out;
0116 }
0117
0118
0119 if (flags & PATH_CHROOT_REL) {
0120 struct path root;
0121 get_fs_root(current->fs, &root);
0122 res = __d_path(path, &root, buf, buflen);
0123 path_put(&root);
0124 } else {
0125 res = d_absolute_path(path, buf, buflen);
0126 if (!our_mnt(path->mnt))
0127 connected = 0;
0128 }
0129
0130
0131
0132
0133 if (!res || IS_ERR(res)) {
0134 if (PTR_ERR(res) == -ENAMETOOLONG) {
0135 error = -ENAMETOOLONG;
0136 *name = buf;
0137 goto out;
0138 }
0139 connected = 0;
0140 res = dentry_path_raw(path->dentry, buf, buflen);
0141 if (IS_ERR(res)) {
0142 error = PTR_ERR(res);
0143 *name = buf;
0144 goto out;
0145 }
0146 } else if (!our_mnt(path->mnt))
0147 connected = 0;
0148
0149 *name = res;
0150
0151 if (!connected)
0152 error = disconnect(path, buf, name, flags, disconnected);
0153
0154
0155
0156
0157
0158
0159
0160 if (d_unlinked(path->dentry) && d_is_positive(path->dentry) &&
0161 !(flags & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))) {
0162 error = -ENOENT;
0163 goto out;
0164 }
0165
0166 out:
0167
0168
0169
0170
0171 if (!error && isdir && ((*name)[1] != '\0' || (*name)[0] != '/'))
0172 strcpy(&buf[aa_g_path_max - 2], "/");
0173
0174 return error;
0175 }
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 int aa_path_name(const struct path *path, int flags, char *buffer,
0198 const char **name, const char **info, const char *disconnected)
0199 {
0200 char *str = NULL;
0201 int error = d_namespace_path(path, buffer, &str, flags, disconnected);
0202
0203 if (info && error) {
0204 if (error == -ENOENT)
0205 *info = "Failed name lookup - deleted entry";
0206 else if (error == -EACCES)
0207 *info = "Failed name lookup - disconnected path";
0208 else if (error == -ENAMETOOLONG)
0209 *info = "Failed name lookup - name too long";
0210 else
0211 *info = "Failed name lookup";
0212 }
0213
0214 *name = str;
0215
0216 return error;
0217 }