.. | .. |
---|
1 | | -/* |
---|
2 | | - * This program is free software; you can redistribute it and/or |
---|
3 | | - * modify it under the terms of the GNU General Public License as |
---|
4 | | - * published by the Free Software Foundation, version 2 of the |
---|
5 | | - * License. |
---|
6 | | - */ |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
7 | 2 | |
---|
8 | 3 | #include <linux/export.h> |
---|
9 | 4 | #include <linux/nsproxy.h> |
---|
.. | .. |
---|
111 | 106 | if (!ns) |
---|
112 | 107 | goto fail_dec; |
---|
113 | 108 | |
---|
| 109 | + ns->parent_could_setfcap = cap_raised(new->cap_effective, CAP_SETFCAP); |
---|
114 | 110 | ret = ns_alloc_inum(&ns->ns); |
---|
115 | 111 | if (ret) |
---|
116 | 112 | goto fail_free; |
---|
.. | .. |
---|
133 | 129 | ns->flags = parent_ns->flags; |
---|
134 | 130 | mutex_unlock(&userns_state_mutex); |
---|
135 | 131 | |
---|
136 | | -#ifdef CONFIG_PERSISTENT_KEYRINGS |
---|
137 | | - init_rwsem(&ns->persistent_keyring_register_sem); |
---|
| 132 | +#ifdef CONFIG_KEYS |
---|
| 133 | + INIT_LIST_HEAD(&ns->keyring_name_list); |
---|
| 134 | + init_rwsem(&ns->keyring_sem); |
---|
138 | 135 | #endif |
---|
139 | 136 | ret = -ENOMEM; |
---|
140 | 137 | if (!setup_userns_sysctls(ns)) |
---|
.. | .. |
---|
196 | 193 | kfree(ns->projid_map.reverse); |
---|
197 | 194 | } |
---|
198 | 195 | retire_userns_sysctls(ns); |
---|
199 | | -#ifdef CONFIG_PERSISTENT_KEYRINGS |
---|
200 | | - key_put(ns->persistent_keyring_register); |
---|
201 | | -#endif |
---|
| 196 | + key_free_user_ns(ns); |
---|
202 | 197 | ns_free_inum(&ns->ns); |
---|
203 | 198 | kmem_cache_free(user_ns_cachep, ns); |
---|
204 | 199 | dec_user_namespaces(ucounts); |
---|
.. | .. |
---|
521 | 516 | * |
---|
522 | 517 | * When there is no mapping defined for the user-namespace projid |
---|
523 | 518 | * pair INVALID_PROJID is returned. Callers are expected to test |
---|
524 | | - * for and handle handle INVALID_PROJID being returned. INVALID_PROJID |
---|
| 519 | + * for and handle INVALID_PROJID being returned. INVALID_PROJID |
---|
525 | 520 | * may be tested for using projid_valid(). |
---|
526 | 521 | */ |
---|
527 | 522 | kprojid_t make_kprojid(struct user_namespace *ns, projid_t projid) |
---|
.. | .. |
---|
847 | 842 | return 0; |
---|
848 | 843 | } |
---|
849 | 844 | |
---|
| 845 | +/** |
---|
| 846 | + * verify_root_map() - check the uid 0 mapping |
---|
| 847 | + * @file: idmapping file |
---|
| 848 | + * @map_ns: user namespace of the target process |
---|
| 849 | + * @new_map: requested idmap |
---|
| 850 | + * |
---|
| 851 | + * If a process requests mapping parent uid 0 into the new ns, verify that the |
---|
| 852 | + * process writing the map had the CAP_SETFCAP capability as the target process |
---|
| 853 | + * will be able to write fscaps that are valid in ancestor user namespaces. |
---|
| 854 | + * |
---|
| 855 | + * Return: true if the mapping is allowed, false if not. |
---|
| 856 | + */ |
---|
| 857 | +static bool verify_root_map(const struct file *file, |
---|
| 858 | + struct user_namespace *map_ns, |
---|
| 859 | + struct uid_gid_map *new_map) |
---|
| 860 | +{ |
---|
| 861 | + int idx; |
---|
| 862 | + const struct user_namespace *file_ns = file->f_cred->user_ns; |
---|
| 863 | + struct uid_gid_extent *extent0 = NULL; |
---|
| 864 | + |
---|
| 865 | + for (idx = 0; idx < new_map->nr_extents; idx++) { |
---|
| 866 | + if (new_map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) |
---|
| 867 | + extent0 = &new_map->extent[idx]; |
---|
| 868 | + else |
---|
| 869 | + extent0 = &new_map->forward[idx]; |
---|
| 870 | + if (extent0->lower_first == 0) |
---|
| 871 | + break; |
---|
| 872 | + |
---|
| 873 | + extent0 = NULL; |
---|
| 874 | + } |
---|
| 875 | + |
---|
| 876 | + if (!extent0) |
---|
| 877 | + return true; |
---|
| 878 | + |
---|
| 879 | + if (map_ns == file_ns) { |
---|
| 880 | + /* The process unshared its ns and is writing to its own |
---|
| 881 | + * /proc/self/uid_map. User already has full capabilites in |
---|
| 882 | + * the new namespace. Verify that the parent had CAP_SETFCAP |
---|
| 883 | + * when it unshared. |
---|
| 884 | + * */ |
---|
| 885 | + if (!file_ns->parent_could_setfcap) |
---|
| 886 | + return false; |
---|
| 887 | + } else { |
---|
| 888 | + /* Process p1 is writing to uid_map of p2, who is in a child |
---|
| 889 | + * user namespace to p1's. Verify that the opener of the map |
---|
| 890 | + * file has CAP_SETFCAP against the parent of the new map |
---|
| 891 | + * namespace */ |
---|
| 892 | + if (!file_ns_capable(file, map_ns->parent, CAP_SETFCAP)) |
---|
| 893 | + return false; |
---|
| 894 | + } |
---|
| 895 | + |
---|
| 896 | + return true; |
---|
| 897 | +} |
---|
| 898 | + |
---|
850 | 899 | static ssize_t map_write(struct file *file, const char __user *buf, |
---|
851 | 900 | size_t count, loff_t *ppos, |
---|
852 | 901 | int cap_setid, |
---|
.. | .. |
---|
854 | 903 | struct uid_gid_map *parent_map) |
---|
855 | 904 | { |
---|
856 | 905 | struct seq_file *seq = file->private_data; |
---|
857 | | - struct user_namespace *ns = seq->private; |
---|
| 906 | + struct user_namespace *map_ns = seq->private; |
---|
858 | 907 | struct uid_gid_map new_map; |
---|
859 | 908 | unsigned idx; |
---|
860 | 909 | struct uid_gid_extent extent; |
---|
.. | .. |
---|
901 | 950 | /* |
---|
902 | 951 | * Adjusting namespace settings requires capabilities on the target. |
---|
903 | 952 | */ |
---|
904 | | - if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN)) |
---|
| 953 | + if (cap_valid(cap_setid) && !file_ns_capable(file, map_ns, CAP_SYS_ADMIN)) |
---|
905 | 954 | goto out; |
---|
906 | 955 | |
---|
907 | 956 | /* Parse the user data */ |
---|
.. | .. |
---|
971 | 1020 | |
---|
972 | 1021 | ret = -EPERM; |
---|
973 | 1022 | /* Validate the user is allowed to use user id's mapped to. */ |
---|
974 | | - if (!new_idmap_permitted(file, ns, cap_setid, &new_map)) |
---|
| 1023 | + if (!new_idmap_permitted(file, map_ns, cap_setid, &new_map)) |
---|
975 | 1024 | goto out; |
---|
976 | 1025 | |
---|
977 | 1026 | ret = -EPERM; |
---|
.. | .. |
---|
1092 | 1141 | struct uid_gid_map *new_map) |
---|
1093 | 1142 | { |
---|
1094 | 1143 | const struct cred *cred = file->f_cred; |
---|
| 1144 | + |
---|
| 1145 | + if (cap_setid == CAP_SETUID && !verify_root_map(file, ns, new_map)) |
---|
| 1146 | + return false; |
---|
| 1147 | + |
---|
1095 | 1148 | /* Don't allow mappings that would allow anything that wouldn't |
---|
1096 | 1149 | * be allowed without the establishment of unprivileged mappings. |
---|
1097 | 1150 | */ |
---|
.. | .. |
---|
1259 | 1312 | put_user_ns(to_user_ns(ns)); |
---|
1260 | 1313 | } |
---|
1261 | 1314 | |
---|
1262 | | -static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns) |
---|
| 1315 | +static int userns_install(struct nsset *nsset, struct ns_common *ns) |
---|
1263 | 1316 | { |
---|
1264 | 1317 | struct user_namespace *user_ns = to_user_ns(ns); |
---|
1265 | 1318 | struct cred *cred; |
---|
.. | .. |
---|
1280 | 1333 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) |
---|
1281 | 1334 | return -EPERM; |
---|
1282 | 1335 | |
---|
1283 | | - cred = prepare_creds(); |
---|
| 1336 | + cred = nsset_cred(nsset); |
---|
1284 | 1337 | if (!cred) |
---|
1285 | | - return -ENOMEM; |
---|
| 1338 | + return -EINVAL; |
---|
1286 | 1339 | |
---|
1287 | 1340 | put_user_ns(cred->user_ns); |
---|
1288 | 1341 | set_cred_user_ns(cred, get_user_ns(user_ns)); |
---|
1289 | 1342 | |
---|
1290 | | - return commit_creds(cred); |
---|
| 1343 | + return 0; |
---|
1291 | 1344 | } |
---|
1292 | 1345 | |
---|
1293 | 1346 | struct ns_common *ns_get_owner(struct ns_common *ns) |
---|