Commit e8a3e4719b7ec19288c56f22623f537cb78885c1

Authored by Eric W. Biederman
1 parent f76d207a66

userns: Implement struct kqid

Add the data type struct kqid which holds the kernel internal form of
the owning identifier of a quota.  struct kqid is a replacement for
the implicit union of uid, gid and project id stored in an unsigned
int and the quota type field that is was used in the quota data
structures.  Making the data type explicit allows the kuid_t and
kgid_t type safety to propogate more thoroughly through the code,
revealing more places where uid/gid conversions need be made.

Along with the data type struct kqid comes the helper functions
qid_eq, qid_lt, from_kqid, from_kqid_munged, qid_valid, make_kqid,
make_kqid_invalid, make_kqid_uid, make_kqid_gid.

Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>

Showing 3 changed files with 258 additions and 1 deletions Side-by-side Diff

... ... @@ -2,7 +2,7 @@
2 2 obj-$(CONFIG_QFMT_V1) += quota_v1.o
3 3 obj-$(CONFIG_QFMT_V2) += quota_v2.o
4 4 obj-$(CONFIG_QUOTA_TREE) += quota_tree.o
5   -obj-$(CONFIG_QUOTACTL) += quota.o
  5 +obj-$(CONFIG_QUOTACTL) += quota.o kqid.o
6 6 obj-$(CONFIG_QUOTACTL_COMPAT) += compat.o
7 7 obj-$(CONFIG_QUOTA_NETLINK_INTERFACE) += netlink.o
  1 +#include <linux/fs.h>
  2 +#include <linux/quota.h>
  3 +#include <linux/export.h>
  4 +
  5 +/**
  6 + * qid_eq - Test to see if to kquid values are the same
  7 + * @left: A qid value
  8 + * @right: Another quid value
  9 + *
  10 + * Return true if the two qid values are equal and false otherwise.
  11 + */
  12 +bool qid_eq(struct kqid left, struct kqid right)
  13 +{
  14 + if (left.type != right.type)
  15 + return false;
  16 + switch(left.type) {
  17 + case USRQUOTA:
  18 + return uid_eq(left.uid, right.uid);
  19 + case GRPQUOTA:
  20 + return gid_eq(left.gid, right.gid);
  21 + case PRJQUOTA:
  22 + return projid_eq(left.projid, right.projid);
  23 + default:
  24 + BUG();
  25 + }
  26 +}
  27 +EXPORT_SYMBOL(qid_eq);
  28 +
  29 +/**
  30 + * qid_lt - Test to see if one qid value is less than another
  31 + * @left: The possibly lesser qid value
  32 + * @right: The possibly greater qid value
  33 + *
  34 + * Return true if left is less than right and false otherwise.
  35 + */
  36 +bool qid_lt(struct kqid left, struct kqid right)
  37 +{
  38 + if (left.type < right.type)
  39 + return true;
  40 + if (left.type > right.type)
  41 + return false;
  42 + switch (left.type) {
  43 + case USRQUOTA:
  44 + return uid_lt(left.uid, right.uid);
  45 + case GRPQUOTA:
  46 + return gid_lt(left.gid, right.gid);
  47 + case PRJQUOTA:
  48 + return projid_lt(left.projid, right.projid);
  49 + default:
  50 + BUG();
  51 + }
  52 +}
  53 +EXPORT_SYMBOL(qid_lt);
  54 +
  55 +/**
  56 + * from_kqid - Create a qid from a kqid user-namespace pair.
  57 + * @targ: The user namespace we want a qid in.
  58 + * @kuid: The kernel internal quota identifier to start with.
  59 + *
  60 + * Map @kqid into the user-namespace specified by @targ and
  61 + * return the resulting qid.
  62 + *
  63 + * There is always a mapping into the initial user_namespace.
  64 + *
  65 + * If @kqid has no mapping in @targ (qid_t)-1 is returned.
  66 + */
  67 +qid_t from_kqid(struct user_namespace *targ, struct kqid kqid)
  68 +{
  69 + switch (kqid.type) {
  70 + case USRQUOTA:
  71 + return from_kuid(targ, kqid.uid);
  72 + case GRPQUOTA:
  73 + return from_kgid(targ, kqid.gid);
  74 + case PRJQUOTA:
  75 + return from_kprojid(targ, kqid.projid);
  76 + default:
  77 + BUG();
  78 + }
  79 +}
  80 +EXPORT_SYMBOL(from_kqid);
  81 +
  82 +/**
  83 + * from_kqid_munged - Create a qid from a kqid user-namespace pair.
  84 + * @targ: The user namespace we want a qid in.
  85 + * @kqid: The kernel internal quota identifier to start with.
  86 + *
  87 + * Map @kqid into the user-namespace specified by @targ and
  88 + * return the resulting qid.
  89 + *
  90 + * There is always a mapping into the initial user_namespace.
  91 + *
  92 + * Unlike from_kqid from_kqid_munged never fails and always
  93 + * returns a valid projid. This makes from_kqid_munged
  94 + * appropriate for use in places where failing to provide
  95 + * a qid_t is not a good option.
  96 + *
  97 + * If @kqid has no mapping in @targ the kqid.type specific
  98 + * overflow identifier is returned.
  99 + */
  100 +qid_t from_kqid_munged(struct user_namespace *targ, struct kqid kqid)
  101 +{
  102 + switch (kqid.type) {
  103 + case USRQUOTA:
  104 + return from_kuid_munged(targ, kqid.uid);
  105 + case GRPQUOTA:
  106 + return from_kgid_munged(targ, kqid.gid);
  107 + case PRJQUOTA:
  108 + return from_kprojid_munged(targ, kqid.projid);
  109 + default:
  110 + BUG();
  111 + }
  112 +}
  113 +EXPORT_SYMBOL(from_kqid_munged);
  114 +
  115 +/**
  116 + * qid_valid - Report if a valid value is stored in a kqid.
  117 + * @qid: The kernel internal quota identifier to test.
  118 + */
  119 +bool qid_valid(struct kqid qid)
  120 +{
  121 + switch (qid.type) {
  122 + case USRQUOTA:
  123 + return uid_valid(qid.uid);
  124 + case GRPQUOTA:
  125 + return gid_valid(qid.gid);
  126 + case PRJQUOTA:
  127 + return projid_valid(qid.projid);
  128 + default:
  129 + BUG();
  130 + }
  131 +}
  132 +EXPORT_SYMBOL(qid_valid);
include/linux/quota.h
... ... @@ -181,9 +181,134 @@
181 181 #include <linux/dqblk_v2.h>
182 182  
183 183 #include <linux/atomic.h>
  184 +#include <linux/uidgid.h>
  185 +#include <linux/projid.h>
184 186  
  187 +#undef USRQUOTA
  188 +#undef GRPQUOTA
  189 +enum quota_type {
  190 + USRQUOTA = 0, /* element used for user quotas */
  191 + GRPQUOTA = 1, /* element used for group quotas */
  192 + PRJQUOTA = 2, /* element used for project quotas */
  193 +};
  194 +
185 195 typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
186 196 typedef long long qsize_t; /* Type in which we store sizes */
  197 +
  198 +struct kqid { /* Type in which we store the quota identifier */
  199 + union {
  200 + kuid_t uid;
  201 + kgid_t gid;
  202 + kprojid_t projid;
  203 + };
  204 + enum quota_type type; /* USRQUOTA (uid) or GRPQUOTA (gid) or PRJQUOTA (projid) */
  205 +};
  206 +
  207 +extern bool qid_eq(struct kqid left, struct kqid right);
  208 +extern bool qid_lt(struct kqid left, struct kqid right);
  209 +extern qid_t from_kqid(struct user_namespace *to, struct kqid qid);
  210 +extern qid_t from_kqid_munged(struct user_namespace *to, struct kqid qid);
  211 +extern bool qid_valid(struct kqid qid);
  212 +
  213 +/**
  214 + * make_kqid - Map a user-namespace, type, qid tuple into a kqid.
  215 + * @from: User namespace that the qid is in
  216 + * @type: The type of quota
  217 + * @qid: Quota identifier
  218 + *
  219 + * Maps a user-namespace, type qid tuple into a kernel internal
  220 + * kqid, and returns that kqid.
  221 + *
  222 + * When there is no mapping defined for the user-namespace, type,
  223 + * qid tuple an invalid kqid is returned. Callers are expected to
  224 + * test for and handle handle invalid kqids being returned.
  225 + * Invalid kqids may be tested for using qid_valid().
  226 + */
  227 +static inline struct kqid make_kqid(struct user_namespace *from,
  228 + enum quota_type type, qid_t qid)
  229 +{
  230 + struct kqid kqid;
  231 +
  232 + kqid.type = type;
  233 + switch (type) {
  234 + case USRQUOTA:
  235 + kqid.uid = make_kuid(from, qid);
  236 + break;
  237 + case GRPQUOTA:
  238 + kqid.gid = make_kgid(from, qid);
  239 + break;
  240 + case PRJQUOTA:
  241 + kqid.projid = make_kprojid(from, qid);
  242 + break;
  243 + default:
  244 + BUG();
  245 + }
  246 + return kqid;
  247 +}
  248 +
  249 +/**
  250 + * make_kqid_invalid - Explicitly make an invalid kqid
  251 + * @type: The type of quota identifier
  252 + *
  253 + * Returns an invalid kqid with the specified type.
  254 + */
  255 +static inline struct kqid make_kqid_invalid(enum quota_type type)
  256 +{
  257 + struct kqid kqid;
  258 +
  259 + kqid.type = type;
  260 + switch (type) {
  261 + case USRQUOTA:
  262 + kqid.uid = INVALID_UID;
  263 + break;
  264 + case GRPQUOTA:
  265 + kqid.gid = INVALID_GID;
  266 + break;
  267 + case PRJQUOTA:
  268 + kqid.projid = INVALID_PROJID;
  269 + break;
  270 + default:
  271 + BUG();
  272 + }
  273 + return kqid;
  274 +}
  275 +
  276 +/**
  277 + * make_kqid_uid - Make a kqid from a kuid
  278 + * @uid: The kuid to make the quota identifier from
  279 + */
  280 +static inline struct kqid make_kqid_uid(kuid_t uid)
  281 +{
  282 + struct kqid kqid;
  283 + kqid.type = USRQUOTA;
  284 + kqid.uid = uid;
  285 + return kqid;
  286 +}
  287 +
  288 +/**
  289 + * make_kqid_gid - Make a kqid from a kgid
  290 + * @gid: The kgid to make the quota identifier from
  291 + */
  292 +static inline struct kqid make_kqid_gid(kgid_t gid)
  293 +{
  294 + struct kqid kqid;
  295 + kqid.type = GRPQUOTA;
  296 + kqid.gid = gid;
  297 + return kqid;
  298 +}
  299 +
  300 +/**
  301 + * make_kqid_projid - Make a kqid from a projid
  302 + * @projid: The kprojid to make the quota identifier from
  303 + */
  304 +static inline struct kqid make_kqid_projid(kprojid_t projid)
  305 +{
  306 + struct kqid kqid;
  307 + kqid.type = PRJQUOTA;
  308 + kqid.projid = projid;
  309 + return kqid;
  310 +}
  311 +
187 312  
188 313 extern spinlock_t dq_data_lock;
189 314